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 */