xref: /btstack/platform/embedded/btstack_audio_embedded.c (revision 2fca4dad957cd7b88f4657ed51e89c12615dda72)
1dfa32746SMatthias Ringwald /*
2dfa32746SMatthias Ringwald  * Copyright (C) 2018 BlueKitchen GmbH
3dfa32746SMatthias Ringwald  *
4dfa32746SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5dfa32746SMatthias Ringwald  * modification, are permitted provided that the following conditions
6dfa32746SMatthias Ringwald  * are met:
7dfa32746SMatthias Ringwald  *
8dfa32746SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9dfa32746SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10dfa32746SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11dfa32746SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12dfa32746SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13dfa32746SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14dfa32746SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15dfa32746SMatthias Ringwald  *    from this software without specific prior written permission.
16dfa32746SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17dfa32746SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18dfa32746SMatthias Ringwald  *    monetary gain.
19dfa32746SMatthias Ringwald  *
20dfa32746SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21dfa32746SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22dfa32746SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*2fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*2fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25dfa32746SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26dfa32746SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27dfa32746SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28dfa32746SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29dfa32746SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30dfa32746SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31dfa32746SMatthias Ringwald  * SUCH DAMAGE.
32dfa32746SMatthias Ringwald  *
33dfa32746SMatthias Ringwald  * Please inquire about commercial licensing options at
34dfa32746SMatthias Ringwald  * [email protected]
35dfa32746SMatthias Ringwald  *
36dfa32746SMatthias Ringwald  */
37dfa32746SMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_audio_embedded.c"
39dfa32746SMatthias Ringwald 
40dfa32746SMatthias Ringwald /*
41dfa32746SMatthias Ringwald  *  btstack_audio_embedded.c
42dfa32746SMatthias Ringwald  *
43dfa32746SMatthias Ringwald  *  Implementation of btstack_audio.h using hal_audio.h for embedded run loop
44dfa32746SMatthias Ringwald  *
45dfa32746SMatthias Ringwald  */
46dfa32746SMatthias Ringwald 
47dfa32746SMatthias Ringwald #include "btstack_config.h"
48dfa32746SMatthias Ringwald #include "btstack_debug.h"
49dfa32746SMatthias Ringwald #include "btstack_audio.h"
50dfa32746SMatthias Ringwald #include "btstack_run_loop_embedded.h"
51dfa32746SMatthias Ringwald #include "hal_audio.h"
52dfa32746SMatthias Ringwald 
53dfa32746SMatthias Ringwald // allow to compile all files in embedded folder even if there's no audio support
54dfa32746SMatthias Ringwald #ifdef HAVE_HAL_AUDIO
55dfa32746SMatthias Ringwald 
56dfa32746SMatthias Ringwald #define DRIVER_POLL_INTERVAL_MS          5
57dfa32746SMatthias Ringwald 
58dfa32746SMatthias Ringwald // client
59dfa32746SMatthias Ringwald static void (*playback_callback)(int16_t * buffer, uint16_t num_samples);
60fb90eb3fSMatthias Ringwald static void (*recording_callback)(const int16_t * buffer, uint16_t num_samples);
61dfa32746SMatthias Ringwald 
62dfa32746SMatthias Ringwald // timer to fill output ring buffer
630402264cSMatthias Ringwald static btstack_timer_source_t  driver_timer_sink;
64fb90eb3fSMatthias Ringwald static btstack_timer_source_t  driver_timer_source;
65dfa32746SMatthias Ringwald 
66dfa32746SMatthias Ringwald static volatile unsigned int output_buffer_to_play;
67dfa32746SMatthias Ringwald static          unsigned int output_buffer_to_fill;
68dfa32746SMatthias Ringwald static          unsigned int output_buffer_count;
69dfa32746SMatthias Ringwald static          unsigned int output_buffer_samples;
70dfa32746SMatthias Ringwald 
71fb90eb3fSMatthias Ringwald static volatile int       input_buffer_ready;
72fb90eb3fSMatthias Ringwald static volatile const int16_t * input_buffer_samples;
73fb90eb3fSMatthias Ringwald static volatile uint16_t  input_buffer_num_samples;
74fb90eb3fSMatthias Ringwald 
756fd4ca9eSMatthias Ringwald static int source_active;
766fd4ca9eSMatthias Ringwald static int sink_active;
776fd4ca9eSMatthias Ringwald 
78dfa32746SMatthias Ringwald static void btstack_audio_audio_played(uint8_t buffer_index){
79dfa32746SMatthias Ringwald     output_buffer_to_play = (buffer_index + 1) % output_buffer_count;
80dfa32746SMatthias Ringwald }
81dfa32746SMatthias Ringwald 
82dfa32746SMatthias Ringwald static void btstack_audio_audio_recorded(const int16_t * samples, uint16_t num_samples){
83fb90eb3fSMatthias Ringwald     input_buffer_samples     = samples;
84fb90eb3fSMatthias Ringwald     input_buffer_num_samples = num_samples;
85fb90eb3fSMatthias Ringwald     input_buffer_ready       = 1;
86dfa32746SMatthias Ringwald }
87dfa32746SMatthias Ringwald 
880402264cSMatthias Ringwald static void driver_timer_handler_sink(btstack_timer_source_t * ts){
89dfa32746SMatthias Ringwald 
90dfa32746SMatthias Ringwald     // playback buffer ready to fill
910402264cSMatthias Ringwald     if (output_buffer_to_play != output_buffer_to_fill){
92ff0081eeSMatthias Ringwald         int16_t * buffer = hal_audio_sink_get_output_buffer(output_buffer_to_fill);
93dfa32746SMatthias Ringwald         (*playback_callback)(buffer, output_buffer_samples);
94dfa32746SMatthias Ringwald 
95dfa32746SMatthias Ringwald         // next
96dfa32746SMatthias Ringwald         output_buffer_to_fill = (output_buffer_to_fill + 1 ) % output_buffer_count;
97dfa32746SMatthias Ringwald     }
98dfa32746SMatthias Ringwald 
99dfa32746SMatthias Ringwald     // re-set timer
100dfa32746SMatthias Ringwald     btstack_run_loop_set_timer(ts, DRIVER_POLL_INTERVAL_MS);
101dfa32746SMatthias Ringwald     btstack_run_loop_add_timer(ts);
102dfa32746SMatthias Ringwald }
103dfa32746SMatthias Ringwald 
1040402264cSMatthias Ringwald static void driver_timer_handler_source(btstack_timer_source_t * ts){
105fb90eb3fSMatthias Ringwald     // deliver samples if ready
106fb90eb3fSMatthias Ringwald     if (input_buffer_ready){
107fb90eb3fSMatthias Ringwald         (*recording_callback)((const int16_t *)input_buffer_samples, input_buffer_num_samples);
108fb90eb3fSMatthias Ringwald         input_buffer_ready = 0;
1090402264cSMatthias Ringwald     }
110fb90eb3fSMatthias Ringwald 
111fb90eb3fSMatthias Ringwald     // re-set timer
112fb90eb3fSMatthias Ringwald     btstack_run_loop_set_timer(ts, DRIVER_POLL_INTERVAL_MS);
113fb90eb3fSMatthias Ringwald     btstack_run_loop_add_timer(ts);
114fb90eb3fSMatthias Ringwald }
1150402264cSMatthias Ringwald 
1160402264cSMatthias Ringwald static int btstack_audio_embedded_sink_init(
117dfa32746SMatthias Ringwald     uint8_t channels,
118dfa32746SMatthias Ringwald     uint32_t samplerate,
1190402264cSMatthias Ringwald     void (*playback)(int16_t * buffer, uint16_t num_samples)
120dfa32746SMatthias Ringwald ){
1210402264cSMatthias Ringwald     if (!playback){
1220402264cSMatthias Ringwald         log_error("No playback callback");
1230402264cSMatthias Ringwald         return 1;
1240402264cSMatthias Ringwald     }
125dfa32746SMatthias Ringwald 
1260402264cSMatthias Ringwald     playback_callback  = playback;
1270402264cSMatthias Ringwald 
128ff0081eeSMatthias Ringwald     hal_audio_sink_init(channels, samplerate, &btstack_audio_audio_played);
129dfa32746SMatthias Ringwald 
130dfa32746SMatthias Ringwald     return 0;
131dfa32746SMatthias Ringwald }
132dfa32746SMatthias Ringwald 
1330402264cSMatthias Ringwald static int btstack_audio_embedded_source_init(
1340402264cSMatthias Ringwald     uint8_t channels,
1350402264cSMatthias Ringwald     uint32_t samplerate,
1360402264cSMatthias Ringwald     void (*recording)(const int16_t * buffer, uint16_t num_samples)
1370402264cSMatthias Ringwald ){
1380402264cSMatthias Ringwald     if (!recording){
1390402264cSMatthias Ringwald         log_error("No recording callback");
1400402264cSMatthias Ringwald         return 1;
1410402264cSMatthias Ringwald     }
142fb90eb3fSMatthias Ringwald 
143fb90eb3fSMatthias Ringwald     recording_callback  = recording;
144fb90eb3fSMatthias Ringwald 
145fb90eb3fSMatthias Ringwald     hal_audio_source_init(channels, samplerate, &btstack_audio_audio_recorded);
146fb90eb3fSMatthias Ringwald 
1470402264cSMatthias Ringwald     return 0;
1480402264cSMatthias Ringwald }
149dfa32746SMatthias Ringwald 
1501b7f8fa1SMatthias Ringwald static void btstack_audio_embedded_sink_set_volume(uint8_t volume){
1511b7f8fa1SMatthias Ringwald     UNUSED(volume);
1521b7f8fa1SMatthias Ringwald }
1531b7f8fa1SMatthias Ringwald 
1541b7f8fa1SMatthias Ringwald static void btstack_audio_embedded_source_set_gain(uint8_t gain){
1551b7f8fa1SMatthias Ringwald     UNUSED(gain);
1561b7f8fa1SMatthias Ringwald }
1571b7f8fa1SMatthias Ringwald 
1580402264cSMatthias Ringwald static void btstack_audio_embedded_sink_start_stream(void){
159ff0081eeSMatthias Ringwald     output_buffer_count   = hal_audio_sink_get_num_output_buffers();
160ff0081eeSMatthias Ringwald     output_buffer_samples = hal_audio_sink_get_num_output_buffer_samples();
161dfa32746SMatthias Ringwald 
162dfa32746SMatthias Ringwald     // pre-fill HAL buffers
163dfa32746SMatthias Ringwald     uint16_t i;
164dfa32746SMatthias Ringwald     for (i=0;i<output_buffer_count;i++){
165ff0081eeSMatthias Ringwald         int16_t * buffer = hal_audio_sink_get_output_buffer(i);
166dfa32746SMatthias Ringwald         (*playback_callback)(buffer, output_buffer_samples);
167dfa32746SMatthias Ringwald     }
168dfa32746SMatthias Ringwald 
169dfa32746SMatthias Ringwald     output_buffer_to_play = 0;
170dfa32746SMatthias Ringwald     output_buffer_to_fill = 0;
171dfa32746SMatthias Ringwald 
172dfa32746SMatthias Ringwald     // start playback
173ff0081eeSMatthias Ringwald     hal_audio_sink_start();
174dfa32746SMatthias Ringwald 
175dfa32746SMatthias Ringwald     // start timer
1760402264cSMatthias Ringwald     btstack_run_loop_set_timer_handler(&driver_timer_sink, &driver_timer_handler_sink);
1770402264cSMatthias Ringwald     btstack_run_loop_set_timer(&driver_timer_sink, DRIVER_POLL_INTERVAL_MS);
1780402264cSMatthias Ringwald     btstack_run_loop_add_timer(&driver_timer_sink);
1796fd4ca9eSMatthias Ringwald 
1806fd4ca9eSMatthias Ringwald     // state
1816fd4ca9eSMatthias Ringwald     sink_active = 1;
182dfa32746SMatthias Ringwald }
183dfa32746SMatthias Ringwald 
1840402264cSMatthias Ringwald static void btstack_audio_embedded_source_start_stream(void){
185fb90eb3fSMatthias Ringwald     // just started, no data ready
186fb90eb3fSMatthias Ringwald     input_buffer_ready = 0;
187fb90eb3fSMatthias Ringwald 
188fb90eb3fSMatthias Ringwald     // start recording
189fb90eb3fSMatthias Ringwald     hal_audio_source_start();
190fb90eb3fSMatthias Ringwald 
191fb90eb3fSMatthias Ringwald     // start timer
192fb90eb3fSMatthias Ringwald     btstack_run_loop_set_timer_handler(&driver_timer_source, &driver_timer_handler_source);
193fb90eb3fSMatthias Ringwald     btstack_run_loop_set_timer(&driver_timer_source, DRIVER_POLL_INTERVAL_MS);
194fb90eb3fSMatthias Ringwald     btstack_run_loop_add_timer(&driver_timer_source);
1956fd4ca9eSMatthias Ringwald 
1966fd4ca9eSMatthias Ringwald     // state
1976fd4ca9eSMatthias Ringwald     source_active = 1;
1986fd4ca9eSMatthias Ringwald }
1996fd4ca9eSMatthias Ringwald 
2006fd4ca9eSMatthias Ringwald static void btstack_audio_embedded_sink_stop_stream(void){
2016fd4ca9eSMatthias Ringwald     // stop stream
2026fd4ca9eSMatthias Ringwald     hal_audio_sink_stop();
2036fd4ca9eSMatthias Ringwald     // stop timer
2046fd4ca9eSMatthias Ringwald     btstack_run_loop_remove_timer(&driver_timer_sink);
2056fd4ca9eSMatthias Ringwald     // state
2066fd4ca9eSMatthias Ringwald     sink_active = 0;
2076fd4ca9eSMatthias Ringwald }
2086fd4ca9eSMatthias Ringwald 
2096fd4ca9eSMatthias Ringwald static void btstack_audio_embedded_source_stop_stream(void){
2106fd4ca9eSMatthias Ringwald     // stop stream
2116fd4ca9eSMatthias Ringwald     hal_audio_source_stop();
2126fd4ca9eSMatthias Ringwald     // stop timer
2136fd4ca9eSMatthias Ringwald     btstack_run_loop_remove_timer(&driver_timer_source);
2146fd4ca9eSMatthias Ringwald     // state
2156fd4ca9eSMatthias Ringwald     source_active = 0;
2160402264cSMatthias Ringwald }
2170402264cSMatthias Ringwald 
2180402264cSMatthias Ringwald static void btstack_audio_embedded_sink_close(void){
2196fd4ca9eSMatthias Ringwald     // stop stream if needed
2206fd4ca9eSMatthias Ringwald     if (sink_active){
2216fd4ca9eSMatthias Ringwald         btstack_audio_embedded_sink_stop_stream();
2226fd4ca9eSMatthias Ringwald     }
223dfa32746SMatthias Ringwald     // close HAL
224ff0081eeSMatthias Ringwald     hal_audio_sink_close();
225dfa32746SMatthias Ringwald }
226dfa32746SMatthias Ringwald 
2270402264cSMatthias Ringwald static void btstack_audio_embedded_source_close(void){
2286fd4ca9eSMatthias Ringwald     // stop stream if needed
2296fd4ca9eSMatthias Ringwald     if (source_active){
2306fd4ca9eSMatthias Ringwald         btstack_audio_embedded_source_stop_stream();
2316fd4ca9eSMatthias Ringwald     }
232fb90eb3fSMatthias Ringwald     // close HAL
233fb90eb3fSMatthias Ringwald     hal_audio_source_close();
2340402264cSMatthias Ringwald }
2350402264cSMatthias Ringwald 
2360402264cSMatthias Ringwald static const btstack_audio_sink_t btstack_audio_embedded_sink = {
2370402264cSMatthias Ringwald     /* int (*init)(..);*/                                       &btstack_audio_embedded_sink_init,
2381b7f8fa1SMatthias Ringwald     /* void (*set_volume)(uint8_t volume); */                   &btstack_audio_embedded_sink_set_volume,
2390402264cSMatthias Ringwald     /* void (*start_stream(void));*/                            &btstack_audio_embedded_sink_start_stream,
2406fd4ca9eSMatthias Ringwald     /* void (*stop_stream)(void)  */                            &btstack_audio_embedded_sink_stop_stream,
2410402264cSMatthias Ringwald     /* void (*close)(void); */                                  &btstack_audio_embedded_sink_close
242dfa32746SMatthias Ringwald };
243dfa32746SMatthias Ringwald 
2440402264cSMatthias Ringwald static const btstack_audio_source_t btstack_audio_embedded_source = {
2450402264cSMatthias Ringwald     /* int (*init)(..);*/                                       &btstack_audio_embedded_source_init,
2461b7f8fa1SMatthias Ringwald     /* void (*set_gain)(uint8_t gain); */                       &btstack_audio_embedded_source_set_gain,
2470402264cSMatthias Ringwald     /* void (*start_stream(void));*/                            &btstack_audio_embedded_source_start_stream,
2486fd4ca9eSMatthias Ringwald     /* void (*stop_stream)(void)  */                            &btstack_audio_embedded_source_stop_stream,
2490402264cSMatthias Ringwald     /* void (*close)(void); */                                  &btstack_audio_embedded_source_close
2500402264cSMatthias Ringwald };
2510402264cSMatthias Ringwald 
2520402264cSMatthias Ringwald const btstack_audio_sink_t * btstack_audio_embedded_sink_get_instance(void){
2530402264cSMatthias Ringwald     return &btstack_audio_embedded_sink;
2540402264cSMatthias Ringwald }
2550402264cSMatthias Ringwald 
2560402264cSMatthias Ringwald const btstack_audio_source_t * btstack_audio_embedded_source_get_instance(void){
2570402264cSMatthias Ringwald     return &btstack_audio_embedded_source;
258dfa32746SMatthias Ringwald }
259dfa32746SMatthias Ringwald 
260dfa32746SMatthias Ringwald #endif
261