blob: ac4bed8929a21c1a47dabae31c1a61ac29f8f6ff [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>
6
7#include "mbtk_log.h"
8#include "mbtk_audio_internal.h"
9
10#define WAV_PLAY_BUFF 2048
11
b.liub21bd8d2023-12-28 19:07:21 +080012typedef struct {
13 const unsigned char *pcm_data;
14 int data_size;
15} audio_buff_t;
16
b.liu1c1c7212023-12-22 16:35:27 +080017static int wav_play_fd = -1;
18static audio_play_state_enum play_state = AUDIO_PLAY_STATE_STOP;
19static pthread_cond_t play_cond;
20static pthread_mutex_t play_mutex;
21static pthread_t play_thread_play;
22
23static int wav_recorder_fd = -1;
24static struct wav_header recorder_header;
25static uint32 recorver_data_count = 0;
26
b.liub21bd8d2023-12-28 19:07:21 +080027static audio_buff_t audio_buff;
28
yu.dongbe938702024-11-01 04:11:35 -070029static int current_loopback_state = 0;
30static int current_loopback_device = -1;
31static mbtk_audio_service_error_cb_f service_error_cb = NULL;
32
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);
125 write(wav_recorder_fd, &recorder_header, sizeof(struct wav_header));
126
127 close(wav_recorder_fd);
128 wav_recorder_fd = -1;
129 }
130}
131
yu.dongbe938702024-11-01 04:11:35 -0700132int mbtk_register_error_callback(mbtk_audio_service_error_cb_f cb)
133{
134 if (cb == NULL) {
135 LOGE("Error: Callback function is NULL.");
136 return -1;
137 }
138 service_error_cb = cb;
139 LOGD("Callback function registered successfully.");
140 return 0;
141}
142
b.liu1c1c7212023-12-22 16:35:27 +0800143int mbtk_audio_wav_init()
144{
145 //mbtk_log_init("radio", "MBTK_AUDIO");
146 return mbtk_audio_pcm_init();
147}
148
149int mbtk_audio_wav_play_start(const void *wav_file)
150{
151 struct stat st;
152 const char *path = (const char *)wav_file;
153 struct riff_wave_header riff_wave_header;
154 struct chunk_header chunk_header;
155 struct chunk_fmt chunk_fmt = {0};
156 unsigned int more_chunks = 1;
157
158 if(play_state != AUDIO_PLAY_STATE_STOP) {
159 LOGW("Audio is playing...");
160 return -1;
161 }
162
163 /* Check and open source file */
164 if (access(path, F_OK) || stat(path, &st)) {
165 LOGE("%s: error reading from file %s", __FUNCTION__, path);
166 return -1;
167 }
168
169 if (!st.st_size) {
170 LOGE("%s: empty file %s", __FUNCTION__, path);
171 return -1;
172 }
173
174 wav_play_fd = open(path, O_RDONLY);
175 if (wav_play_fd < 0) {
176 LOGE("%s: error opening file %s", __FUNCTION__, path);
177 return -1;
178 }
179
180 read(wav_play_fd, &riff_wave_header, sizeof(riff_wave_header));
181 if ((riff_wave_header.riff_id != ID_RIFF) || (riff_wave_header.wave_id != ID_WAVE)) {
182 LOGE("Error: '%s' is not a riff/wave file", path);
183 close(wav_play_fd);
184 return -1;
185 }
186
187 do {
188 read(wav_play_fd, &chunk_header, sizeof(chunk_header));
189
190 switch (chunk_header.id) {
191 case ID_FMT:
192 read(wav_play_fd, &chunk_fmt, sizeof(chunk_fmt));
193 /* If the format header is larger, skip the rest */
194 if (chunk_header.sz > sizeof(chunk_fmt))
195 lseek(wav_play_fd, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
196 break;
197 case ID_DATA:
198 /* Stop looking for chunks */
199 more_chunks = 0;
200 break;
201 default:
202 /* Unknown chunk, skip bytes */
203 lseek(wav_play_fd, chunk_header.sz, SEEK_CUR);
204 }
205 } while (more_chunks);
206
207 //Support 8k/16k & mono wave file
208 if (((chunk_fmt.sample_rate != 8000) && (chunk_fmt.sample_rate != 16000))
209 || (chunk_fmt.num_channels != 1) ) {
210 LOGD("%s: error wave file:sample_rate = %d, num_channels = %d!!",
211 __FUNCTION__,chunk_fmt.sample_rate, chunk_fmt.num_channels);
212 close(wav_play_fd);
213 return -1;
214 }
215
216 LOGE("%s: success open wave file:%s, sample_rate = %d, num_channels = %d.",
217 __FUNCTION__, path, chunk_fmt.sample_rate, chunk_fmt.num_channels);
218
219 if ((8000 == chunk_fmt.sample_rate) && (1 == chunk_fmt.num_channels)) {
220 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_8000);
221 } else if ((16000 == chunk_fmt.sample_rate) && (1 == chunk_fmt.num_channels)) {
222 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_16000);
223 }
224
225 if (mbtk_audio_pcm_play_start()) {
226 LOGE("%s: error opening output device.", __FUNCTION__);
227 return -1;
228 }
229
230 LOGD("Start play wav file...");
231
232 pthread_attr_t thread_attr;
233 pthread_attr_init(&thread_attr);
234 if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
235 {
236 LOGE("pthread_attr_setdetachstate() fail.");
237 return -1;
238 }
239
240 if (pthread_create(&play_thread_play, NULL, (void *)&audio_play_thread, NULL) < 0) {
241 LOGE("%s: error creating thread_play!", __FUNCTION__);
242 return -1;
243 }
244
245 return 0;
246}
247
b.liub21bd8d2023-12-28 19:07:21 +0800248int mbtk_audio_wav_stream_play_start(const unsigned char *pcm_data, int data_size, int sample_rate, int num_channels)
249{
250 if(play_state != AUDIO_PLAY_STATE_STOP) {
251 LOGW("Audio is playing...");
252 return -1;
253 }
254
255 //Support 8k/16k & mono wave file
256 if (((sample_rate != 8000) && (sample_rate != 16000))
257 || (num_channels != 1) ) {
258 LOGD("%s: error wave file:sample_rate = %d, num_channels = %d!!",
259 __FUNCTION__,sample_rate, num_channels);
260 return -1;
261 }
262
263 LOGE("%s: success open wave stream, sample_rate = %d, num_channels = %d.",
264 __FUNCTION__, sample_rate, num_channels);
265
266 if ((8000 == sample_rate) && (1 == num_channels)) {
267 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_8000);
268 } else if ((16000 == sample_rate) && (1 == num_channels)) {
269 mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_16000);
270 }
271
272 if (mbtk_audio_pcm_play_start()) {
273 LOGE("%s: error opening output device.", __FUNCTION__);
274 return -1;
275 }
276
277 audio_buff.pcm_data = pcm_data;
278 audio_buff.data_size = data_size;
279 LOGD("Start play wav stream...");
280
281 pthread_attr_t thread_attr;
282 pthread_attr_init(&thread_attr);
283 if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
284 {
285 LOGE("pthread_attr_setdetachstate() fail.");
286 return -1;
287 }
288
289 if (pthread_create(&play_thread_play, NULL, (void *)&audio_play_thread, NULL) < 0) {
290 LOGE("%s: error creating thread_play!", __FUNCTION__);
291 return -1;
292 }
293
294 return 0;
295}
296
297
b.liu1c1c7212023-12-22 16:35:27 +0800298int mbtk_audio_wav_play_pause()
299{
300 int result = 0;
301 pthread_mutex_lock(&play_mutex);
302 if(play_state == AUDIO_PLAY_STATE_RUNNING) {
303 play_state = AUDIO_PLAY_STATE_PAUSE;
304 } else {
b.liub21bd8d2023-12-28 19:07:21 +0800305 // result = -1;
b.liu1c1c7212023-12-22 16:35:27 +0800306 LOGW("Audio state : %d", play_state);
307 }
308 pthread_mutex_unlock(&play_mutex);
309 return result;
310}
311
312int mbtk_audio_wav_play_resume()
313{
314 int result = 0;
315 pthread_mutex_lock(&play_mutex);
316 if(play_state == AUDIO_PLAY_STATE_PAUSE) {
317 play_state = AUDIO_PLAY_STATE_RUNNING;
318 pthread_cond_signal(&play_cond);
319 } else {
b.liub21bd8d2023-12-28 19:07:21 +0800320 // result = -1;
b.liu1c1c7212023-12-22 16:35:27 +0800321 LOGW("Audio state : %d", play_state);
322 }
323 pthread_mutex_unlock(&play_mutex);
324 return result;
325}
326
327
328int mbtk_audio_wav_play_stop()
329{
330 int result = 0;
331 pthread_mutex_lock(&play_mutex);
332 if(play_state == AUDIO_PLAY_STATE_PAUSE || play_state == AUDIO_PLAY_STATE_RUNNING) {
333 if(play_state == AUDIO_PLAY_STATE_PAUSE) {
334 pthread_cond_signal(&play_cond);
335 }
336 play_state = AUDIO_PLAY_STATE_STOP;
337 pthread_mutex_unlock(&play_mutex);
338
339 LOGD("Waitting play thread exit...");
340 if (pthread_join(play_thread_play, NULL)) {
341 LOGE("error join thread_play!");
342 // abort();
343 }
344 LOGD("Play thread exit success.");
345 } else {
346 pthread_mutex_unlock(&play_mutex);
b.liub21bd8d2023-12-28 19:07:21 +0800347 // result = -1;
b.liu1c1c7212023-12-22 16:35:27 +0800348 LOGW("Audio state : %d", play_state);
349 }
350
351 return result;
352}
353
354int mbtk_audio_wav_recorder_start(const void *wav_file, mbtk_audio_sample_rate_enum sample_rate)
355{
356 int rc;
357 const char *path = (const char *)wav_file;
358
359 LOGD("wav_file is %s.", path);
360 if(wav_recorder_fd > 0) {
361 LOGW("Audio is recorder...");
362 }
363
364 memset(&recorder_header, 0x0, sizeof(struct wav_header));
365 recorder_header.riff_id = ID_RIFF;
366 recorder_header.riff_sz = 0;
367 recorder_header.riff_fmt = ID_WAVE;
368 recorder_header.fmt_id = ID_FMT;
369 recorder_header.fmt_sz = 16;
370 recorder_header.audio_format = 1; //FORMAT_PCM;
371 recorder_header.num_channels = 1; //Modem ONLY support mono recording
372 recorder_header.sample_rate = (sample_rate == MBTK_AUDIO_SAMPLE_RATE_8000 ? 8000 : 16000);
373 recorder_header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
374 recorder_header.byte_rate = (recorder_header.bits_per_sample / 8) * recorder_header.num_channels * recorder_header.sample_rate;
375 recorder_header.block_align = recorder_header.num_channels * (recorder_header.bits_per_sample / 8);
376 recorder_header.data_id = ID_DATA;
377
378 mbtk_audio_pcm_sample_rate_set(sample_rate);
379
b.liub3b923a2024-06-06 15:15:49 +0800380 wav_recorder_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
b.liu1c1c7212023-12-22 16:35:27 +0800381 if (wav_recorder_fd < 0) {
382 LOGE("%s: error opening file %s!", __FUNCTION__, path);
383 return -1;
384 }
385
386 //leave enough room for header
387 lseek(wav_recorder_fd, sizeof(struct wav_header), SEEK_SET);
388
389 recorver_data_count = 0;
390
391 return mbtk_audio_pcm_recorder_start(audio_recorder_cb);
392}
393
394int mbtk_audio_wav_recorder_pause()
395{
396 return mbtk_audio_pcm_recorder_pause();
397}
398
399int mbtk_audio_wav_recorder_resume()
400{
401 return mbtk_audio_pcm_recorder_resume();
402}
403
404
405int mbtk_audio_wav_recorder_stop()
406{
407 return mbtk_audio_pcm_recorder_stop();
408}
409
410int mbtk_audio_wav_deinit()
411{
412 if(play_state != AUDIO_PLAY_STATE_STOP) {
413 if(mbtk_audio_wav_play_stop()) {
414 LOGE("mbtk_audio_wav_play_stop() fail.");
415 }
416 }
417
418 if(wav_recorder_fd > 0) {
419 mbtk_audio_wav_recorder_stop();
420 }
421
422 return mbtk_audio_pcm_deinit();
423}
424
yu.dongbe938702024-11-01 04:11:35 -0700425int mbtk_audio_set_loopback_enable_state(int device, int enable_state)
426{
427 char command[128];
428
429 if (device < 0 || device > 2 || (enable_state != 0 && enable_state != 1)) {
430 LOGE("Invalid device or enable_state");
431 return -1;
432 }
433
434 snprintf(command, sizeof(command), "ubus call audio_if audio_mode_set '{\"param0\":0}'");
435 if (system(command) != 0) {
436 LOGE("Failed to set audio mode");
437 return -1;
438 }
439
440 if (enable_state == 1) {
441 snprintf(command, sizeof(command), "ubus call audio_if loopback_enable '{\"param0\":%d}'", device);
442 if (system(command) != 0) {
443 LOGE("Failed to enable loopback");
444 return -1;
445 }
446 } else {
447 if (system("ubus call audio_if loopback_disable") != 0) {
448 LOGE("Failed to disable loopback");
449 return -1;
450 }
451 }
452
453 current_loopback_device = device;
454 current_loopback_state = enable_state;
455
456 return 0;
457}
458
459int mbtk_audio_get_loopback_enable_state(int *device, int *enable_state)
460{
461 if (device == NULL || enable_state == NULL) {
462 LOGE("Null pointer provided for device or enable_state");
463 return -1;
464 }
465
466 *device = current_loopback_device;
467 *enable_state = current_loopback_state;
468
469 return 0;
470}