audio_duplex.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright (C) 2014 BlueKitchen GmbH
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. * 4. Any redistribution, use, or modification is done solely for
  17. * personal benefit and not for any commercial purpose or for
  18. * monetary gain.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
  24. * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * Please inquire about commercial licensing options at
  34. * contact@bluekitchen-gmbh.com
  35. *
  36. */
  37. #define BTSTACK_FILE__ "audio_duplex.c"
  38. /*
  39. * Audio Duplex: forward audio from BTstack audio source to audio sink - test for audio interface
  40. *
  41. */
  42. #include "btstack.h"
  43. // uncomment to test start/stop of loopback / audio driver
  44. // #define TEST_START_STOP_INTERVAL 5000
  45. // change to 1 for mono input and 2 for stereo input
  46. #define NUM_INPUT_CHANNELS 1
  47. #define BYTES_PER_SAMPLE (NUM_INPUT_CHANNELS * 2)
  48. #ifdef TEST_START_STOP_INTERVAL
  49. static void stop_loopback(btstack_timer_source_t * ts);
  50. #endif
  51. static btstack_timer_source_t start_stop_timer;
  52. // samplerate
  53. const uint32_t samplerate = 16000;
  54. // ring buffer for audio
  55. #define BUFFER_SAMPLES 1024
  56. static uint16_t audio_buffer_storage[BUFFER_SAMPLES];
  57. static btstack_ring_buffer_t audio_buffer;
  58. // transfer buffer
  59. #define TRANSFER_BUFFER_LEN 128
  60. static int16_t transfer_buffer[TRANSFER_BUFFER_LEN];
  61. // playback starts after audio_buffer is half full
  62. static int playback_started;
  63. // sample couners
  64. static int count_recording;
  65. static int count_playback;
  66. static void audio_recording(const int16_t * pcm_buffer, uint16_t num_samples_to_write){
  67. count_recording += num_samples_to_write;
  68. int err = btstack_ring_buffer_write(&audio_buffer, (uint8_t *) pcm_buffer, num_samples_to_write * BYTES_PER_SAMPLE);
  69. if (err){
  70. printf("Failed to store %u samples\n", num_samples_to_write);
  71. }
  72. }
  73. static void audio_playback(int16_t * pcm_buffer, uint16_t num_samples_to_write){
  74. int num_samples_in_buffer = btstack_ring_buffer_bytes_available(&audio_buffer) / BYTES_PER_SAMPLE;
  75. if (playback_started == 0){
  76. if ( num_samples_in_buffer < (BUFFER_SAMPLES / 2)) return;
  77. playback_started = 1;
  78. }
  79. count_playback += num_samples_to_write;
  80. while (num_samples_to_write){
  81. num_samples_in_buffer = btstack_ring_buffer_bytes_available(&audio_buffer) / BYTES_PER_SAMPLE;
  82. int num_samples_ready = btstack_min(num_samples_in_buffer, num_samples_to_write);
  83. // limit by transfer_buffer
  84. int num_samples_from_buffer = btstack_min(num_samples_ready, TRANSFER_BUFFER_LEN);
  85. if (!num_samples_from_buffer) break;
  86. uint32_t bytes_read;
  87. btstack_ring_buffer_read(&audio_buffer, (uint8_t *) transfer_buffer, num_samples_from_buffer * BYTES_PER_SAMPLE, &bytes_read);
  88. #if (NUM_INPUT_CHANNELS == 1)
  89. // duplicate samples for stereo output
  90. int i;
  91. for (i=0; i < num_samples_from_buffer;i++) {
  92. *pcm_buffer++ = transfer_buffer[i];
  93. *pcm_buffer++ = transfer_buffer[i];
  94. num_samples_to_write--;
  95. }
  96. #endif
  97. #if (NUM_INPUT_CHANNELS == 2)
  98. // copy samples
  99. int i;
  100. int j = 0;
  101. for (i=0; i < num_samples_from_buffer;i++) {
  102. *pcm_buffer++ = transfer_buffer[j++];
  103. *pcm_buffer++ = transfer_buffer[j++];
  104. num_samples_to_write--;
  105. }
  106. #endif
  107. }
  108. // warn about underrun
  109. if (num_samples_to_write){
  110. printf("Buffer underrun - recording %u, playback %u - delta %d!\n", count_recording, count_playback, count_recording - count_playback);
  111. }
  112. // fill rest with silence
  113. while (num_samples_to_write){
  114. *pcm_buffer++ = 0;
  115. *pcm_buffer++ = 0;
  116. num_samples_to_write--;
  117. }
  118. }
  119. static void start_loopback(btstack_timer_source_t * ts){
  120. const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
  121. const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
  122. // prepare audio buffer
  123. btstack_ring_buffer_init(&audio_buffer, (uint8_t*) &audio_buffer_storage[0], sizeof(audio_buffer_storage));
  124. // setup audio: mono input -> stereo output
  125. audio_sink->init(2, samplerate, &audio_playback);
  126. audio_source->init(NUM_INPUT_CHANNELS, samplerate, &audio_recording);
  127. // start duplex
  128. audio_sink->start_stream();
  129. audio_source->start_stream();
  130. printf("Start Audio Loopback\n");
  131. #ifdef TEST_START_STOP_INTERVAL
  132. // schedule stop
  133. btstack_run_loop_set_timer_handler(ts, &stop_loopback);
  134. btstack_run_loop_set_timer(ts, TEST_START_STOP_INTERVAL);
  135. btstack_run_loop_add_timer(ts);
  136. #else
  137. UNUSED(ts);
  138. #endif
  139. }
  140. #ifdef TEST_START_STOP_INTERVAL
  141. static void stop_loopback(btstack_timer_source_t * ts){
  142. const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
  143. const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
  144. // stop streams
  145. audio_sink->stop_stream();
  146. audio_source->stop_stream();
  147. // close audio
  148. audio_sink->close();
  149. audio_source->close();
  150. playback_started = 0;
  151. printf("Stop Audio Loopback\n");
  152. // schedule stop
  153. btstack_run_loop_set_timer_handler(ts, &start_loopback);
  154. btstack_run_loop_set_timer(ts, TEST_START_STOP_INTERVAL);
  155. btstack_run_loop_add_timer(ts);
  156. }
  157. #endif
  158. int btstack_main(int argc, const char * argv[]);
  159. int btstack_main(int argc, const char * argv[]){
  160. (void)argc;
  161. (void)argv;
  162. // check audio interface
  163. const btstack_audio_sink_t * audio_sink = btstack_audio_sink_get_instance();
  164. if (!audio_sink){
  165. printf("BTstack Audio Sink not setup\n");
  166. return 10;
  167. }
  168. const btstack_audio_source_t * audio_source = btstack_audio_source_get_instance();
  169. if (!audio_source){
  170. printf("BTstack Audio Source not setup\n");
  171. return 10;
  172. }
  173. start_loopback(&start_stop_timer);
  174. return 0;
  175. }