blob: b5b4c33533ee9c14bcb61bbd9cedaebb08cb97e4 [file] [log] [blame]
b.liu1c1c7212023-12-22 16:35:27 +08001#include <sys/stat.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <fcntl.h>
5#include <errno.h>
b.liu9e8584b2024-11-06 19:21:28 +08006#include <stdlib.h>
b.liu1c1c7212023-12-22 16:35:27 +08007
8#include "mbtk_log.h"
9#include "mbtk_audio_internal.h"
10
11#define WAV_PLAY_BUFF 2048
12
b.liub21bd8d2023-12-28 19:07:21 +080013typedef struct {
14 const unsigned char *pcm_data;
15 int data_size;
16} audio_buff_t;
17
b.liu1c1c7212023-12-22 16:35:27 +080018static int wav_play_fd = -1;
19static audio_play_state_enum play_state = AUDIO_PLAY_STATE_STOP;
20static pthread_cond_t play_cond;
21static pthread_mutex_t play_mutex;
22static pthread_t play_thread_play;
23
24static int wav_recorder_fd = -1;
25static struct wav_header recorder_header;
26static uint32 recorver_data_count = 0;
27
b.liub21bd8d2023-12-28 19:07:21 +080028static audio_buff_t audio_buff;
29
yu.dongbe938702024-11-01 04:11:35 -070030static int current_loopback_state = 0;
31static int current_loopback_device = -1;
yu.dongbe938702024-11-01 04:11:35 -070032
b.liu1c1c7212023-12-22 16:35:27 +080033static void audio_play_thread(void *arg)
34{
35 int rc, len, frames = 0;
36 char buf[WAV_PLAY_BUFF];
37
38 play_state = AUDIO_PLAY_STATE_RUNNING;
39 pthread_mutex_init(&play_mutex, NULL);
40 pthread_cond_init(&play_cond, NULL);
41
b.liub21bd8d2023-12-28 19:07:21 +080042 int data_send = 0;
b.liu1c1c7212023-12-22 16:35:27 +080043 while (TRUE) {
44 /* Playback loop */
45 pthread_mutex_lock(&play_mutex);
46 if(play_state == AUDIO_PLAY_STATE_STOP) {
47 LOGD("Stop play...");
48 pthread_mutex_unlock(&play_mutex);
49 break;
50 } else if(play_state == AUDIO_PLAY_STATE_PAUSE) {
51 pthread_cond_wait(&play_cond, &play_mutex);
52 pthread_mutex_unlock(&play_mutex);
53 continue;
54 } else {
55 pthread_mutex_unlock(&play_mutex);
56 }
57
58 memset(buf, 0x00, sizeof(buf));
b.liub21bd8d2023-12-28 19:07:21 +080059 if(wav_play_fd > 0) { // Play file.
60 len = read(wav_play_fd, buf, WAV_PLAY_BUFF);
61 if (len == -1) {
62 LOGE("%s: error reading from file", __FUNCTION__);
63 goto thread_end;
64 }
b.liu1c1c7212023-12-22 16:35:27 +080065
b.liub21bd8d2023-12-28 19:07:21 +080066 if (len == 0) {
67 /* reached EOF */
68 LOGE("%s: Read wav file end.", __FUNCTION__);
69 break;
70 }
71 } else { // Play buffer.
72 if(data_send >= audio_buff.data_size) {
73 /* reached EOF */
74 LOGE("%s: Read buffer end.", __FUNCTION__);
75 break;
76 }
77 if(audio_buff.data_size - data_send >= WAV_PLAY_BUFF) {
78 memcpy(buf, audio_buff.pcm_data + data_send, WAV_PLAY_BUFF);
79 len = WAV_PLAY_BUFF;
80 } else {
81 memcpy(buf, audio_buff.pcm_data + data_send, audio_buff.data_size - data_send);
82 len = audio_buff.data_size - data_send;
83 }
84 data_send += len;
b.liu1c1c7212023-12-22 16:35:27 +080085 }
86
87 if((rc = mbtk_audio_pcm_play_data_send(buf, len)) < len) {
88 LOGE("Send data %d/%d", rc, len);
89 goto thread_end;
90 }
91
92 LOGD("%s: No.%d frame playback", __FUNCTION__, ++frames);
93 }
94
95 play_state = AUDIO_PLAY_STATE_STOP;
96
97thread_end:
98 pthread_mutex_destroy(&play_mutex);
99 pthread_cond_destroy(&play_cond);
100 mbtk_audio_pcm_play_stop();
101
b.liub21bd8d2023-12-28 19:07:21 +0800102 if(wav_play_fd > 0) {
103 if (close(wav_play_fd))
104 LOGE("%s: error closing file", __FUNCTION__);
105 }
b.liu1c1c7212023-12-22 16:35:27 +0800106
107 wav_play_fd = -1;
108 LOGD("%s: finished pcm playback.", __FUNCTION__);
109 return;
110}
111
112static void audio_recorder_cb(void *data, uint32 data_len)
113{
114 if(data_len > 0) {
115 LOGD("Recorver data:%d, count:%d", data_len, recorver_data_count);
116 if (write(wav_recorder_fd, data, data_len) < data_len) {
117 LOGE("%s: error writing to file!", __FUNCTION__);
118 }
119 recorver_data_count += data_len;
120 } else {
121 LOGD("Recorver data end.");
122 recorder_header.data_sz = recorver_data_count;
123 recorder_header.riff_sz = recorder_header.data_sz + sizeof(recorder_header) - 8;
124 lseek(wav_recorder_fd, 0, SEEK_SET);
b.liu9e8584b2024-11-06 19:21:28 +0800125
126 if(sizeof(struct wav_header) == write(wav_recorder_fd, &recorder_header, sizeof(struct wav_header))) {
127 // Do nothting.
128 }
b.liu1c1c7212023-12-22 16:35:27 +0800129
130 close(wav_recorder_fd);
131 wav_recorder_fd = -1;
132 }
133}
134
135int mbtk_audio_wav_init()
136{
137 //mbtk_log_init("radio", "MBTK_AUDIO");
138 return mbtk_audio_pcm_init();
139}
140
141int mbtk_audio_wav_play_start(const void *wav_file)
142{
143 struct stat st;
144 const char *path = (const char *)wav_file;
145 struct riff_wave_header riff_wave_header;
146 struct chunk_header chunk_header;
147 struct chunk_fmt chunk_fmt = {0};
148 unsigned int more_chunks = 1;
149
150 if(play_state != AUDIO_PLAY_STATE_STOP) {
151 LOGW("Audio is playing...");
152 return -1;
153 }
154
155 /* Check and open source file */
156 if (access(path, F_OK) || stat(path, &st)) {
157 LOGE("%s: error reading from file %s", __FUNCTION__, path);
158 return -1;
159 }
160
161 if (!st.st_size) {
162 LOGE("%s: empty file %s", __FUNCTION__, path);
163 return -1;
164 }
165
166 wav_play_fd = open(path, O_RDONLY);
167 if (wav_play_fd < 0) {
168 LOGE("%s: error opening file %s", __FUNCTION__, path);
169 return -1;
170 }
171
b.liu9e8584b2024-11-06 19:21:28 +0800172 if(sizeof(riff_wave_header) != read(wav_play_fd, &riff_wave_header, sizeof(riff_wave_header))) {
173 LOGE("%s: read riff_wave_header fail.", __FUNCTION__);
174 return -1;
175 }
176
b.liu1c1c7212023-12-22 16:35:27 +0800177 if ((riff_wave_header.riff_id != ID_RIFF) || (riff_wave_header.wave_id != ID_WAVE)) {
178 LOGE("Error: '%s' is not a riff/wave file", path);
179 close(wav_play_fd);
180 return -1;
181 }
182
183 do {
b.liu9e8584b2024-11-06 19:21:28 +0800184 if(sizeof(chunk_header) != read(wav_play_fd, &chunk_header, sizeof(chunk_header))) {
185 LOGE("%s: read chunk_header fail.", __FUNCTION__);
186 return -1;
187 }
b.liu1c1c7212023-12-22 16:35:27 +0800188
189 switch (chunk_header.id) {
190 case ID_FMT:
b.liu9e8584b2024-11-06 19:21:28 +0800191 if(sizeof(chunk_fmt) != read(wav_play_fd, &chunk_fmt, sizeof(chunk_fmt))) {
192 LOGE("%s: read chunk_fmt fail.", __FUNCTION__);
193 return -1;
194 }
b.liu1c1c7212023-12-22 16:35:27 +0800195 /* If the format header is larger, skip the rest */
196 if (chunk_header.sz > sizeof(chunk_fmt))
197 lseek(wav_play_fd, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
198 break;
199 case ID_DATA:
200 /* Stop looking for chunks */
201 more_chunks = 0;
202 break;
203 default:
204 /* Unknown chunk, skip bytes */
205 lseek(wav_play_fd, chunk_header.sz, SEEK_CUR);
206 }
207 } while (more_chunks);
208
209 //Support 8k/16k & mono wave file
210 if (((chunk_fmt.sample_rate != 8000) && (chunk_fmt.sample_rate != 16000))
211 || (chunk_fmt.num_channels != 1) ) {
212 LOGD("%s: error wave file:sample_rate = %d, num_channels = %d!!",
213 __FUNCTION__,chunk_fmt.sample_rate, chunk_fmt.num_channels);
214 close(wav_play_fd);
215 return -1;
216 }
217
218 LOGE("%s: success open wave file:%s, sample_rate = %d, num_channels = %d.",
219 __FUNCTION__, path, chunk_fmt.sample_rate, chunk_fmt.num_channels);
220
221 if ((8000 == chunk_fmt.sample_rate) && (1 == chunk_fmt.num_channels)) {
222 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_8000);
223 } else if ((16000 == chunk_fmt.sample_rate) && (1 == chunk_fmt.num_channels)) {
224 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_16000);
225 }
226
227 if (mbtk_audio_pcm_play_start()) {
228 LOGE("%s: error opening output device.", __FUNCTION__);
229 return -1;
230 }
231
232 LOGD("Start play wav file...");
233
234 pthread_attr_t thread_attr;
235 pthread_attr_init(&thread_attr);
236 if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
237 {
238 LOGE("pthread_attr_setdetachstate() fail.");
239 return -1;
240 }
241
242 if (pthread_create(&play_thread_play, NULL, (void *)&audio_play_thread, NULL) < 0) {
243 LOGE("%s: error creating thread_play!", __FUNCTION__);
244 return -1;
245 }
246
247 return 0;
248}
249
b.liub21bd8d2023-12-28 19:07:21 +0800250int mbtk_audio_wav_stream_play_start(const unsigned char *pcm_data, int data_size, int sample_rate, int num_channels)
251{
252 if(play_state != AUDIO_PLAY_STATE_STOP) {
253 LOGW("Audio is playing...");
254 return -1;
255 }
256
257 //Support 8k/16k & mono wave file
258 if (((sample_rate != 8000) && (sample_rate != 16000))
259 || (num_channels != 1) ) {
260 LOGD("%s: error wave file:sample_rate = %d, num_channels = %d!!",
261 __FUNCTION__,sample_rate, num_channels);
262 return -1;
263 }
264
265 LOGE("%s: success open wave stream, sample_rate = %d, num_channels = %d.",
266 __FUNCTION__, sample_rate, num_channels);
267
268 if ((8000 == sample_rate) && (1 == num_channels)) {
269 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_8000);
270 } else if ((16000 == sample_rate) && (1 == num_channels)) {
271 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_16000);
272 }
273
274 if (mbtk_audio_pcm_play_start()) {
275 LOGE("%s: error opening output device.", __FUNCTION__);
276 return -1;
277 }
278
279 audio_buff.pcm_data = pcm_data;
280 audio_buff.data_size = data_size;
281 LOGD("Start play wav stream...");
282
283 pthread_attr_t thread_attr;
284 pthread_attr_init(&thread_attr);
285 if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
286 {
287 LOGE("pthread_attr_setdetachstate() fail.");
288 return -1;
289 }
290
291 if (pthread_create(&play_thread_play, NULL, (void *)&audio_play_thread, NULL) < 0) {
292 LOGE("%s: error creating thread_play!", __FUNCTION__);
293 return -1;
294 }
295
296 return 0;
297}
298
299
b.liu1c1c7212023-12-22 16:35:27 +0800300int mbtk_audio_wav_play_pause()
301{
302 int result = 0;
303 pthread_mutex_lock(&play_mutex);
304 if(play_state == AUDIO_PLAY_STATE_RUNNING) {
305 play_state = AUDIO_PLAY_STATE_PAUSE;
306 } else {
b.liub21bd8d2023-12-28 19:07:21 +0800307 // result = -1;
b.liu1c1c7212023-12-22 16:35:27 +0800308 LOGW("Audio state : %d", play_state);
309 }
310 pthread_mutex_unlock(&play_mutex);
311 return result;
312}
313
314int mbtk_audio_wav_play_resume()
315{
316 int result = 0;
317 pthread_mutex_lock(&play_mutex);
318 if(play_state == AUDIO_PLAY_STATE_PAUSE) {
319 play_state = AUDIO_PLAY_STATE_RUNNING;
320 pthread_cond_signal(&play_cond);
321 } else {
b.liub21bd8d2023-12-28 19:07:21 +0800322 // result = -1;
b.liu1c1c7212023-12-22 16:35:27 +0800323 LOGW("Audio state : %d", play_state);
324 }
325 pthread_mutex_unlock(&play_mutex);
326 return result;
327}
328
329
330int mbtk_audio_wav_play_stop()
331{
332 int result = 0;
333 pthread_mutex_lock(&play_mutex);
334 if(play_state == AUDIO_PLAY_STATE_PAUSE || play_state == AUDIO_PLAY_STATE_RUNNING) {
335 if(play_state == AUDIO_PLAY_STATE_PAUSE) {
336 pthread_cond_signal(&play_cond);
337 }
338 play_state = AUDIO_PLAY_STATE_STOP;
339 pthread_mutex_unlock(&play_mutex);
340
341 LOGD("Waitting play thread exit...");
342 if (pthread_join(play_thread_play, NULL)) {
343 LOGE("error join thread_play!");
344 // abort();
345 }
346 LOGD("Play thread exit success.");
347 } else {
348 pthread_mutex_unlock(&play_mutex);
b.liub21bd8d2023-12-28 19:07:21 +0800349 // result = -1;
b.liu1c1c7212023-12-22 16:35:27 +0800350 LOGW("Audio state : %d", play_state);
351 }
352
353 return result;
354}
355
356int mbtk_audio_wav_recorder_start(const void *wav_file, mbtk_audio_sample_rate_enum sample_rate)
357{
b.liu1c1c7212023-12-22 16:35:27 +0800358 const char *path = (const char *)wav_file;
359
360 LOGD("wav_file is %s.", path);
361 if(wav_recorder_fd > 0) {
362 LOGW("Audio is recorder...");
363 }
364
365 memset(&recorder_header, 0x0, sizeof(struct wav_header));
366 recorder_header.riff_id = ID_RIFF;
367 recorder_header.riff_sz = 0;
368 recorder_header.riff_fmt = ID_WAVE;
369 recorder_header.fmt_id = ID_FMT;
370 recorder_header.fmt_sz = 16;
371 recorder_header.audio_format = 1; //FORMAT_PCM;
372 recorder_header.num_channels = 1; //Modem ONLY support mono recording
373 recorder_header.sample_rate = (sample_rate == MBTK_AUDIO_SAMPLE_RATE_8000 ? 8000 : 16000);
374 recorder_header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
375 recorder_header.byte_rate = (recorder_header.bits_per_sample / 8) * recorder_header.num_channels * recorder_header.sample_rate;
376 recorder_header.block_align = recorder_header.num_channels * (recorder_header.bits_per_sample / 8);
377 recorder_header.data_id = ID_DATA;
378
379 mbtk_audio_pcm_sample_rate_set(sample_rate);
380
b.liub3b923a2024-06-06 15:15:49 +0800381 wav_recorder_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
b.liu1c1c7212023-12-22 16:35:27 +0800382 if (wav_recorder_fd < 0) {
383 LOGE("%s: error opening file %s!", __FUNCTION__, path);
384 return -1;
385 }
386
387 //leave enough room for header
388 lseek(wav_recorder_fd, sizeof(struct wav_header), SEEK_SET);
389
390 recorver_data_count = 0;
391
392 return mbtk_audio_pcm_recorder_start(audio_recorder_cb);
393}
394
395int mbtk_audio_wav_recorder_pause()
396{
397 return mbtk_audio_pcm_recorder_pause();
398}
399
400int mbtk_audio_wav_recorder_resume()
401{
402 return mbtk_audio_pcm_recorder_resume();
403}
404
405
406int mbtk_audio_wav_recorder_stop()
407{
408 return mbtk_audio_pcm_recorder_stop();
409}
410
411int mbtk_audio_wav_deinit()
412{
413 if(play_state != AUDIO_PLAY_STATE_STOP) {
414 if(mbtk_audio_wav_play_stop()) {
415 LOGE("mbtk_audio_wav_play_stop() fail.");
416 }
417 }
418
419 if(wav_recorder_fd > 0) {
420 mbtk_audio_wav_recorder_stop();
421 }
422
423 return mbtk_audio_pcm_deinit();
424}
425
yu.dongbe938702024-11-01 04:11:35 -0700426int mbtk_audio_set_loopback_enable_state(int device, int enable_state)
427{
428 char command[128];
429
430 if (device < 0 || device > 2 || (enable_state != 0 && enable_state != 1)) {
431 LOGE("Invalid device or enable_state");
432 return -1;
433 }
434
435 snprintf(command, sizeof(command), "ubus call audio_if audio_mode_set '{\"param0\":0}'");
436 if (system(command) != 0) {
437 LOGE("Failed to set audio mode");
438 return -1;
439 }
440
441 if (enable_state == 1) {
442 snprintf(command, sizeof(command), "ubus call audio_if loopback_enable '{\"param0\":%d}'", device);
443 if (system(command) != 0) {
444 LOGE("Failed to enable loopback");
445 return -1;
446 }
447 } else {
448 if (system("ubus call audio_if loopback_disable") != 0) {
449 LOGE("Failed to disable loopback");
450 return -1;
451 }
452 }
453
454 current_loopback_device = device;
455 current_loopback_state = enable_state;
456
457 return 0;
458}
459
460int mbtk_audio_get_loopback_enable_state(int *device, int *enable_state)
461{
462 if (device == NULL || enable_state == NULL) {
463 LOGE("Null pointer provided for device or enable_state");
464 return -1;
465 }
466
467 *device = current_loopback_device;
468 *enable_state = current_loopback_state;
469
470 return 0;
471}