xref: /btstack/example/a2dp_source_demo.c (revision 44547c84faa6a554e2fd86f4522c503cd5d96476)
1 /*
2  * Copyright (C) 2016 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  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "a2dp_source_demo.c"
39 
40 /*
41  * a2dp_source_demo.c
42  */
43 
44 // *****************************************************************************
45 /* EXAMPLE_START(a2dp_source_demo): Serve audio stream and handle remote playback control and queries.
46  *
47  * @text This  A2DP Source example demonstrates how to send an audio data stream
48  * to a remote A2DP Sink device and how to switch between two audio data sources.
49  * In addition, the AVRCP Target is used to answer queries on currently played media,
50  * as well as to handle remote playback control, i.e. play, stop, repeat, etc.
51  *
52  * @test To test with a remote device, e.g. a Bluetooth speaker,
53  * set the device_addr_string to the Bluetooth address of your
54  * remote device in the code, and use the UI to connect and start playback.
55  * Tap SPACE on the console to show the available commands.
56  */
57 // *****************************************************************************
58 
59 
60 #include <stdint.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 
65 #include "btstack.h"
66 #include "hxcmod.h"
67 #include "mods/mod.h"
68 
69 // logarithmic volume reduction, samples are divided by 2^x
70 // #define VOLUME_REDUCTION 3
71 // #undef  HAVE_BTSTACK_STDIN
72 
73 //#define AVRCP_BROWSING_ENABLED
74 
75 #define NUM_CHANNELS                2
76 #define BYTES_PER_AUDIO_SAMPLE      (2*NUM_CHANNELS)
77 #define AUDIO_TIMEOUT_MS            10
78 #define TABLE_SIZE_441HZ            100
79 
80 #define SBC_STORAGE_SIZE 1030
81 
82 typedef enum {
83     STREAM_SINE = 0,
84     STREAM_MOD,
85     STREAM_PTS_TEST
86 } stream_data_source_t;
87 
88 typedef struct {
89     uint16_t a2dp_cid;
90     uint8_t  local_seid;
91     uint8_t  stream_opened;
92     uint16_t avrcp_cid;
93 
94     uint32_t time_audio_data_sent; // ms
95     uint32_t acc_num_missed_samples;
96     uint32_t samples_ready;
97     btstack_timer_source_t audio_timer;
98     uint8_t  streaming;
99     int      max_media_payload_size;
100 
101     uint8_t  sbc_storage[SBC_STORAGE_SIZE];
102     uint16_t sbc_storage_count;
103     uint8_t  sbc_ready_to_send;
104 } a2dp_media_sending_context_t;
105 
106 static  uint8_t media_sbc_codec_capabilities[] = {
107     (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
108     0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
109     2, 53
110 };
111 
112 // input signal: pre-computed int16 sine wave, 44100 Hz at 441 Hz
113 static const int16_t sine_int16_44100[] = {
114      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
115  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
116  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
117  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
118  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
119      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
120 -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
121 -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
122 -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
123 -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
124 };
125 
126 static const int num_samples_sine_int16_44100 = sizeof(sine_int16_44100) / 2;
127 
128 // input signal: pre-computed int16 sine wave, 48000 Hz at 441 Hz
129 static const int16_t sine_int16_48000[] = {
130      0,    1905,    3804,    5690,    7557,    9398,   11207,   12978,   14706,   16383,
131  18006,   19567,   21062,   22486,   23834,   25101,   26283,   27376,   28377,   29282,
132  30087,   30791,   31390,   31884,   32269,   32545,   32712,   32767,   32712,   32545,
133  32269,   31884,   31390,   30791,   30087,   29282,   28377,   27376,   26283,   25101,
134  23834,   22486,   21062,   19567,   18006,   16383,   14706,   12978,   11207,    9398,
135   7557,    5690,    3804,    1905,       0,   -1905,   -3804,   -5690,   -7557,   -9398,
136 -11207,  -12978,  -14706,  -16384,  -18006,  -19567,  -21062,  -22486,  -23834,  -25101,
137 -26283,  -27376,  -28377,  -29282,  -30087,  -30791,  -31390,  -31884,  -32269,  -32545,
138 -32712,  -32767,  -32712,  -32545,  -32269,  -31884,  -31390,  -30791,  -30087,  -29282,
139 -28377,  -27376,  -26283,  -25101,  -23834,  -22486,  -21062,  -19567,  -18006,  -16384,
140 -14706,  -12978,  -11207,   -9398,   -7557,   -5690,   -3804,   -1905,  };
141 
142 static const int num_samples_sine_int16_48000 = sizeof(sine_int16_48000) / 2;
143 
144 typedef struct {
145     int reconfigure;
146     int num_channels;
147     int sampling_frequency;
148     int channel_mode;
149     int block_length;
150     int subbands;
151     int allocation_method;
152     int min_bitpool_value;
153     int max_bitpool_value;
154     int frames_per_buffer;
155 } avdtp_media_codec_configuration_sbc_t;
156 
157 static btstack_packet_callback_registration_t hci_event_callback_registration;
158 
159 // pts:             static const char * device_addr_string = "00:1B:DC:08:0A:A5";
160 // pts:             static const char * device_addr_string = "00:1B:DC:08:E2:72";
161 // mac 2013:        static const char * device_addr_string = "84:38:35:65:d1:15";
162 // phone 2013:      static const char * device_addr_string = "D8:BB:2C:DF:F0:F2";
163 // Minijambox:
164 static const char * device_addr_string = "00:21:3C:AC:F7:38";
165 // Philips SHB9100: static const char * device_addr_string = "00:22:37:05:FD:E8";
166 // RT-B6:           static const char * device_addr_string = "00:75:58:FF:C9:7D";
167 // BT dongle:       static const char * device_addr_string = "00:1A:7D:DA:71:0A";
168 // Sony MDR-ZX330BT static const char * device_addr_string = "00:18:09:28:50:18";
169 // Panda (BM6)      static const char * device_addr_string = "4F:3F:66:52:8B:E0";
170 
171 static bd_addr_t device_addr;
172 static uint8_t sdp_a2dp_source_service_buffer[150];
173 static uint8_t sdp_avrcp_target_service_buffer[200];
174 static uint8_t sdp_avrcp_controller_service_buffer[200];
175 
176 static avdtp_media_codec_configuration_sbc_t sbc_configuration;
177 static btstack_sbc_encoder_state_t sbc_encoder_state;
178 
179 static uint8_t media_sbc_codec_configuration[4];
180 static a2dp_media_sending_context_t media_tracker;
181 
182 static stream_data_source_t data_source;
183 
184 static int sine_phase;
185 static int sample_rate = 44100;
186 
187 static int hxcmod_initialized;
188 static modcontext mod_context;
189 static tracker_buffer_state trkbuf;
190 
191 static uint16_t avrcp_controller_cid = 0;
192 
193 /* AVRCP Target context START */
194 static const uint8_t subunit_info[] = {
195     0,0,0,0,
196     1,1,1,1,
197     2,2,2,2,
198     3,3,3,3,
199     4,4,4,4,
200     5,5,5,5,
201     6,6,6,6,
202     7,7,7,7
203 };
204 
205 static uint32_t company_id = 0x112233;
206 static uint8_t companies_num = 1;
207 static uint8_t companies[] = {
208     0x00, 0x19, 0x58 //BT SIG registered CompanyID
209 };
210 
211 static uint8_t events_num = 13;
212 static uint8_t events[] = {
213     AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED,
214     AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED,
215     AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END,
216     AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START,
217     AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED,
218     AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED,
219     AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED,
220     AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED,
221     AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED,
222     AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED,
223     AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED,
224     AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED,
225     AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED
226 };
227 
228 typedef struct {
229     uint8_t track_id[8];
230     uint32_t song_length_ms;
231     avrcp_playback_status_t status;
232     uint32_t song_position_ms; // 0xFFFFFFFF if not supported
233 } avrcp_play_status_info_t;
234 
235 // python -c "print('a'*512)"
236 static const char title[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
237 
238 avrcp_track_t tracks[] = {
239     {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 1, "Sine", "Generated", "A2DP Source Demo", "monotone", 12345},
240     {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 2, "Nao-deceased", "Decease", "A2DP Source Demo", "vivid", 12345},
241     {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, 3, (char *)title, "Decease", "A2DP Source Demo", "vivid", 12345},
242 };
243 int current_track_index;
244 avrcp_play_status_info_t play_info;
245 
246 /* AVRCP Target context END */
247 
248 /* @section Main Application Setup
249  *
250  * @text The Listing MainConfiguration shows how to setup AD2P Source and AVRCP Target services.
251  */
252 
253 /* LISTING_START(MainConfiguration): Setup Audio Source and AVRCP Target services */
254 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size);
255 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
256 static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
257 #ifdef HAVE_BTSTACK_STDIN
258 static void stdin_process(char cmd);
259 #endif
260 
261 static void a2dp_demo_reconfigure_sample_rate(int new_sample_rate){
262     if (!hxcmod_initialized){
263         hxcmod_initialized = hxcmod_init(&mod_context);
264         if (!hxcmod_initialized) {
265             printf("could not initialize hxcmod\n");
266             return;
267         }
268     }
269     sample_rate = new_sample_rate;
270     media_tracker.sbc_storage_count = 0;
271     media_tracker.samples_ready = 0;
272     hxcmod_unload(&mod_context);
273     hxcmod_setcfg(&mod_context, sample_rate, 16, 1, 1, 1);
274     hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
275 }
276 
277 static int a2dp_source_and_avrcp_services_init(void){
278 
279     l2cap_init();
280     // Initialize  A2DP Source.
281     a2dp_source_init();
282     a2dp_source_register_packet_handler(&a2dp_source_packet_handler);
283 
284     // Create stream endpoint.
285     avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_source_create_stream_endpoint(AVDTP_AUDIO, AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities), media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration));
286     if (!local_stream_endpoint){
287         printf("A2DP Source: not enough memory to create local stream endpoint\n");
288         return 1;
289     }
290     media_tracker.local_seid = avdtp_local_seid(local_stream_endpoint);
291     avdtp_source_register_delay_reporting_category(media_tracker.local_seid);
292 
293     // Initialize AVRCP Target.
294     avrcp_target_init();
295     avrcp_target_register_packet_handler(&avrcp_target_packet_handler);
296     // Initialize AVRCP Controller
297     avrcp_controller_init();
298     avrcp_controller_register_packet_handler(&avrcp_controller_packet_handler);
299 
300     // Initialize SDP,
301     sdp_init();
302 
303     // Create  A2DP Source service record and register it with SDP.
304     memset(sdp_a2dp_source_service_buffer, 0, sizeof(sdp_a2dp_source_service_buffer));
305     a2dp_source_create_sdp_record(sdp_a2dp_source_service_buffer, 0x10002, 1, NULL, NULL);
306     sdp_register_service(sdp_a2dp_source_service_buffer);
307 
308     // Create AVRCP target service record and register it with SDP.
309     memset(sdp_avrcp_target_service_buffer, 0, sizeof(sdp_avrcp_target_service_buffer));
310     uint16_t supported_features = (1 << AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER);
311 #ifdef AVRCP_BROWSING_ENABLED
312     supported_features |= (1 << AVRCP_TARGET_SUPPORTED_FEATURE_BROWSING);
313 #endif
314     avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer, 0x10001, supported_features, NULL, NULL);
315     sdp_register_service(sdp_avrcp_target_service_buffer);
316 
317     // setup AVRCP Controller
318     memset(sdp_avrcp_controller_service_buffer, 0, sizeof(sdp_avrcp_controller_service_buffer));
319     uint16_t controller_supported_features = (1 << AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_MONITOR_OR_AMPLIFIER);
320     avrcp_controller_create_sdp_record(sdp_avrcp_controller_service_buffer, 0x10002, controller_supported_features, NULL, NULL);
321     sdp_register_service(sdp_avrcp_controller_service_buffer);
322 
323     // Set local name with a template Bluetooth address, that will be automatically
324     // replaced with a actual address once it is available, i.e. when BTstack boots
325     // up and starts talking to a Bluetooth module.
326     gap_set_local_name("A2DP Source 00:00:00:00:00:00");
327     gap_discoverable_control(1);
328     gap_set_class_of_device(0x200408);
329 
330     // Register for HCI events.
331     hci_event_callback_registration.callback = &a2dp_source_packet_handler;
332     hci_add_event_handler(&hci_event_callback_registration);
333 
334     a2dp_demo_reconfigure_sample_rate(sample_rate);
335 
336     // Parse human readable Bluetooth address.
337     sscanf_bd_addr(device_addr_string, device_addr);
338 
339 #ifdef HAVE_BTSTACK_STDIN
340     btstack_stdin_setup(stdin_process);
341 #endif
342     return 0;
343 }
344 /* LISTING_END */
345 
346 static void a2dp_demo_send_media_packet(void){
347     int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length();
348     int bytes_in_storage = media_tracker.sbc_storage_count;
349     uint8_t num_frames = bytes_in_storage / num_bytes_in_frame;
350     a2dp_source_stream_send_media_payload(media_tracker.a2dp_cid, media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0);
351     media_tracker.sbc_storage_count = 0;
352     media_tracker.sbc_ready_to_send = 0;
353 }
354 
355 static void produce_sine_audio(int16_t * pcm_buffer, int num_samples_to_write){
356     int count;
357     for (count = 0; count < num_samples_to_write ; count++){
358         switch (sample_rate){
359             case 44100:
360                 pcm_buffer[count * 2]     = sine_int16_44100[sine_phase];
361                 pcm_buffer[count * 2 + 1] = sine_int16_44100[sine_phase];
362                 sine_phase++;
363                 if (sine_phase >= num_samples_sine_int16_44100){
364                     sine_phase -= num_samples_sine_int16_44100;
365                 }
366                 break;
367             case 48000:
368                 pcm_buffer[count * 2]     = sine_int16_48000[sine_phase];
369                 pcm_buffer[count * 2 + 1] = sine_int16_48000[sine_phase];
370                 sine_phase++;
371                 if (sine_phase >= num_samples_sine_int16_48000){
372                     sine_phase -= num_samples_sine_int16_48000;
373                 }
374                 break;
375             default:
376                 break;
377         }
378 
379 
380     }
381 }
382 
383 static void produce_mod_audio(int16_t * pcm_buffer, int num_samples_to_write){
384     hxcmod_fillbuffer(&mod_context, (unsigned short *) &pcm_buffer[0], num_samples_to_write, &trkbuf);
385 }
386 
387 static void produce_audio(int16_t * pcm_buffer, int num_samples){
388     switch (data_source){
389         case STREAM_SINE:
390             produce_sine_audio(pcm_buffer, num_samples);
391             break;
392         case STREAM_MOD:
393             produce_mod_audio(pcm_buffer, num_samples);
394             break;
395         default:
396             break;
397     }
398 #ifdef VOLUME_REDUCTION
399     int i;
400     for (i=0;i<num_samples*2;i++){
401         if (pcm_buffer[i] > 0){
402             pcm_buffer[i] =     pcm_buffer[i]  >> VOLUME_REDUCTION;
403         } else {
404             pcm_buffer[i] = -((-pcm_buffer[i]) >> VOLUME_REDUCTION);
405         }
406     }
407 #endif
408 }
409 
410 static int a2dp_demo_fill_sbc_audio_buffer(a2dp_media_sending_context_t * context){
411     // perform sbc encodin
412     int total_num_bytes_read = 0;
413     unsigned int num_audio_samples_per_sbc_buffer = btstack_sbc_encoder_num_audio_frames();
414     while (context->samples_ready >= num_audio_samples_per_sbc_buffer
415         && (context->max_media_payload_size - context->sbc_storage_count) >= btstack_sbc_encoder_sbc_buffer_length()){
416 
417         int16_t pcm_frame[256*NUM_CHANNELS];
418 
419         produce_audio(pcm_frame, num_audio_samples_per_sbc_buffer);
420         btstack_sbc_encoder_process_data(pcm_frame);
421 
422         uint16_t sbc_frame_size = btstack_sbc_encoder_sbc_buffer_length();
423         uint8_t * sbc_frame = btstack_sbc_encoder_sbc_buffer();
424 
425         total_num_bytes_read += num_audio_samples_per_sbc_buffer;
426         memcpy(&context->sbc_storage[context->sbc_storage_count], sbc_frame, sbc_frame_size);
427         context->sbc_storage_count += sbc_frame_size;
428         context->samples_ready -= num_audio_samples_per_sbc_buffer;
429     }
430     return total_num_bytes_read;
431 }
432 
433 static void a2dp_demo_audio_timeout_handler(btstack_timer_source_t * timer){
434     a2dp_media_sending_context_t * context = (a2dp_media_sending_context_t *) btstack_run_loop_get_timer_context(timer);
435     btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS);
436     btstack_run_loop_add_timer(&context->audio_timer);
437     uint32_t now = btstack_run_loop_get_time_ms();
438 
439     uint32_t update_period_ms = AUDIO_TIMEOUT_MS;
440     if (context->time_audio_data_sent > 0){
441         update_period_ms = now - context->time_audio_data_sent;
442     }
443 
444     uint32_t num_samples = (update_period_ms * sample_rate) / 1000;
445     context->acc_num_missed_samples += (update_period_ms * sample_rate) % 1000;
446 
447     while (context->acc_num_missed_samples >= 1000){
448         num_samples++;
449         context->acc_num_missed_samples -= 1000;
450     }
451     context->time_audio_data_sent = now;
452     context->samples_ready += num_samples;
453 
454     if (context->sbc_ready_to_send) return;
455 
456     a2dp_demo_fill_sbc_audio_buffer(context);
457 
458     if ((context->sbc_storage_count + btstack_sbc_encoder_sbc_buffer_length()) > context->max_media_payload_size){
459         // schedule sending
460         context->sbc_ready_to_send = 1;
461         a2dp_source_stream_endpoint_request_can_send_now(context->a2dp_cid, context->local_seid);
462     }
463 }
464 
465 static void a2dp_demo_timer_start(a2dp_media_sending_context_t * context){
466     context->max_media_payload_size = btstack_min(a2dp_max_media_payload_size(context->a2dp_cid, context->local_seid), SBC_STORAGE_SIZE);
467     context->sbc_storage_count = 0;
468     context->sbc_ready_to_send = 0;
469     context->streaming = 1;
470     btstack_run_loop_remove_timer(&context->audio_timer);
471     btstack_run_loop_set_timer_handler(&context->audio_timer, a2dp_demo_audio_timeout_handler);
472     btstack_run_loop_set_timer_context(&context->audio_timer, context);
473     btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS);
474     btstack_run_loop_add_timer(&context->audio_timer);
475 }
476 
477 static void a2dp_demo_timer_stop(a2dp_media_sending_context_t * context){
478     context->time_audio_data_sent = 0;
479     context->acc_num_missed_samples = 0;
480     context->samples_ready = 0;
481     context->streaming = 1;
482     context->sbc_storage_count = 0;
483     context->sbc_ready_to_send = 0;
484     btstack_run_loop_remove_timer(&context->audio_timer);
485 }
486 
487 static void dump_sbc_configuration(avdtp_media_codec_configuration_sbc_t * configuration){
488     printf("Received media codec configuration:\n");
489     printf("    - num_channels: %d\n", configuration->num_channels);
490     printf("    - sampling_frequency: %d\n", configuration->sampling_frequency);
491     printf("    - channel_mode: %d\n", configuration->channel_mode);
492     printf("    - block_length: %d\n", configuration->block_length);
493     printf("    - subbands: %d\n", configuration->subbands);
494     printf("    - allocation_method: %d\n", configuration->allocation_method);
495     printf("    - bitpool_value [%d, %d] \n", configuration->min_bitpool_value, configuration->max_bitpool_value);
496 }
497 
498 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
499     UNUSED(channel);
500     UNUSED(size);
501     uint8_t status;
502     uint8_t local_seid;
503     bd_addr_t address;
504     uint16_t cid;
505 
506     if (packet_type != HCI_EVENT_PACKET) return;
507 
508 #ifndef HAVE_BTSTACK_STDIN
509     if (hci_event_packet_get_type(packet) == BTSTACK_EVENT_STATE){
510         if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
511         printf("Create A2DP Source connection to addr %s.\n", bd_addr_to_str(device_addr));
512         status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
513         if (status != ERROR_CODE_SUCCESS){
514             printf("Could not perform command, status 0x%2x\n", status);
515         }
516         return;
517     }
518 #endif
519     if (hci_event_packet_get_type(packet) == HCI_EVENT_PIN_CODE_REQUEST) {
520         printf("Pin code request - using '0000'\n");
521         hci_event_pin_code_request_get_bd_addr(packet, address);
522         gap_pin_code_response(address, "0000");
523         return;
524     }
525 
526     if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
527 
528     switch (hci_event_a2dp_meta_get_subevent_code(packet)){
529         case A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED:
530             a2dp_subevent_signaling_connection_established_get_bd_addr(packet, address);
531             cid = a2dp_subevent_signaling_connection_established_get_a2dp_cid(packet);
532             status = a2dp_subevent_signaling_connection_established_get_status(packet);
533 
534             if (status != ERROR_CODE_SUCCESS){
535                 printf("A2DP Source: Connection failed, status 0x%02x, cid 0x%02x, a2dp_cid 0x%02x \n", status, cid, media_tracker.a2dp_cid);
536                 media_tracker.a2dp_cid = 0;
537                 break;
538             }
539             media_tracker.a2dp_cid = cid;
540             printf("A2DP Source: Connected to address %s, a2dp cid 0x%02x.\n", bd_addr_to_str(address), media_tracker.a2dp_cid);
541             break;
542 
543          case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{
544             cid  = avdtp_subevent_signaling_media_codec_sbc_configuration_get_avdtp_cid(packet);
545             if (cid != media_tracker.a2dp_cid) return;
546 
547             sbc_configuration.reconfigure = a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet);
548             sbc_configuration.num_channels = a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet);
549             sbc_configuration.sampling_frequency = a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet);
550             sbc_configuration.channel_mode = a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet);
551             sbc_configuration.block_length = a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet);
552             sbc_configuration.subbands = a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet);
553             sbc_configuration.allocation_method = a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet);
554             sbc_configuration.min_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet);
555             sbc_configuration.max_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);
556             sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length;
557             printf("A2DP Source: Received SBC codec configuration, sampling frequency %u.\n", sbc_configuration.sampling_frequency);
558 
559             // Adapt Bluetooth spec definition to SBC Encoder expected input
560             sbc_configuration.allocation_method -= 1;
561             sbc_configuration.num_channels = 2;
562             switch (sbc_configuration.channel_mode){
563                 case AVDTP_SBC_JOINT_STEREO:
564                     sbc_configuration.channel_mode = 3;
565                     break;
566                 case AVDTP_SBC_STEREO:
567                     sbc_configuration.channel_mode = 2;
568                     break;
569                 case AVDTP_SBC_DUAL_CHANNEL:
570                     sbc_configuration.channel_mode = 1;
571                     break;
572                 case AVDTP_SBC_MONO:
573                     sbc_configuration.channel_mode = 0;
574                     sbc_configuration.num_channels = 1;
575                     break;
576             }
577             dump_sbc_configuration(&sbc_configuration);
578 
579             btstack_sbc_encoder_init(&sbc_encoder_state, SBC_MODE_STANDARD,
580                 sbc_configuration.block_length, sbc_configuration.subbands,
581                 sbc_configuration.allocation_method, sbc_configuration.sampling_frequency,
582                 sbc_configuration.max_bitpool_value,
583                 sbc_configuration.channel_mode);
584             break;
585         }
586 
587         case A2DP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY:
588             printf("A2DP Source: remote supports delay report\n");
589             break;
590         case A2DP_SUBEVENT_SIGNALING_CAPABILITIES_DONE:
591             printf("A2DP Source: All capabilities reported\n");
592             break;
593 
594         case A2DP_SUBEVENT_SIGNALING_DELAY_REPORT:
595             printf("A2DP Source: Received delay report of %d.%0d ms, local seid %d\n",
596                 avdtp_subevent_signaling_delay_report_get_delay_100us(packet)/10, avdtp_subevent_signaling_delay_report_get_delay_100us(packet)%10,
597                 avdtp_subevent_signaling_delay_report_get_local_seid(packet));
598             break;
599 
600         case A2DP_SUBEVENT_STREAM_ESTABLISHED:
601             a2dp_subevent_stream_established_get_bd_addr(packet, address);
602             status = a2dp_subevent_stream_established_get_status(packet);
603             if (status){
604                 printf("A2DP Source: Stream failed, status 0x%02x.\n", status);
605                 break;
606             }
607             local_seid = a2dp_subevent_stream_established_get_local_seid(packet);
608             if (local_seid != media_tracker.local_seid){
609                 printf("A2DP Source: Stream failed, wrong local seid %d, expected %d.\n", local_seid, media_tracker.local_seid);
610                 break;
611             }
612             printf("A2DP Source: Stream established, address %s, a2dp cid 0x%02x, local seid %d, remote seid %d.\n", bd_addr_to_str(address),
613                 media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet));
614             media_tracker.stream_opened = 1;
615             data_source = STREAM_MOD;
616             status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
617             break;
618 
619         case A2DP_SUBEVENT_STREAM_RECONFIGURED:
620             status = a2dp_subevent_stream_reconfigured_get_status(packet);
621             printf("A2DP Source: Reconfigured, status 0x%02x\n", status);
622             break;
623 
624         case A2DP_SUBEVENT_STREAM_STARTED:
625             play_info.status = AVRCP_PLAYBACK_STATUS_PLAYING;
626             if (media_tracker.avrcp_cid){
627                 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t));
628                 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PLAYING);
629             }
630             a2dp_demo_timer_start(&media_tracker);
631             printf("A2DP Source: Stream started.\n");
632             break;
633 
634         case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:
635             a2dp_demo_send_media_packet();
636             break;
637 
638         case A2DP_SUBEVENT_STREAM_SUSPENDED:
639             play_info.status = AVRCP_PLAYBACK_STATUS_PAUSED;
640             if (media_tracker.avrcp_cid){
641                 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_PAUSED);
642             }
643             printf("A2DP Source: Stream paused.\n");
644             a2dp_demo_timer_stop(&media_tracker);
645             break;
646 
647         case A2DP_SUBEVENT_STREAM_RELEASED:
648             play_info.status = AVRCP_PLAYBACK_STATUS_STOPPED;
649             cid = a2dp_subevent_stream_released_get_a2dp_cid(packet);
650             if (cid == media_tracker.a2dp_cid) {
651                 media_tracker.stream_opened = 0;
652                 printf("A2DP Source: Stream released.\n");
653             }
654             if (media_tracker.avrcp_cid){
655                 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t));
656                 avrcp_target_set_playback_status(media_tracker.avrcp_cid, AVRCP_PLAYBACK_STATUS_STOPPED);
657             }
658             a2dp_demo_timer_stop(&media_tracker);
659             break;
660         case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
661             cid = a2dp_subevent_signaling_connection_released_get_a2dp_cid(packet);
662             if (cid == media_tracker.a2dp_cid) {
663                 media_tracker.avrcp_cid = 0;
664                 media_tracker.a2dp_cid = 0;
665                 printf("A2DP Source: Signaling released.\n\n");
666             }
667             break;
668         default:
669             break;
670     }
671 }
672 
673 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
674     UNUSED(channel);
675     UNUSED(size);
676     bd_addr_t event_addr;
677     uint16_t local_cid;
678     uint8_t  status = ERROR_CODE_SUCCESS;
679 
680     if (packet_type != HCI_EVENT_PACKET) return;
681     if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
682 
683     switch (packet[2]){
684         case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
685             local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
686             // if (avrcp_cid != 0 && avrcp_cid != local_cid) {
687             //     printf("AVRCP Target: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", avrcp_cid, local_cid);
688             //     return;
689             // }
690             // if (avrcp_cid != local_cid) break;
691 
692             status = avrcp_subevent_connection_established_get_status(packet);
693             if (status != ERROR_CODE_SUCCESS){
694                 printf("AVRCP Target: Connection failed, status 0x%02x\n", status);
695                 return;
696             }
697             media_tracker.avrcp_cid = local_cid;
698             avrcp_subevent_connection_established_get_bd_addr(packet, event_addr);
699             printf("AVRCP Target: Connected to %s, avrcp_cid 0x%02x\n", bd_addr_to_str(event_addr), local_cid);
700 
701             avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t));
702             avrcp_target_set_unit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, company_id);
703             avrcp_target_set_subunit_info(media_tracker.avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, (uint8_t *)subunit_info, sizeof(subunit_info));
704             return;
705         }
706         case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED:
707             printf("AVRCP Target: new volume %d\n", avrcp_subevent_notification_volume_changed_get_absolute_volume(packet));
708             break;
709         case AVRCP_SUBEVENT_EVENT_IDS_QUERY:
710             status = avrcp_target_supported_events(media_tracker.avrcp_cid, events_num, events, sizeof(events));
711             break;
712         case AVRCP_SUBEVENT_COMPANY_IDS_QUERY:
713             status = avrcp_target_supported_companies(media_tracker.avrcp_cid, companies_num, companies, sizeof(companies));
714             break;
715         case AVRCP_SUBEVENT_PLAY_STATUS_QUERY:
716             status = avrcp_target_play_status(media_tracker.avrcp_cid, play_info.song_length_ms, play_info.song_position_ms, play_info.status);
717             break;
718         // case AVRCP_SUBEVENT_NOW_PLAYING_INFO_QUERY:
719         //     status = avrcp_target_now_playing_info(avrcp_cid);
720         //     break;
721         case AVRCP_SUBEVENT_OPERATION:{
722             avrcp_operation_id_t operation_id = avrcp_subevent_operation_get_operation_id(packet);
723             switch (operation_id){
724                 case AVRCP_OPERATION_ID_PLAY:
725                     printf("AVRCP Target: PLAY\n");
726                     status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
727                     break;
728                 case AVRCP_OPERATION_ID_PAUSE:
729                     printf("AVRCP Target: PAUSE\n");
730                     status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
731                     break;
732                 case AVRCP_OPERATION_ID_STOP:
733                     printf("AVRCP Target: STOP\n");
734                     status = a2dp_source_disconnect(media_tracker.a2dp_cid);
735                     break;
736                 default:
737                     printf("AVRCP Target: operation 0x%2x is not handled\n", operation_id);
738                     return;
739             }
740             break;
741         }
742         case AVRCP_SUBEVENT_CONNECTION_RELEASED:
743             printf("AVRCP Target: Disconnected, avrcp_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
744             media_tracker.avrcp_cid = 0;
745             return;
746         default:
747             break;
748     }
749 
750     if (status != ERROR_CODE_SUCCESS){
751         printf("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status);
752     }
753 }
754 
755 static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
756     UNUSED(channel);
757     UNUSED(size);
758     uint16_t local_cid;
759     uint8_t  status = 0xFF;
760     bd_addr_t adress;
761 
762     if (packet_type != HCI_EVENT_PACKET) return;
763     if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
764     switch (packet[2]){
765         case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
766             local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
767             if (avrcp_controller_cid != 0 && avrcp_controller_cid != local_cid) {
768                 printf("AVRCP Controller: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", avrcp_controller_cid, local_cid);
769                 return;
770             }
771 
772             status = avrcp_subevent_connection_established_get_status(packet);
773             if (status != ERROR_CODE_SUCCESS){
774                 printf("AVRCP Controller: Connection failed: status 0x%02x\n", status);
775                 avrcp_controller_cid = 0;
776                 return;
777             }
778 
779             avrcp_controller_cid = local_cid;
780             avrcp_subevent_connection_established_get_bd_addr(packet, adress);
781             printf("AVRCP Controller: Channel successfully opened: %s, avrcp_controller_cid 0x%02x\n", bd_addr_to_str(adress), avrcp_controller_cid);
782 
783             // automatically enable notifications
784             avrcp_controller_enable_notification(avrcp_controller_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);
785             return;
786         }
787         case AVRCP_SUBEVENT_CONNECTION_RELEASED:
788             printf("AVRCP Controller: Channel released: avrcp_controller_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
789             avrcp_controller_cid = 0;
790             return;
791         default:
792             break;
793     }
794 
795     status = packet[5];
796     if (!avrcp_controller_cid) return;
797 
798     // ignore INTERIM status
799     if (status == AVRCP_CTYPE_RESPONSE_INTERIM) return;
800 
801     switch (packet[2]){
802         case AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED:{
803             int volume_percentage = avrcp_subevent_notification_volume_changed_get_absolute_volume(packet) * 100 / 127;
804             printf("AVRCP Controller: notification absolute volume changed %d %%\n", volume_percentage);
805             return;
806         }
807         default:
808             break;
809     }
810 }
811 
812 #ifdef HAVE_BTSTACK_STDIN
813 static void show_usage(void){
814     bd_addr_t      iut_address;
815     gap_local_bd_addr(iut_address);
816     printf("\n--- Bluetooth  A2DP Source/AVRCP Target Demo %s ---\n", bd_addr_to_str(iut_address));
817     printf("b      - A2DP Source create connection to addr %s\n", device_addr_string);
818     printf("B      - A2DP Source disconnect\n");
819     printf("c      - AVRCP Target create connection to addr %s\n", device_addr_string);
820     printf("C      - AVRCP Target disconnect\n");
821 
822     printf("x      - start streaming sine\n");
823     if (hxcmod_initialized){
824         printf("z      - start streaming '%s'\n", mod_name);
825     }
826     printf("p      - pause streaming\n");
827     printf("w      - reconfigure stream for 44100 Hz\n");
828     printf("e      - reconfigure stream for 48000 Hz\n");
829     printf("t      - volume up\n");
830     printf("T      - volume down\n");
831     printf("v      - absolute volume of 50 percent\n");
832 
833     printf("\n--- Bluetooth  AVRCP Target Commands %s ---\n", bd_addr_to_str(iut_address));
834     printf("---\n");
835 }
836 
837 static void stdin_process(char cmd){
838     uint8_t status = ERROR_CODE_SUCCESS;
839     switch (cmd){
840         case 'b':
841             status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
842             printf("%c - Create A2DP Source connection to addr %s, cid 0x%02x.\n", cmd, bd_addr_to_str(device_addr), media_tracker.a2dp_cid);
843             break;
844         case 'B':
845             printf("%c - A2DP Source Disconnect from cid 0x%2x\n", cmd, media_tracker.a2dp_cid);
846             status = a2dp_source_disconnect(media_tracker.a2dp_cid);
847             break;
848         case 'c':
849             printf("%c - Create AVRCP Target connection to addr %s.\n", cmd, bd_addr_to_str(device_addr));
850             status = avrcp_target_connect(device_addr, &media_tracker.avrcp_cid);
851             break;
852         case 'C':
853             printf("%c - AVRCP Target disconnect\n", cmd);
854             status = avrcp_target_disconnect(media_tracker.avrcp_cid);
855             break;
856 
857         case '\n':
858         case '\r':
859             break;
860 
861         case 't':
862             printf(" - volume up\n");
863             status = avrcp_controller_volume_up(avrcp_controller_cid);
864             break;
865         case 'T':
866             printf(" - volume down\n");
867             status = avrcp_controller_volume_down(avrcp_controller_cid);
868             break;
869         case 'v':
870             printf(" - absolute volume of 50%% (64)\n");
871             status = avrcp_controller_set_absolute_volume(avrcp_controller_cid, 64);
872             break;
873 
874         case 'x':
875             if (media_tracker.avrcp_cid){
876                 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t));
877             }
878             printf("%c - Play sine.\n", cmd);
879             data_source = STREAM_SINE;
880             if (!media_tracker.stream_opened) break;
881             status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
882             break;
883         case 'z':
884             if (media_tracker.avrcp_cid){
885                 avrcp_target_set_now_playing_info(media_tracker.avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t));
886             }
887             printf("%c - Play mod.\n", cmd);
888             data_source = STREAM_MOD;
889             if (!media_tracker.stream_opened) break;
890             status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
891             if (status == ERROR_CODE_SUCCESS){
892                 a2dp_demo_reconfigure_sample_rate(sample_rate);
893             }
894             break;
895 
896         case 'p':
897             if (!media_tracker.stream_opened) break;
898             printf("%c - Pause stream.\n", cmd);
899             status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
900             break;
901 
902         case 'w':
903             if (!media_tracker.stream_opened) break;
904             if (play_info.status == AVRCP_PLAYBACK_STATUS_PLAYING){
905                 printf("Stream cannot be reconfigured while playing, please pause stream first\n");
906                 break;
907             }
908             printf("%c - Reconfigure for %d Hz.\n", cmd, sample_rate);
909             status = a2dp_source_reconfigure_stream_sampling_frequency(media_tracker.a2dp_cid, 44100);
910             if (status == ERROR_CODE_SUCCESS){
911                 a2dp_demo_reconfigure_sample_rate(44100);
912             }
913             break;
914 
915         case 'e':
916             if (!media_tracker.stream_opened) break;
917             if (play_info.status == AVRCP_PLAYBACK_STATUS_PLAYING){
918                 printf("Stream cannot be reconfigured while playing, please pause stream first\n");
919                 break;
920             }
921             printf("%c - Reconfigure for %d Hz.\n", cmd, sample_rate);
922             status = a2dp_source_reconfigure_stream_sampling_frequency(media_tracker.a2dp_cid, 48000);
923             if (status == ERROR_CODE_SUCCESS){
924                 a2dp_demo_reconfigure_sample_rate(48000);
925             }
926             break;
927 
928         default:
929             show_usage();
930             return;
931     }
932     if (status != ERROR_CODE_SUCCESS){
933         printf("Could not perform command \'%c\', status 0x%2x\n", cmd, status);
934     }
935 }
936 #endif
937 
938 
939 int btstack_main(int argc, const char * argv[]);
940 int btstack_main(int argc, const char * argv[]){
941     (void)argc;
942     (void)argv;
943 
944     int err = a2dp_source_and_avrcp_services_init();
945     if (err) return err;
946     // turn on!
947     hci_power_control(HCI_POWER_ON);
948     return 0;
949 }
950 /* EXAMPLE_END */
951