1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <hal_timer.h>
41 #include <aw-alsa-lib/pcm.h>
42 #include <aw-alsa-lib/control.h>
43 
44 #include "common.h"
45 #include "wav_parser.h"
46 
47 #undef DUPLEX_FS_WAV
48 
49 static char *g_pcm_name = "default";
50 
51 struct duplex_priv {
52     rt_mutex_t xMutex;
53     audio_mgr_t *playback_mgr;
54     audio_mgr_t *capture_mgr;
55     char *input_name;
56     char *output_name;
57 };
58 
pcm_read(snd_pcm_t * handle,char * data,snd_pcm_uframes_t frames_total,unsigned int frame_bytes)59 static int pcm_read(snd_pcm_t *handle, char *data,
60         snd_pcm_uframes_t frames_total, unsigned int frame_bytes)
61 {
62     int ret = 0;
63     snd_pcm_sframes_t size;
64     snd_pcm_uframes_t frames_loop = 400;
65     snd_pcm_uframes_t frames_count = 0;
66     snd_pcm_uframes_t frames = 0;
67     unsigned int offset = 0;
68 
69     while (1) {
70         if ((frames_total - frames_count) < frames_loop)
71             frames = frames_total - frames_count;
72         if (frames == 0)
73             frames = frames_loop;
74         /*hal_usleep(500000);*/
75         /*printf("snd_pcm_readi %ld frames\n", frames);*/
76         size = snd_pcm_readi(handle, (void *)(data + offset), frames);
77         if (size < 0)
78             printf("snd_pcm_readi return %ld\n", size);
79         if (size == -EAGAIN) {
80             /* retry */
81             hal_usleep(10000);
82             continue;
83         } else if (size == -EPIPE) {
84             xrun(handle);
85             continue;
86         } else if (size == -ESTRPIPE) {
87 
88             continue;
89         } else if (size < 0) {
90             printf("-----snd_pcm_readi failed!!, return %ld\n", size);
91             ret = (int)size;
92             goto err;
93         }
94         offset += (size * frame_bytes);
95         frames_count += size;
96         frames -= size;
97         if (frames_total == frames_count)
98             break;
99         /*printf("frames_count = %ld, frames_total = %ld\n", frames_count, frames_total);*/
100     }
101 err:
102     return frames_count > 0 ? frames_count : ret;
103 }
104 
pcm_write(snd_pcm_t * handle,const char * data,snd_pcm_uframes_t frames_total,unsigned int frame_bytes)105 static int pcm_write(snd_pcm_t *handle, const char *data,
106         snd_pcm_uframes_t frames_total, unsigned int frame_bytes)
107 {
108     int ret = 0;
109     snd_pcm_sframes_t size;
110     snd_pcm_uframes_t frames_loop = 400;
111     snd_pcm_uframes_t frames_count = 0;
112     snd_pcm_uframes_t frames = 0;
113 
114     while (1) {
115         if ((frames_total - frames_count) < frames_loop)
116             frames = frames_total - frames_count;
117         if (frames == 0)
118             frames = frames_loop;
119         /*hal_usleep(500000);*/
120         size = snd_pcm_writei(handle, data, frames);
121         if (size != frames) {
122             printf("snd_pcm_writei return %ld\n", size);
123         }
124         if (size == -EAGAIN) {
125             hal_usleep(10000);
126             continue;
127         } else if (size == -EPIPE) {
128             xrun(handle);
129             continue;
130         } else if (size == -ESTRPIPE) {
131 
132             continue;
133         } else if (size < 0) {
134             printf("-----snd_pcm_writei failed!!, return %ld\n", size);
135             return size;
136         }
137         data += (size * frame_bytes);
138         frames_count += size;
139         frames -= size;
140         if (frames_total == frames_count)
141             break;
142         /*printf("frames_count = %ld, frames_total = %ld\n", frames_count, frames_total);*/
143     }
144 
145     return frames_count;
146 }
147 
playback_fs_wav(audio_mgr_t * mgr,const char * pcm_name,const char * path)148 static int playback_fs_wav(audio_mgr_t *mgr, const char *pcm_name, const char *path)
149 {
150     int ret = 0;
151     int fd = 0;
152     wav_header_t wav_header;
153     wav_hw_params_t wav_hwparams = {16000, SND_PCM_FORMAT_UNKNOWN, 2};
154     unsigned int c;
155     unsigned int written = 0;
156     unsigned int count;
157     unsigned int chunk_bytes;
158     unsigned int frame_bytes = 0;
159     ssize_t r = 0;
160     char *audiobuf = NULL;
161 
162     if (path == NULL) {
163         printf("[%s] path is null.\n", __func__);
164         return -1;
165     }
166 
167     fd = open(path, O_RDONLY);
168     if (fd < 0) {
169         printf("no such wav file\n");
170         ret = -1;
171         goto err_fd_open;
172     }
173     r = read(fd, &wav_header, sizeof(wav_header_t));
174     if (r != sizeof(wav_header_t)) {
175         printf("read wav file header failed, return %ld\n", (long int)r);
176         goto err_fread_wav_header;
177     }
178 
179     if (check_wav_header(&wav_header, &wav_hwparams) != 0) {
180         printf("check wav header failed\n");
181         goto err_checkout_wav_header;
182     }
183     count = wav_header.dataSize;
184     if (count == 0) {
185         printf("wav data siez is %d.\n", count);
186         goto err_checkout_wav_datasize;
187     }
188 
189     /* open card */
190     ret = snd_pcm_open(&mgr->handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0);
191     if (ret < 0) {
192         printf("audio open error:%d\n", ret);
193         goto err_pcm_open;
194     }
195     mgr->format = wav_hwparams.format;
196     mgr->rate = wav_hwparams.rate;
197     mgr->channels = wav_hwparams.channels;
198 
199     ret = set_param(mgr->handle, mgr->format, mgr->rate, mgr->channels,
200             mgr->period_size, mgr->buffer_size);
201     if (ret < 0) {
202         printf("audio set param error:%d\n", ret);
203         goto err_set_param;
204     }
205 
206     frame_bytes = snd_pcm_frames_to_bytes(mgr->handle, 1);
207     chunk_bytes = snd_pcm_frames_to_bytes(mgr->handle, mgr->period_size);
208 
209     audiobuf = malloc(chunk_bytes);
210     if (!audiobuf) {
211         printf("no memory...\n");
212         goto err_malloc;
213     }
214     while (written < count) {
215         c = count - written;
216         if (c > chunk_bytes)
217             c = chunk_bytes;
218         r = read(fd, audiobuf, c);
219         if (r < 0 || r != c) {
220             printf("read file error, r=%ld,c=%u\n", (long int)r, c);
221             break;
222         }
223         r = pcm_write(mgr->handle, audiobuf, r/frame_bytes, frame_bytes);
224         if (r != c/frame_bytes)
225             break;
226         written += c;
227     }
228     snd_pcm_drain(mgr->handle);
229 
230     free(audiobuf);
231 
232 err_malloc:
233 err_set_param:
234     /* close card */
235     if (mgr->handle != NULL)
236         snd_pcm_close(mgr->handle);
237 err_pcm_open:
238 err_checkout_wav_datasize:
239 err_checkout_wav_header:
240 err_fread_wav_header:
241     close(fd);
242 err_fd_open:
243     return ret;
244 }
245 
capture_fs_wav(audio_mgr_t * mgr,const char * pcm_name,const char * path)246 static int capture_fs_wav(audio_mgr_t *mgr, const char *pcm_name, const char *path)
247 {
248     unsigned int len = 0;
249     int ret = 0;
250     int fd = 0;
251     wav_header_t header;
252     unsigned int written = 0;
253     long rest = -1, c = 0;
254     char *audiobuf = NULL;
255     unsigned int chunk_bytes;
256     unsigned int frame_bytes = 0;
257     struct stat statbuf;
258 
259     if (path == NULL)
260         return -1;
261 
262     /* open card */
263     ret = snd_pcm_open(&mgr->handle, pcm_name, SND_PCM_STREAM_CAPTURE, 0);
264     if (ret < 0) {
265         printf("audio open error:%d\n", ret);
266         return -1;
267     }
268 
269     ret = set_param(mgr->handle, mgr->format, mgr->rate, mgr->channels,
270             mgr->period_size, mgr->buffer_size);
271     if (ret < 0)
272         goto err;
273 
274     frame_bytes = snd_pcm_frames_to_bytes(mgr->handle, 1);
275     chunk_bytes = snd_pcm_frames_to_bytes(mgr->handle, mgr->period_size);
276     if (mgr->capture_duration > 0)
277         rest = mgr->capture_duration * snd_pcm_frames_to_bytes(mgr->handle, mgr->rate);
278 
279     create_wav(&header, mgr->format, mgr->rate, mgr->channels);
280     if (!stat(path, &statbuf)) {
281         if (S_ISREG(statbuf.st_mode))
282             remove(path);
283     }
284     fd = open(path, O_RDWR | O_CREAT, 0644);
285     if (fd < 0) {
286         printf("create wav file failed\n");
287         goto err;
288     }
289     write(fd, &header, sizeof(header));
290 
291     audiobuf = malloc(chunk_bytes);
292     if (!audiobuf) {
293         printf("no memory...\n");
294         goto err;
295     }
296     char *temp_wav_file = NULL;
297     unsigned int temp_wav_file_off = 0;
298     if (rest < 0) {
299         printf("please set capture duration..\n");
300         goto err;
301     }
302     temp_wav_file = malloc(rest);
303     if (!temp_wav_file) {
304         printf("no memory for temp_wav_file\n");
305         goto err;
306     }
307     while (rest > 0 && !mgr->in_aborting) {
308         int f = mgr->period_size;
309         if (rest <= chunk_bytes)
310             c = rest;
311         else
312             c = chunk_bytes;
313         f = pcm_read(mgr->handle, audiobuf, f, frame_bytes);
314         if (f < 0) {
315             printf("pcm read error, return %d\n", f);
316             break;
317         }
318         memcpy(temp_wav_file + temp_wav_file_off, audiobuf, c);
319         temp_wav_file_off += c;
320         if (rest > 0)
321             rest -= c;
322         written += c;
323     }
324 
325     ret = snd_pcm_drain(mgr->handle);
326     if (ret < 0)
327         printf("stop failed!, return %d\n", ret);
328 
329 err:
330     /* close card */
331     ret = snd_pcm_close(mgr->handle);
332     if (ret < 0) {
333         printf("audio close error:%d\n", ret);
334         return ret;
335     }
336 
337     printf("please wait...writing data(%u bytes) into %s\n", temp_wav_file_off, path);
338     ret = write(fd, temp_wav_file, temp_wav_file_off);
339     if (ret != temp_wav_file_off) {
340         printf("write temp_wav_file failed. ret:%d, wav_file_off:%d\n",
341             ret, temp_wav_file_off);
342         goto err1;
343     }
344     printf("write finish...\n");
345     resize_wav(&header, written);
346     lseek(fd, 0, SEEK_SET);
347     write(fd, &header, sizeof(header));
348 
349 err1:
350     if (temp_wav_file)
351         free(temp_wav_file);
352 
353     if (fd > 0)
354         close(fd);
355     if (audiobuf)
356         free(audiobuf);
357     return ret;
358 }
359 
360 /*
361  * arg0: arecord
362  * arg1: card
363  * arg2: format
364  * arg3: rate
365  * arg4: channels
366  * arg5: data
367  * arg6: len
368  */
arecord(const char * card_name,snd_pcm_format_t format,unsigned int rate,unsigned int channels,void * data,unsigned int datalen)369 static int arecord(const char *card_name, snd_pcm_format_t format, unsigned int rate,
370             unsigned int channels, void *data, unsigned int datalen)
371 {
372     int ret = 0;
373     snd_pcm_t *handle;
374     int mode = 0;
375     snd_pcm_hw_params_t *params;
376     snd_pcm_sw_params_t *sw_params;
377     snd_pcm_uframes_t period_frames = 1024, buffer_frames = 4096;
378 
379     printf("arecord dump args:\n");
380     printf("card:      %s\n", card_name);
381     printf("format:    %u\n", format);
382     printf("rate:      %u\n", rate);
383     printf("channels:  %u\n", channels);
384     printf("data:      %p\n", data);
385     printf("datalen:   %u\n", datalen);
386 
387     /* open card */
388     ret = snd_pcm_open(&handle, card_name, SND_PCM_STREAM_CAPTURE, mode);
389     if (ret < 0) {
390         printf("audio open error:%d\n", ret);
391         return -1;
392     }
393 
394     ret = set_param(handle, format, rate, channels, period_frames, buffer_frames);
395     if (ret < 0) {
396         printf("set param failed!, return %d\n", ret);
397         goto err_set_param;
398     }
399     printf("pcm_read start...\n");
400     ret = pcm_read(handle, data, snd_pcm_bytes_to_frames(handle, datalen),
401             snd_pcm_frames_to_bytes(handle, 1));
402     if (ret < 0) {
403         printf("capture error:%d\n", ret);
404         goto err_pcm_read;
405     }
406 
407 err_pcm_read:
408     ret = snd_pcm_drain(handle);
409     if (ret < 0)
410         printf("stop failed!, return %d\n", ret);
411 
412 err_set_param:
413     /* close card */
414     ret = snd_pcm_close(handle);
415     if (ret < 0)
416         printf("audio close error:%d\n", ret);
417 
418     return ret;
419 }
420 
421 /*
422  * arg0: aplay
423  * arg1: card
424  * arg2: format
425  * arg3: rate
426  * arg4: channels
427  * arg5: data
428  * arg6: len
429  */
aplay(const char * card_name,snd_pcm_format_t format,unsigned int rate,unsigned int channels,const char * data,unsigned int datalen)430 static int aplay(const char *card_name, snd_pcm_format_t format, unsigned int rate,
431             unsigned int channels, const char *data, unsigned int datalen)
432 {
433     int ret = 0;
434     snd_pcm_t *handle;
435     int mode = 0;
436     snd_pcm_uframes_t period_frames = 1024, buffer_frames = 4096;
437 
438     printf("aplay dump args:\n");
439     printf("card:        %s\n", card_name);
440     printf("format:      %u\n", format);
441     printf("rate:        %u\n", rate);
442     printf("channels:    %u\n", channels);
443     printf("data:        %p\n", data);
444     printf("datalen:     %u\n", datalen);
445     printf("period_size: %lu\n", period_frames);
446     printf("buffer_size: %lu\n", buffer_frames);
447 
448     /* open card */
449     ret = snd_pcm_open(&handle, card_name, SND_PCM_STREAM_PLAYBACK, mode);
450     if (ret < 0) {
451         printf("audio open error:%d\n", ret);
452         return -1;
453     }
454 
455     ret = set_param(handle, format, rate, channels, period_frames, buffer_frames);
456     if (ret < 0) {
457         goto err_set_param;
458     }
459 
460     ret = pcm_write(handle, (char *)data,
461             snd_pcm_bytes_to_frames(handle, datalen),
462             snd_pcm_frames_to_bytes(handle, 1));
463     if (ret < 0) {
464         printf("pcm_write error:%d\n", ret);
465         goto err_pcm_write;
466     }
467 
468 err_pcm_write:
469     ret = snd_pcm_drain(handle);
470     /*ret = snd_pcm_drop(handle);*/
471     if (ret < 0)
472         printf("stop failed!, return %d\n", ret);
473 
474 err_set_param:
475     /* close card */
476     ret = snd_pcm_close(handle);
477     if (ret < 0)
478         printf("audio close error:%d\n", ret);
479 
480     return ret;
481 }
482 
capture_then_play(audio_mgr_t * audio_mgr)483 static int capture_then_play(audio_mgr_t *audio_mgr)
484 {
485     char *capture_data = NULL;
486     unsigned int len = 0;
487 
488     if (audio_mgr->capture_duration == 0)
489         audio_mgr->capture_duration = 3;
490 
491     len = snd_pcm_format_size(audio_mgr->format,
492                audio_mgr->capture_duration * audio_mgr->rate *
493                audio_mgr->channels);
494     capture_data = malloc(len);
495     if (!capture_data) {
496         printf("no memory\n");
497         return -1;
498     }
499     memset(capture_data, 0, len);
500 
501     printf("arecord start...\n");
502     arecord(g_pcm_name, audio_mgr->format, audio_mgr->rate,
503                 audio_mgr->channels, capture_data, len);
504     printf("aplay start...\n");
505     /*snd_ctl_set("audiocodec", "LINEOUT volume", 0x1f);*/
506     aplay("hw:audiocodec", audio_mgr->format, audio_mgr->rate,
507                 audio_mgr->channels, capture_data, len);
508 
509     free(capture_data);
510     capture_data = NULL;
511     return 0;
512 }
513 
arecord_entry(void * arg)514 static void arecord_entry(void * arg)
515 {
516     int ret = 0;
517     struct duplex_priv * duplex_priv = arg;
518     const uint32_t timeout = 1 * 1000;
519 
520     ret = rt_mutex_take(duplex_priv->xMutex, timeout);
521     if (!ret) {
522         printf("[%s] semaphore take failed.\n", __func__);
523 //      vTaskDelete(NULL);
524         return;
525     }
526 #ifdef DUPLEX_FS_WAV
527     ret = capture_fs_wav(duplex_priv->capture_mgr, g_pcm_name,
528                 duplex_priv->input_name);
529     if (ret < 0)
530         printf("capture_fs_wav error:%d\n", ret);
531 #else
532     capture_then_play(duplex_priv->capture_mgr);
533 #endif
534     rt_mutex_release(duplex_priv->xMutex);
535 
536 //  vTaskDelete(NULL);
537 }
538 
usage(void)539 static void usage(void)
540 {
541     printf("Usage: aduplex [option]\n");
542     printf("-D,      pcm device name\n");
543     printf("-r,      sample rate\n");
544     printf("-f,      sample bits\n");
545     printf("-c,      channels\n");
546     printf("-p,      period size\n");
547     printf("-b,      buffer size\n");
548     printf("-i,      input file path\n");
549     printf("-o,      output file path\n");
550     printf("-d,      capture duration(second)\n");
551     printf("-h,      for help\n");
552     printf("\n");
553 }
554 
cmd_aduplex(int argc,char ** argv)555 int cmd_aduplex(int argc, char ** argv)
556 {
557     int i = 0;
558     int c;
559     int ret = 0;
560     unsigned int bits = 16;
561     const uint32_t timeout = 11 * 1000;
562 //  int priority = configAPPLICATION_NORMAL_PRIORITY;
563     uint32_t thread_size = 4 * 1024;
564     struct duplex_priv duplex_priv;
565 //  TaskHandle_t pxCreatedTask;
566     unsigned int buf_size;
567 
568     g_pcm_name = "hw:snddaudio0";
569 
570     duplex_priv.playback_mgr = audio_mgr_create();
571     if (!duplex_priv.playback_mgr) {
572         printf("playback_mgr malloc failed.\n");
573         return -1;
574     }
575 
576     duplex_priv.capture_mgr = audio_mgr_create();
577     if (!duplex_priv.capture_mgr) {
578         printf("capture_mgr malloc failed.\n");
579         goto err_malloc_capture_mgr;
580     }
581 
582     /* for init */
583     duplex_priv.capture_mgr->capture_duration = 5;
584 #ifdef DUPLEX_FS_WAV
585     duplex_priv.input_name = "/data/connect_success_rec.wav";
586 #endif
587     duplex_priv.output_name = "/data/connect_success.wav";
588 
589     optind = 0;
590     while ((c = getopt(argc, argv, "i:o:D:r:f:c:p:b:d:h")) != -1) {
591         switch (c) {
592         case 'i':
593             duplex_priv.input_name = optarg;
594             break;
595         case 'o':
596             duplex_priv.output_name = optarg;
597             break;
598         case 'D':
599             g_pcm_name = optarg;
600             break;
601         case 'r':
602             duplex_priv.playback_mgr->rate = atoi(optarg);
603             duplex_priv.capture_mgr->rate = atoi(optarg);
604             break;
605         case 'f':
606             bits = atoi(optarg);
607             break;
608         case 'c':
609             duplex_priv.playback_mgr->channels = atoi(optarg);
610             duplex_priv.capture_mgr->channels = atoi(optarg);
611             break;
612         case 'p':
613             duplex_priv.playback_mgr->period_size = atoi(optarg);
614             duplex_priv.capture_mgr->period_size = atoi(optarg);
615             break;
616         case 'b':
617             duplex_priv.playback_mgr->buffer_size = atoi(optarg);
618             duplex_priv.capture_mgr->buffer_size = atoi(optarg);
619             break;
620         case 'd':
621             duplex_priv.capture_mgr->capture_duration = atoi(optarg);
622             break;
623         case 'h':
624         default:
625             usage();
626             goto err_cmd;
627         }
628     }
629 
630     /* check params */
631     if (duplex_priv.capture_mgr->capture_duration > 10)
632         duplex_priv.capture_mgr->capture_duration = 10;
633     if (duplex_priv.capture_mgr->capture_duration <= 0)
634         duplex_priv.capture_mgr->capture_duration = 5;
635 
636     if (duplex_priv.output_name == NULL) {
637         printf("output name is null.\n");
638         goto err_out_filename_null;
639     }
640 
641 #ifdef DUPLEX_FS_WAV
642     if (duplex_priv.input_name == NULL) {
643         printf("input file name is null.\n");
644         goto err_in_filename_null;
645     }
646 #endif
647 
648     switch (bits) {
649     case 16:
650         duplex_priv.playback_mgr->format = SND_PCM_FORMAT_S16_LE;
651         duplex_priv.capture_mgr->format = SND_PCM_FORMAT_S16_LE;
652         break;
653     case 24:
654         duplex_priv.playback_mgr->format = SND_PCM_FORMAT_S24_LE;
655         duplex_priv.capture_mgr->format = SND_PCM_FORMAT_S24_LE;
656         break;
657     case 32:
658         duplex_priv.playback_mgr->format = SND_PCM_FORMAT_S32_LE;
659         duplex_priv.capture_mgr->format = SND_PCM_FORMAT_S32_LE;
660         break;
661     default:
662         printf("%u bits not supprot\n", bits);
663         goto err_format;
664     }
665 
666     duplex_priv.xMutex = rt_mutex_create("sound_mtx", RT_IPC_FLAG_PRIO);
667     if(duplex_priv.xMutex == RT_NULL) {
668         printf("mutex create failed.\n");
669         goto err_create_mutex;
670     }
671 
672 //  ret = xTaskCreate(arecord_entry, (signed portCHAR *) "arecord-thread",
673 //              thread_size, &duplex_priv, priority, &pxCreatedTask);
674 //  if (!ret) {
675 //      printf("arecord-thread create failed.\n");
676 //      goto err_create_arecord;
677 //  }
678 
679     playback_fs_wav(duplex_priv.playback_mgr, g_pcm_name, duplex_priv.output_name);
680     /* wait for capturing finished */
681     ret = rt_mutex_take(duplex_priv.xMutex, timeout);
682     if (!ret) {
683         printf("[%s] semaphore take failed.\n", __func__);
684         goto err_arecord_timeout;
685     }
686     rt_mutex_release(duplex_priv.xMutex);
687     rt_mutex_delete(duplex_priv.xMutex);
688 
689 #ifdef DUPLEX_FS_WAV
690     /* after capture finished */
691     playback_fs_wav(duplex_priv.playback_mgr, "default", duplex_priv.input_name);
692 #endif
693 
694     audio_mgr_release(duplex_priv.capture_mgr);
695     audio_mgr_release(duplex_priv.playback_mgr);
696     return 0;
697 
698 err_arecord_timeout:
699 //  vTaskDelete(pxCreatedTask);
700 err_create_arecord:
701 err_format:
702 err_create_mutex:
703 err_in_filename_null:
704 err_out_filename_null:
705 err_cmd:
706     audio_mgr_release(duplex_priv.capture_mgr);
707 err_malloc_capture_mgr:
708     audio_mgr_release(duplex_priv.playback_mgr);
709     return ret;
710 }
711 FINSH_FUNCTION_EXPORT_CMD(cmd_aduplex, aduplex, Playback and Record);
712