1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 #ifdef HAAS_AUDIO_DEMO
5 #include <posix/pthread.h>
6 #else
7 #include <pthread.h>
8 #endif
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <stdbool.h>
14 #include <aos/kernel.h>
15 #include <aos/list.h>
16 #include <errno.h>
17 #include "ulog/ulog.h"
18 #include "audio_rtos.h"
19 
20 #define LOG_TAG                       "[cap_task]"
21 #define CAP_HIGH_STACKSIZE            8192
22 #define CAP_DEFAULT_PRIORITY          33
23 #define CAP_TIMER_DEFAULT_INTERVAL_MS 20    // default capture thread interval 20ms
24 #define CAP_DATA_BUFFER_ENTRY_NUM_MAX 50    // default capture data buffer size 1s
25 
26 typedef struct {
27     struct dlist_s list;
28     char *data;
29     unsigned int size;
30     unsigned int wOffset;
31     void *dev;
32 } cap_data_buf_t;
33 
34 static native_pcm_device_t *pcm_dev = NULL;
35 static pthread_cond_t  cap_cond;
36 static pthread_mutex_t  cap_mutex;
37 static pthread_t cap_thread;
38 static bool bCreateCapThreadFlag = false;
39 static bool bCapStartFlag = false;
40 static unsigned int cap_interval_ms = CAP_TIMER_DEFAULT_INTERVAL_MS;
41 static aos_hdl_t flagMutex;
42 AOS_DLIST_HEAD(cap_data_list);
43 
capture_task_drop()44 static void capture_task_drop()
45 {
46     dlist_t *temp = NULL;
47     cap_data_buf_t *data_buf = NULL;
48     dlist_for_each_entry_safe(&cap_data_list, temp, data_buf, cap_data_buf_t, list) {
49         if(data_buf) {
50             dlist_del(&data_buf->list);
51             free(data_buf->data);
52             free(data_buf);
53         }
54     }
55 }
56 
cap_thread_loop(void * arg)57 static void cap_thread_loop(void *arg)
58 {
59     cap_data_buf_t *databuf = NULL;
60     unsigned int frame_size, period_bytes;
61     bool copyStartFlag = false;
62     while(1) {
63         aos_mutex_lock(&flagMutex, AOS_WAIT_FOREVER);
64         copyStartFlag = bCapStartFlag;
65         aos_mutex_unlock(&flagMutex);
66         if(true == copyStartFlag) {
67             if(dlist_entry_number(&cap_data_list) >= CAP_DATA_BUFFER_ENTRY_NUM_MAX) {
68                 LOGE(LOG_TAG, "%s:%d, capure data list full, report buf overflow event to APP!!", __func__, __LINE__);
69             } else if(pcm_dev && pcm_dev->ops && pcm_dev->ops->read) {
70                 frame_size = pcm_dev->params.channels * pcm_dev->params.sample_bits / 8;
71                 period_bytes = frame_size * cap_interval_ms * pcm_dev->params.rate / 1000;
72                 databuf = malloc(sizeof(cap_data_buf_t));
73                 if(databuf) {
74                     databuf->data = malloc(period_bytes);
75                     if(databuf->data) {
76                         memset(databuf->data, 0, period_bytes);
77                         databuf->size = pcm_dev->ops->read(pcm_dev->hdl, databuf->data, period_bytes);
78                         databuf->wOffset = 0;
79                         databuf->dev = pcm_dev;
80                         dlist_init(&databuf->list);
81                         dlist_add_tail(&databuf->list, &cap_data_list);
82                     }
83                 }
84             } else {
85                 LOGE(LOG_TAG, "%s:%d, invalid pcm_dev params", __func__, __LINE__);
86             }
87             usleep(cap_interval_ms * 1000);
88         } else {
89             LOGE(LOG_TAG, "%s:%d, wait for cap_cond", __func__, __LINE__);
90             capture_task_drop();
91             pthread_cond_wait(&cap_cond, &cap_mutex);
92         }
93     }
94 
95     return 0;
96 }
97 
create_cap_task(void)98 static int create_cap_task(void)
99 {
100     if(bCreateCapThreadFlag == true) {
101         LOGD(LOG_TAG, "%s:%d, capthread is running, skip ...", __func__, __LINE__);
102         return -1;
103     }
104     LOGD(LOG_TAG, "%s:%d, -->>", __func__, __LINE__);
105     pthread_attr_t attr;
106     struct sched_param sched;
107 
108     aos_mutex_new(&flagMutex);
109     pthread_cond_init(&cap_cond, NULL);
110     pthread_mutex_init(&cap_mutex, NULL);
111     pthread_attr_init(&attr);
112     pthread_attr_setstacksize(&attr, CAP_HIGH_STACKSIZE);
113     sched.sched_priority = CAP_DEFAULT_PRIORITY;
114     pthread_attr_setschedparam(&attr, &sched);
115     pthread_create(&cap_thread, &attr, cap_thread_loop, NULL);
116     pthread_setname_np(cap_thread, "capthread");
117     pthread_attr_destroy(&attr);
118     bCreateCapThreadFlag = true;
119     return 0;
120 }
121 
capture_task_start(void * dev)122 void capture_task_start(void *dev)
123 {
124     LOGD(LOG_TAG, "%s:%d", __func__, __LINE__);
125     if(!dev) {
126         LOGE(LOG_TAG, "%s:%d, dev is null", __func__, __LINE__);
127     }
128     pcm_dev = dev;
129     aos_mutex_lock(&flagMutex, AOS_WAIT_FOREVER);
130     bCapStartFlag = true;
131     aos_mutex_unlock(&flagMutex);
132     create_cap_task();
133     pthread_cond_signal(&cap_cond);
134 }
135 
capture_task_stop()136 void capture_task_stop()
137 {
138     LOGD(LOG_TAG, "%s:%d", __func__, __LINE__);
139     aos_mutex_lock(&flagMutex, AOS_WAIT_FOREVER);
140     bCapStartFlag = false;
141     aos_mutex_unlock(&flagMutex);
142 }
143 
capture_read_data(void * dev,char * buf,unsigned int len,int blockMode)144 int capture_read_data(void *dev, char *buf, unsigned int len, int blockMode)
145 {
146     dlist_t *temp = NULL;
147     cap_data_buf_t *data_buf = NULL;
148     unsigned int left_bytes = len;
149     unsigned int read_bytes = 0;
150 
151 __read_routin__:
152     dlist_for_each_entry_safe(&cap_data_list, temp, data_buf, cap_data_buf_t, list) {
153         if(data_buf && (data_buf->dev == dev)) {
154             if((data_buf->size - data_buf->wOffset) >= left_bytes) {
155                 memcpy(buf + read_bytes, data_buf->data + data_buf->wOffset, left_bytes);
156                 read_bytes += left_bytes;
157                 data_buf->wOffset += left_bytes;
158                 left_bytes = 0;
159                 return read_bytes;
160             } else {
161                 memcpy(buf + read_bytes, data_buf->data + data_buf->wOffset, data_buf->size - data_buf->wOffset);
162                 read_bytes += data_buf->size - data_buf->wOffset;
163                 data_buf->wOffset = data_buf->size;
164                 left_bytes -= data_buf->size - data_buf->wOffset;
165             }
166             if(data_buf->wOffset >= data_buf->size) {
167                 /* free data_buf */
168                 dlist_del(&data_buf->list);
169                 free(data_buf->data);
170                 free(data_buf);
171             }
172         }
173     }
174     if(1 == blockMode && read_bytes < len) {
175         usleep(cap_interval_ms * 1000);
176         goto __read_routin__;
177     }
178     return read_bytes;
179 }
180