1 /*
2  * Copyright (c) 2006-2025 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2017-05-09     Urey         first version
9  * 2019-07-09     Zero-Free    improve device ops interface and data flows
10  * 2025-03-04     wumingzi     add doxygen comments.
11  */
12 
13 #include <stdio.h>
14 #include <string.h>
15 #include <rthw.h>
16 #include <rtdevice.h>
17 
18 #define DBG_TAG              "audio"
19 #define DBG_LVL              DBG_INFO
20 #include <rtdbg.h>
21 
22 #ifndef MIN
23 #define MIN(a, b)         ((a) < (b) ? (a) : (b))
24 #endif
25 
26 /**
27  * @addtogroup group_drivers_audio
28  */
29 
30 /** @{ */
31 
32 enum
33 {
34     REPLAY_EVT_NONE  = 0x00,
35     REPLAY_EVT_START = 0x01,
36     REPLAY_EVT_STOP  = 0x02,
37 };
38 
39 /**
40  * @brief Send a replay frame to the audio hardware device
41  *
42  * This function handles sending audio data from the memory queue to the hardware buffer for playback.
43  * If there is no data available in the queue, it sends zero frames. Otherwise, it copies data from the memory pool
44  * to the hardware device FIFO and manages the read index and position accordingly.
45  *
46  * @param[in] audio pointer to the audio device structure
47  *
48  * @return error code, RT_EOK is successful otherwise means failure
49  *
50  * @note This function may temporarily disable interrupts or perform time-consuming operations like memcpy,
51  *       which could affect system responsiveness
52  */
_audio_send_replay_frame(struct rt_audio_device * audio)53 static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio)
54 {
55     rt_err_t result = RT_EOK;
56     rt_uint8_t *data;
57     rt_size_t dst_size, src_size;
58     rt_uint16_t position, remain_bytes = 0, index = 0;
59     struct rt_audio_buf_info *buf_info;
60 
61     RT_ASSERT(audio != RT_NULL);
62 
63     buf_info = &audio->replay->buf_info;
64     /* save current pos */
65     position = audio->replay->pos;
66     dst_size = buf_info->block_size;
67 
68     /* check replay queue is empty */
69     if (rt_data_queue_peek(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK)
70     {
71         /* ack stop event */
72         if (audio->replay->event & REPLAY_EVT_STOP)
73             rt_completion_done(&audio->replay->cmp);
74 
75         /* send zero frames */
76         rt_memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
77 
78         audio->replay->pos += dst_size;
79         audio->replay->pos %= buf_info->total_size;
80     }
81     else
82     {
83         rt_memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
84 
85         /* copy data from memory pool to hardware device fifo */
86         while (index < dst_size)
87         {
88             result = rt_data_queue_peek(&audio->replay->queue, (const void **)&data, &src_size);
89             if (result != RT_EOK)
90             {
91                 LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes);
92                 audio->replay->pos -= remain_bytes;
93                 audio->replay->pos += dst_size;
94                 audio->replay->pos %= buf_info->total_size;
95                 audio->replay->read_index = 0;
96                 result = -RT_EEMPTY;
97                 break;
98             }
99 
100             remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index));
101             rt_memcpy(&buf_info->buffer[audio->replay->pos],
102                    &data[audio->replay->read_index], remain_bytes);
103 
104             index += remain_bytes;
105             audio->replay->read_index += remain_bytes;
106             audio->replay->pos += remain_bytes;
107             audio->replay->pos %= buf_info->total_size;
108 
109             if (audio->replay->read_index == src_size)
110             {
111                 /* free memory */
112                 audio->replay->read_index = 0;
113                 rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO);
114                 rt_mp_free(data);
115 
116                 /* notify transmitted complete. */
117                 if (audio->parent.tx_complete != RT_NULL)
118                     audio->parent.tx_complete(&audio->parent, (void *)data);
119             }
120         }
121     }
122 
123     if (audio->ops->transmit != RT_NULL)
124     {
125         if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size)
126             result = -RT_ERROR;
127     }
128 
129     return result;
130 }
131 
132 /**
133  * @brief Write replay frame into audio device replay queue
134  *
135  * @param[in] audio pointer to audio device
136  *
137  * @return error code, RT_EOK is successful otherwise means failure
138  */
_audio_flush_replay_frame(struct rt_audio_device * audio)139 static rt_err_t _audio_flush_replay_frame(struct rt_audio_device *audio)
140 {
141     rt_err_t result = RT_EOK;
142 
143     if (audio->replay->write_index)
144     {
145         result = rt_data_queue_push(&audio->replay->queue,
146                                     (const void **)audio->replay->write_data,
147                                     audio->replay->write_index,
148                                     RT_WAITING_FOREVER);
149 
150         audio->replay->write_index = 0;
151     }
152 
153     return result;
154 }
155 
156 /**
157  * @brief Replay audio
158  *
159  * @param[in] audio pointer to audio device
160  *
161  * @return error code, RT_EOK is successful otherwise means failure
162  */
_aduio_replay_start(struct rt_audio_device * audio)163 static rt_err_t _aduio_replay_start(struct rt_audio_device *audio)
164 {
165     rt_err_t result = RT_EOK;
166 
167     if (audio->replay->activated != RT_TRUE)
168     {
169         /* start playback hardware device */
170         if (audio->ops->start)
171             result = audio->ops->start(audio, AUDIO_STREAM_REPLAY);
172 
173         audio->replay->activated = RT_TRUE;
174         LOG_D("start audio replay device");
175     }
176 
177     return result;
178 }
179 
180 /**
181  * @brief Stop replaying audio
182  *
183  * When audio->replay->queue is empty and the audio->replay->event was set REPLAY_EVT_STOP,
184  * _audio_send_replay_frame will send completion to stop replaying audio.
185  *
186  * @param[in] audio pointer to audio device
187  *
188  * @return error code, RT_EOK is successful otherwise means failure
189  */
_aduio_replay_stop(struct rt_audio_device * audio)190 static rt_err_t _aduio_replay_stop(struct rt_audio_device *audio)
191 {
192     rt_err_t result = RT_EOK;
193 
194     if (audio->replay->activated == RT_TRUE)
195     {
196         /* flush replay remian frames */
197         _audio_flush_replay_frame(audio);
198 
199         /* notify irq(or thread) to stop the data transmission */
200         audio->replay->event |= REPLAY_EVT_STOP;
201 
202         /* waiting for the remaining data transfer to complete */
203         rt_completion_init(&audio->replay->cmp);
204         rt_completion_wait(&audio->replay->cmp, RT_WAITING_FOREVER);
205         audio->replay->event &= ~REPLAY_EVT_STOP;
206 
207         /* stop playback hardware device */
208         if (audio->ops->stop)
209             result = audio->ops->stop(audio, AUDIO_STREAM_REPLAY);
210 
211         audio->replay->activated = RT_FALSE;
212         LOG_D("stop audio replay device");
213     }
214 
215     return result;
216 }
217 
218 /**
219  * @brief Open audio pipe and start to record audio
220  *
221  * @param[in] audio pointer to audio device
222  *
223  * @return error code, RT_EOK is successful otherwise means failure
224  */
_audio_record_start(struct rt_audio_device * audio)225 static rt_err_t _audio_record_start(struct rt_audio_device *audio)
226 {
227     rt_err_t result = RT_EOK;
228 
229     if (audio->record->activated != RT_TRUE)
230     {
231         /* open audio record pipe */
232         rt_device_open(RT_DEVICE(&audio->record->pipe), RT_DEVICE_OFLAG_RDONLY);
233 
234         /* start record hardware device */
235         if (audio->ops->start)
236             result = audio->ops->start(audio, AUDIO_STREAM_RECORD);
237 
238         audio->record->activated = RT_TRUE;
239         LOG_D("start audio record device");
240     }
241 
242     return result;
243 }
244 
245 /**
246  * @brief stop recording audio and closeaudio pipe
247  *
248  * @param[in] audio pointer to audio device
249  *
250  * @return error code, RT_EOK is successful otherwise means failure
251  */
_audio_record_stop(struct rt_audio_device * audio)252 static rt_err_t _audio_record_stop(struct rt_audio_device *audio)
253 {
254     rt_err_t result = RT_EOK;
255 
256     if (audio->record->activated == RT_TRUE)
257     {
258         /* stop record hardware device */
259         if (audio->ops->stop)
260             result = audio->ops->stop(audio, AUDIO_STREAM_RECORD);
261 
262         /* close audio record pipe */
263         rt_device_close(RT_DEVICE(&audio->record->pipe));
264 
265         audio->record->activated = RT_FALSE;
266         LOG_D("stop audio record device");
267     }
268 
269     return result;
270 }
271 
272 /**
273  * @brief Init audio pipe
274  *
275  * In kernel, this function will set replay or record function depending on device
276  * flag. For replaying, it will malloc for managing audio replay struct meanwhile
277  * creating mempool and dataqueue.For recording, it will creat audio pipe and
278  * it's ringbuffer.
279  * In driver, this function will only execute hardware driver initialization code
280  * and get hardware buffer infomation.
281  *
282  * @param[in] dev pointer to audio device
283  *
284  * @return error code, RT_EOK is successful otherwise means failure
285  */
_audio_dev_init(struct rt_device * dev)286 static rt_err_t _audio_dev_init(struct rt_device *dev)
287 {
288     rt_err_t result = RT_EOK;
289     struct rt_audio_device *audio;
290 
291     RT_ASSERT(dev != RT_NULL);
292     audio = (struct rt_audio_device *) dev;
293 
294     /* initialize replay & record */
295     audio->replay = RT_NULL;
296     audio->record = RT_NULL;
297 
298     /* initialize replay */
299     if (dev->flag & RT_DEVICE_FLAG_WRONLY)
300     {
301         struct rt_audio_replay *replay = (struct rt_audio_replay *) rt_malloc(sizeof(struct rt_audio_replay));
302 
303         if (replay == RT_NULL)
304             return -RT_ENOMEM;
305         rt_memset(replay, 0, sizeof(struct rt_audio_replay));
306 
307         /* init memory pool for replay */
308         replay->mp = rt_mp_create("adu_mp", RT_AUDIO_REPLAY_MP_BLOCK_COUNT, RT_AUDIO_REPLAY_MP_BLOCK_SIZE);
309         if (replay->mp == RT_NULL)
310         {
311             rt_free(replay);
312             LOG_E("create memory pool for replay failed");
313             return -RT_ENOMEM;
314         }
315 
316         /* init queue for audio replay */
317         rt_data_queue_init(&replay->queue, CFG_AUDIO_REPLAY_QUEUE_COUNT, 0, RT_NULL);
318 
319         /* init mutex lock for audio replay */
320         rt_mutex_init(&replay->lock, "replay", RT_IPC_FLAG_PRIO);
321 
322         replay->activated = RT_FALSE;
323         audio->replay = replay;
324     }
325 
326     /* initialize record */
327     if (dev->flag & RT_DEVICE_FLAG_RDONLY)
328     {
329         struct rt_audio_record *record = (struct rt_audio_record *) rt_malloc(sizeof(struct rt_audio_record));
330         rt_uint8_t *buffer;
331 
332         if (record == RT_NULL)
333             return -RT_ENOMEM;
334         rt_memset(record, 0, sizeof(struct rt_audio_record));
335 
336         /* init pipe for record*/
337         buffer = rt_malloc(RT_AUDIO_RECORD_PIPE_SIZE);
338         if (buffer == RT_NULL)
339         {
340             rt_free(record);
341             LOG_E("malloc memory for for record pipe failed");
342             return -RT_ENOMEM;
343         }
344         rt_audio_pipe_init(&record->pipe, "record",
345                            (rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD),
346                            buffer,
347                            RT_AUDIO_RECORD_PIPE_SIZE);
348 
349         record->activated = RT_FALSE;
350         audio->record = record;
351     }
352 
353     /* initialize hardware configuration */
354     if (audio->ops->init)
355         audio->ops->init(audio);
356 
357     /* get replay buffer information */
358     if (audio->ops->buffer_info)
359         audio->ops->buffer_info(audio, &audio->replay->buf_info);
360 
361     return result;
362 }
363 
364 /**
365  * @brief Start record audio
366  *
367  * @param[in] dev pointer to audio device
368  *
369  * @param[in] oflag device flag
370  *
371  * @return error code, RT_EOK is successful otherwise means failure
372  */
_audio_dev_open(struct rt_device * dev,rt_uint16_t oflag)373 static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
374 {
375     struct rt_audio_device *audio;
376 
377     RT_ASSERT(dev != RT_NULL);
378     audio = (struct rt_audio_device *) dev;
379 
380     /* check device flag with the open flag */
381     if ((oflag & RT_DEVICE_OFLAG_RDONLY) && !(dev->flag & RT_DEVICE_FLAG_RDONLY))
382         return -RT_EIO;
383     if ((oflag & RT_DEVICE_OFLAG_WRONLY) && !(dev->flag & RT_DEVICE_FLAG_WRONLY))
384         return -RT_EIO;
385 
386     /* get open flags */
387     dev->open_flag = oflag & 0xff;
388 
389     /* initialize the Rx/Tx structure according to open flag */
390     if (oflag & RT_DEVICE_OFLAG_WRONLY)
391     {
392         if (audio->replay->activated != RT_TRUE)
393         {
394             LOG_D("open audio replay device, oflag = %x\n", oflag);
395             audio->replay->write_index = 0;
396             audio->replay->read_index = 0;
397             audio->replay->pos = 0;
398             audio->replay->event = REPLAY_EVT_NONE;
399         }
400         dev->open_flag |= RT_DEVICE_OFLAG_WRONLY;
401     }
402 
403     if (oflag & RT_DEVICE_OFLAG_RDONLY)
404     {
405         /* open record pipe */
406         if (audio->record->activated != RT_TRUE)
407         {
408             LOG_D("open audio record device ,oflag = %x\n", oflag);
409 
410             _audio_record_start(audio);
411             audio->record->activated = RT_TRUE;
412         }
413         dev->open_flag |= RT_DEVICE_OFLAG_RDONLY;
414     }
415 
416     return RT_EOK;
417 }
418 
419 /**
420  * @brief Stop record, replay or both.
421  *
422  * @param[in] dev pointer to audio device
423  *
424  * @return useless param
425  */
_audio_dev_close(struct rt_device * dev)426 static rt_err_t _audio_dev_close(struct rt_device *dev)
427 {
428     struct rt_audio_device *audio;
429     RT_ASSERT(dev != RT_NULL);
430     audio = (struct rt_audio_device *) dev;
431 
432     if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
433     {
434         /* stop replay stream */
435         _aduio_replay_stop(audio);
436         dev->open_flag &= ~RT_DEVICE_OFLAG_WRONLY;
437     }
438 
439     if (dev->open_flag & RT_DEVICE_OFLAG_RDONLY)
440     {
441         /* stop record stream */
442         _audio_record_stop(audio);
443         dev->open_flag &= ~RT_DEVICE_OFLAG_RDONLY;
444     }
445 
446     return RT_EOK;
447 }
448 
449 /**
450  * @brief Read audio device
451  *
452  * @param[in] dev pointer to device
453  *
454  * @param[in] pos position when reading
455  *
456  * @param[out] buffer a data buffer to save the read data
457  *
458  * @param[in] size buffer size
459  *
460  * @return the actually read size on successfully, otherwise 0 will be returned.
461  *
462  * @note
463  */
_audio_dev_read(struct rt_device * dev,rt_off_t pos,void * buffer,rt_size_t size)464 static rt_ssize_t _audio_dev_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
465 {
466     struct rt_audio_device *audio;
467     RT_ASSERT(dev != RT_NULL);
468     audio = (struct rt_audio_device *) dev;
469 
470     if (!(dev->open_flag & RT_DEVICE_OFLAG_RDONLY) || (audio->record == RT_NULL))
471         return 0;
472 
473     return rt_device_read(RT_DEVICE(&audio->record->pipe), pos, buffer, size);
474 }
475 
476 /**
477  * @brief Write data into replay data queue and replay it
478  *
479  * @param[in] dev pointer to device
480  *
481  * @param[in] pos useless param
482  *
483  * @param[in] buffer a data buffer to be written into data queue
484  *
485  * @param[in] size buffer size
486  *
487  * @return the actually read size on successfully, otherwise 0 will be returned.
488  *
489  * @note This function will take mutex.
490  */
_audio_dev_write(struct rt_device * dev,rt_off_t pos,const void * buffer,rt_size_t size)491 static rt_ssize_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
492 {
493 
494     struct rt_audio_device *audio;
495     rt_uint8_t *ptr;
496     rt_uint16_t block_size, remain_bytes, index = 0;
497 
498     RT_ASSERT(dev != RT_NULL);
499     audio = (struct rt_audio_device *) dev;
500 
501     if (!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL))
502         return 0;
503 
504     /* push a new frame to replay data queue */
505     ptr = (rt_uint8_t *)buffer;
506     block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE;
507 
508     rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER);
509     while (index < size)
510     {
511         /* request buffer from replay memory pool */
512         if (audio->replay->write_index % block_size == 0)
513         {
514             audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER);
515             rt_memset(audio->replay->write_data, 0, block_size);
516         }
517 
518         /* copy data to replay memory pool */
519         remain_bytes = MIN((block_size - audio->replay->write_index), (size - index));
520         rt_memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes);
521 
522         index += remain_bytes;
523         audio->replay->write_index += remain_bytes;
524         audio->replay->write_index %= block_size;
525 
526         if (audio->replay->write_index == 0)
527         {
528             rt_data_queue_push(&audio->replay->queue,
529                                audio->replay->write_data,
530                                block_size,
531                                RT_WAITING_FOREVER);
532         }
533     }
534     rt_mutex_release(&audio->replay->lock);
535 
536     /* check replay state */
537     if (audio->replay->activated != RT_TRUE)
538     {
539         _aduio_replay_start(audio);
540         audio->replay->activated = RT_TRUE;
541     }
542 
543     return index;
544 }
545 
546 /**
547  * @brief Control audio device
548  *
549  * @param[in] dev pointer to device
550  *
551  * @param[in] cmd audio cmd, it can be one of value in @ref group_audio_control
552  *
553  * @param[in] args command argument
554  *
555  * @return error code, RT_EOK is successful otherwise means failure
556  */
_audio_dev_control(struct rt_device * dev,int cmd,void * args)557 static rt_err_t _audio_dev_control(struct rt_device *dev, int cmd, void *args)
558 {
559     rt_err_t result = RT_EOK;
560     struct rt_audio_device *audio;
561     RT_ASSERT(dev != RT_NULL);
562     audio = (struct rt_audio_device *) dev;
563 
564     /* dev stat...*/
565     switch (cmd)
566     {
567     case AUDIO_CTL_GETCAPS:
568     {
569         struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
570 
571         LOG_D("AUDIO_CTL_GETCAPS: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
572         if (audio->ops->getcaps != RT_NULL)
573         {
574             result = audio->ops->getcaps(audio, caps);
575         }
576 
577         break;
578     }
579 
580     case AUDIO_CTL_CONFIGURE:
581     {
582         struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
583 
584         LOG_D("AUDIO_CTL_CONFIGURE: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
585         if (audio->ops->configure != RT_NULL)
586         {
587             result = audio->ops->configure(audio, caps);
588         }
589 
590         break;
591     }
592 
593     case AUDIO_CTL_START:
594     {
595         int stream = *(int *) args;
596 
597         LOG_D("AUDIO_CTL_START: stream = %d", stream);
598         if (stream == AUDIO_STREAM_REPLAY)
599         {
600             result = _aduio_replay_start(audio);
601         }
602         else
603         {
604             result = _audio_record_start(audio);
605         }
606 
607         break;
608     }
609 
610     case AUDIO_CTL_STOP:
611     {
612         int stream = *(int *) args;
613 
614         LOG_D("AUDIO_CTL_STOP: stream = %d", stream);
615         if (stream == AUDIO_STREAM_REPLAY)
616         {
617             result = _aduio_replay_stop(audio);
618         }
619         else
620         {
621             result = _audio_record_stop(audio);
622         }
623 
624         break;
625     }
626 
627     default:
628         break;
629     }
630 
631     return result;
632 }
633 
634 #ifdef RT_USING_DEVICE_OPS
635 const static struct rt_device_ops audio_ops =
636 {
637     _audio_dev_init,
638     _audio_dev_open,
639     _audio_dev_close,
640     _audio_dev_read,
641     _audio_dev_write,
642     _audio_dev_control
643 };
644 #endif
645 
646 /**
647  * @brief Register and initialize audio device
648  *
649  * @param[in] audio pointer to audio deive
650  *
651  * @param[in] name device name
652  *
653  * @param[in] flag device flags
654  *
655  * @param[in] data user data
656  *
657  * @return error code, RT_EOK is successful otherwise means failure
658  */
rt_audio_register(struct rt_audio_device * audio,const char * name,rt_uint32_t flag,void * data)659 rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data)
660 {
661     rt_err_t result = RT_EOK;
662     struct rt_device *device;
663 
664     RT_ASSERT(audio != RT_NULL);
665     device = &(audio->parent);
666 
667     device->type = RT_Device_Class_Sound;
668     device->rx_indicate = RT_NULL;
669     device->tx_complete = RT_NULL;
670 
671 #ifdef RT_USING_DEVICE_OPS
672     device->ops  = &audio_ops;
673 #else
674     device->init    = _audio_dev_init;
675     device->open    = _audio_dev_open;
676     device->close   = _audio_dev_close;
677     device->read    = _audio_dev_read;
678     device->write   = _audio_dev_write;
679     device->control = _audio_dev_control;
680 #endif
681     device->user_data = data;
682 
683     /* register a character device */
684     result = rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE);
685 
686     /* initialize audio device */
687     if (result == RT_EOK)
688         result = rt_device_init(device);
689 
690     return result;
691 }
692 
693 /**
694  * @brief Set audio sample rate
695  *
696  * @param[in] bitValue audio sample rate, it can be one of value in @ref group_audio_samp_rates
697  *
698  * @return speed has been set
699  */
rt_audio_samplerate_to_speed(rt_uint32_t bitValue)700 int rt_audio_samplerate_to_speed(rt_uint32_t bitValue)
701 {
702     int speed = 0;
703     switch (bitValue)
704     {
705     case AUDIO_SAMP_RATE_8K:
706         speed = 8000;
707         break;
708     case AUDIO_SAMP_RATE_11K:
709         speed = 11052;
710         break;
711     case AUDIO_SAMP_RATE_16K:
712         speed = 16000;
713         break;
714     case AUDIO_SAMP_RATE_22K:
715         speed = 22050;
716         break;
717     case AUDIO_SAMP_RATE_32K:
718         speed = 32000;
719         break;
720     case AUDIO_SAMP_RATE_44K:
721         speed = 44100;
722         break;
723     case AUDIO_SAMP_RATE_48K:
724         speed = 48000;
725         break;
726     case AUDIO_SAMP_RATE_96K:
727         speed = 96000;
728         break;
729     case AUDIO_SAMP_RATE_128K:
730         speed = 128000;
731         break;
732     case AUDIO_SAMP_RATE_160K:
733         speed = 160000;
734         break;
735     case AUDIO_SAMP_RATE_172K:
736         speed = 176400;
737         break;
738     case AUDIO_SAMP_RATE_192K:
739         speed = 192000;
740         break;
741     default:
742         break;
743     }
744 
745     return speed;
746 }
747 
748 /**
749  * @brief Send a replay frame to the audio hardware device
750  *
751  * See _audio_send_replay_frame for details
752  *
753  * @param[in] audio pointer to audio device
754  *
755  * @return void
756  */
rt_audio_tx_complete(struct rt_audio_device * audio)757 void rt_audio_tx_complete(struct rt_audio_device *audio)
758 {
759     /* try to send next frame */
760     _audio_send_replay_frame(audio);
761 }
762 
763 /**
764  * @brief Receive recording from audio device
765  *
766  * @param[in] audio pointer to audio device
767  *
768  * @param[in] pbuf pointer ro data to be received
769  *
770  * @param[in] len buffer size
771  *
772  * @return void
773  */
rt_audio_rx_done(struct rt_audio_device * audio,rt_uint8_t * pbuf,rt_size_t len)774 void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len)
775 {
776     /* save data to record pipe */
777     rt_device_write(RT_DEVICE(&audio->record->pipe), 0, pbuf, len);
778 
779     /* invoke callback */
780     if (audio->parent.rx_indicate != RT_NULL)
781         audio->parent.rx_indicate(&audio->parent, len);
782 }
783 
784 /** @} group_drivers_audio */