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