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