xref: /btstack/example/a2dp_source_demo.c (revision 6c099da017fdc786e6cea93a272d1635a8ab2cf5)
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 #define AVRCP_BROWSING_ENABLED 0
70 
71 #define NUM_CHANNELS                2
72 #define A2DP_SAMPLE_RATE            44100
73 #define BYTES_PER_AUDIO_SAMPLE      (2*NUM_CHANNELS)
74 #define AUDIO_TIMEOUT_MS            10
75 #define TABLE_SIZE_441HZ            100
76 
77 #define SBC_STORAGE_SIZE 1030
78 
79 typedef enum {
80     STREAM_SINE = 0,
81     STREAM_MOD,
82     STREAM_PTS_TEST
83 } stream_data_source_t;
84 
85 typedef struct {
86     uint16_t a2dp_cid;
87     uint8_t  local_seid;
88     uint8_t  connected;
89     uint8_t  stream_opened;
90 
91     uint32_t time_audio_data_sent; // ms
92     uint32_t acc_num_missed_samples;
93     uint32_t samples_ready;
94     btstack_timer_source_t audio_timer;
95     uint8_t  streaming;
96     int      max_media_payload_size;
97 
98     uint8_t  sbc_storage[SBC_STORAGE_SIZE];
99     uint16_t sbc_storage_count;
100     uint8_t  sbc_ready_to_send;
101 } a2dp_media_sending_context_t;
102 
103 static  uint8_t media_sbc_codec_capabilities[] = {
104     (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
105     0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
106     2, 53
107 };
108 
109 static const int16_t sine_int16[] = {
110      0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
111  19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
112  31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
113  31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
114  19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
115      0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
116 -19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
117 -31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
118 -31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
119 -19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
120 };
121 
122 typedef struct {
123     int reconfigure;
124     int num_channels;
125     int sampling_frequency;
126     int channel_mode;
127     int block_length;
128     int subbands;
129     int allocation_method;
130     int min_bitpool_value;
131     int max_bitpool_value;
132     int frames_per_buffer;
133 } avdtp_media_codec_configuration_sbc_t;
134 
135 static btstack_packet_callback_registration_t hci_event_callback_registration;
136 
137 // pts:             static const char * device_addr_string = "00:1B:DC:08:0A:A5";
138 // mac 2013:        static const char * device_addr_string = "84:38:35:65:d1:15";
139 // phone 2013:      static const char * device_addr_string = "D8:BB:2C:DF:F0:F2";
140 // Minijambox:
141 // static const char * device_addr_string = "00:21:3C:AC:F7:38";
142 // Philips SHB9100: static const char * device_addr_string = "00:22:37:05:FD:E8";
143 // RT-B6:           static const char * device_addr_string = "00:75:58:FF:C9:7D";
144 // BT dongle:
145 static const char * device_addr_string = "00:1A:7D:DA:71:0A";
146 // Sony MDR-ZX330BT static const char * device_addr_string = "00:18:09:28:50:18";
147 
148 static bd_addr_t device_addr;
149 static uint8_t sdp_a2dp_source_service_buffer[150];
150 static uint8_t sdp_avrcp_target_service_buffer[200];
151 static avdtp_media_codec_configuration_sbc_t sbc_configuration;
152 static btstack_sbc_encoder_state_t sbc_encoder_state;
153 
154 static uint8_t media_sbc_codec_configuration[4];
155 static a2dp_media_sending_context_t media_tracker;
156 
157 static uint16_t avrcp_cid;
158 static uint8_t  avrcp_connected;
159 
160 static stream_data_source_t data_source;
161 
162 static int sine_phase;
163 
164 static int hxcmod_initialized;
165 static modcontext mod_context;
166 static tracker_buffer_state trkbuf;
167 
168 
169 /* AVRCP Target context START */
170 static const uint8_t subunit_info[] = {
171     0,0,0,0,
172     1,1,1,1,
173     2,2,2,2,
174     3,3,3,3,
175     4,4,4,4,
176     5,5,5,5,
177     6,6,6,6,
178     7,7,7,7
179 };
180 
181 static uint32_t company_id = 0x112233;
182 static uint8_t companies_num = 1;
183 static uint8_t companies[] = {
184     0x00, 0x19, 0x58 //BT SIG registered CompanyID
185 };
186 
187 static uint8_t events_num = 13;
188 static uint8_t events[] = {
189     AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED,
190     AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED,
191     AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END,
192     AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START,
193     AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED,
194     AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED,
195     AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED,
196     AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED,
197     AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED,
198     AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED,
199     AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED,
200     AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED,
201     AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED
202 };
203 
204 typedef struct {
205     uint8_t track_id[8];
206     uint32_t song_length_ms;
207     avrcp_playback_status_t status;
208     uint32_t song_position_ms; // 0xFFFFFFFF if not supported
209 } avrcp_play_status_info_t;
210 
211 // python -c "print('a'*512)"
212 static const char title[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
213 
214 avrcp_track_t tracks[] = {
215     {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 1, "Sine", "Generated", "AVRCP Demo", "monotone", 12345},
216     {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 2, "Nao-deceased", "Decease", "AVRCP Demo", "vivid", 12345},
217     {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, 3, (char *)title, "Decease", "AVRCP Demo", "vivid", 12345},
218 };
219 int current_track_index;
220 avrcp_play_status_info_t play_info;
221 
222 /* AVRCP Target context END */
223 
224 /* @section Main Application Setup
225  *
226  * @text The Listing MainConfiguration shows how to setup AD2P Source and AVRCP Target services.
227  */
228 
229 /* LISTING_START(MainConfiguration): Setup Audio Source and AVRCP Target services */
230 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size);
231 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
232 #ifdef HAVE_BTSTACK_STDIN
233 static void stdin_process(char cmd);
234 #endif
235 
236 static int a2dp_source_and_avrcp_services_init(void){
237     // Register for HCI events.
238     hci_event_callback_registration.callback = &a2dp_source_packet_handler;
239     hci_add_event_handler(&hci_event_callback_registration);
240 
241     l2cap_init();
242     // Initialize  A2DP Source.
243     a2dp_source_init();
244     a2dp_source_register_packet_handler(&a2dp_source_packet_handler);
245 
246     // Create stream endpoint.
247     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));
248     if (!local_stream_endpoint){
249         printf(" A2DP Source demo: not enough memory to create local stream endpoint\n");
250         return 1;
251     }
252     media_tracker.local_seid = avdtp_local_seid(local_stream_endpoint);
253 
254     // Initialize AVRCP Target.
255     avrcp_target_init();
256     avrcp_target_register_packet_handler(&avrcp_target_packet_handler);
257 
258     // Initialize SDP,
259     sdp_init();
260 
261     // Create  A2DP Source service record and register it with SDP.
262     memset(sdp_a2dp_source_service_buffer, 0, sizeof(sdp_a2dp_source_service_buffer));
263     a2dp_source_create_sdp_record(sdp_a2dp_source_service_buffer, 0x10002, 1, NULL, NULL);
264     sdp_register_service(sdp_a2dp_source_service_buffer);
265 
266     // Create AVRCP target service record and register it with SDP.
267     memset(sdp_avrcp_target_service_buffer, 0, sizeof(sdp_avrcp_target_service_buffer));
268     avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer, 0x10001, AVRCP_BROWSING_ENABLED, 1, NULL, NULL);
269     sdp_register_service(sdp_avrcp_target_service_buffer);
270 
271     // Set local name with a template Bluetooth address, that will be automatically
272     // replaced with a actual address once it is available, i.e. when BTstack boots
273     // up and starts talking to a Bluetooth module.
274     gap_set_local_name(" A2DP Source Demo 00:00:00:00:00:00");
275     gap_discoverable_control(1);
276     gap_set_class_of_device(0x200408);
277 
278     hxcmod_initialized = hxcmod_init(&mod_context);
279     if (hxcmod_initialized){
280         hxcmod_setcfg(&mod_context, A2DP_SAMPLE_RATE, 16, 1, 1, 1);
281         hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
282         printf("loaded mod '%s', size %u\n", mod_name, mod_len);
283     }
284 
285     // Parse human readable Bluetooth address.
286     sscanf_bd_addr(device_addr_string, device_addr);
287 
288 #ifdef HAVE_BTSTACK_STDIN
289     btstack_stdin_setup(stdin_process);
290 #endif
291     return 0;
292 }
293 /* LISTING_END */
294 
295 static void a2dp_demo_send_media_packet(void){
296     int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length();
297     int bytes_in_storage = media_tracker.sbc_storage_count;
298     uint8_t num_frames = bytes_in_storage / num_bytes_in_frame;
299     a2dp_source_stream_send_media_payload(media_tracker.a2dp_cid, media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0);
300     media_tracker.sbc_storage_count = 0;
301     media_tracker.sbc_ready_to_send = 0;
302 }
303 
304 static void produce_sine_audio(int16_t * pcm_buffer, int num_samples_to_write){
305     int count;
306     for (count = 0; count < num_samples_to_write ; count++){
307         pcm_buffer[count * 2]     = sine_int16[sine_phase];
308         pcm_buffer[count * 2 + 1] = sine_int16[sine_phase];
309         sine_phase++;
310         if (sine_phase >= TABLE_SIZE_441HZ){
311             sine_phase -= TABLE_SIZE_441HZ;
312         }
313     }
314 }
315 
316 static void produce_mod_audio(int16_t * pcm_buffer, int num_samples_to_write){
317     hxcmod_fillbuffer(&mod_context, (unsigned short *) &pcm_buffer[0], num_samples_to_write, &trkbuf);
318 }
319 
320 static void produce_audio(int16_t * pcm_buffer, int num_samples){
321     switch (data_source){
322         case STREAM_SINE:
323             produce_sine_audio(pcm_buffer, num_samples);
324             break;
325         case STREAM_MOD:
326             produce_mod_audio(pcm_buffer, num_samples);
327             break;
328         default:
329             break;
330     }
331 }
332 
333 static int a2dp_demo_fill_sbc_audio_buffer(a2dp_media_sending_context_t * context){
334     // perform sbc encodin
335     int total_num_bytes_read = 0;
336     unsigned int num_audio_samples_per_sbc_buffer = btstack_sbc_encoder_num_audio_frames();
337     while (context->samples_ready >= num_audio_samples_per_sbc_buffer
338         && (context->max_media_payload_size - context->sbc_storage_count) >= btstack_sbc_encoder_sbc_buffer_length()){
339 
340         int16_t pcm_frame[256*NUM_CHANNELS];
341 
342         produce_audio(pcm_frame, num_audio_samples_per_sbc_buffer);
343         btstack_sbc_encoder_process_data(pcm_frame);
344 
345         uint16_t sbc_frame_size = btstack_sbc_encoder_sbc_buffer_length();
346         uint8_t * sbc_frame = btstack_sbc_encoder_sbc_buffer();
347 
348         total_num_bytes_read += num_audio_samples_per_sbc_buffer;
349         memcpy(&context->sbc_storage[context->sbc_storage_count], sbc_frame, sbc_frame_size);
350         context->sbc_storage_count += sbc_frame_size;
351         context->samples_ready -= num_audio_samples_per_sbc_buffer;
352     }
353     return total_num_bytes_read;
354 }
355 
356 static void a2dp_demo_audio_timeout_handler(btstack_timer_source_t * timer){
357     a2dp_media_sending_context_t * context = (a2dp_media_sending_context_t *) btstack_run_loop_get_timer_context(timer);
358     btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS);
359     btstack_run_loop_add_timer(&context->audio_timer);
360     uint32_t now = btstack_run_loop_get_time_ms();
361 
362     uint32_t update_period_ms = AUDIO_TIMEOUT_MS;
363     if (context->time_audio_data_sent > 0){
364         update_period_ms = now - context->time_audio_data_sent;
365     }
366 
367     uint32_t num_samples = (update_period_ms * A2DP_SAMPLE_RATE) / 1000;
368     context->acc_num_missed_samples += (update_period_ms * A2DP_SAMPLE_RATE) % 1000;
369 
370     while (context->acc_num_missed_samples >= 1000){
371         num_samples++;
372         context->acc_num_missed_samples -= 1000;
373     }
374     context->time_audio_data_sent = now;
375     context->samples_ready += num_samples;
376 
377     if (context->sbc_ready_to_send) return;
378 
379     a2dp_demo_fill_sbc_audio_buffer(context);
380 
381     if ((context->sbc_storage_count + btstack_sbc_encoder_sbc_buffer_length()) > context->max_media_payload_size){
382         // schedule sending
383         context->sbc_ready_to_send = 1;
384         a2dp_source_stream_endpoint_request_can_send_now(context->a2dp_cid, context->local_seid);
385     }
386 }
387 
388 static void a2dp_demo_timer_start(a2dp_media_sending_context_t * context){
389     context->max_media_payload_size = btstack_min(a2dp_max_media_payload_size(context->a2dp_cid, context->local_seid), SBC_STORAGE_SIZE);
390     context->sbc_storage_count = 0;
391     context->sbc_ready_to_send = 0;
392     context->streaming = 1;
393     btstack_run_loop_remove_timer(&context->audio_timer);
394     btstack_run_loop_set_timer_handler(&context->audio_timer, a2dp_demo_audio_timeout_handler);
395     btstack_run_loop_set_timer_context(&context->audio_timer, context);
396     btstack_run_loop_set_timer(&context->audio_timer, AUDIO_TIMEOUT_MS);
397     btstack_run_loop_add_timer(&context->audio_timer);
398 }
399 
400 static void a2dp_demo_timer_stop(a2dp_media_sending_context_t * context){
401     context->time_audio_data_sent = 0;
402     context->acc_num_missed_samples = 0;
403     context->samples_ready = 0;
404     context->streaming = 1;
405     context->sbc_storage_count = 0;
406     context->sbc_ready_to_send = 0;
407     btstack_run_loop_remove_timer(&context->audio_timer);
408 }
409 
410 static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
411     UNUSED(channel);
412     UNUSED(size);
413     uint8_t status;
414     uint8_t local_seid;
415     bd_addr_t address;
416     uint16_t cid;
417 
418     if (packet_type != HCI_EVENT_PACKET) return;
419 
420 #ifndef HAVE_BTSTACK_STDIN
421     if (hci_event_packet_get_type(packet) == BTSTACK_EVENT_STATE){
422         if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
423         printf("Create AVDTP Source connection to addr %s.\n", bd_addr_to_str(device_addr));
424         status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
425         if (status != ERROR_CODE_SUCCESS){
426             printf("Could not perform command, status 0x%2x\n", status);
427         }
428         return;
429     }
430 #endif
431     if (hci_event_packet_get_type(packet) == HCI_EVENT_PIN_CODE_REQUEST) {
432         printf("Pin code request - using '0000'\n");
433         hci_event_pin_code_request_get_bd_addr(packet, address);
434         gap_pin_code_response(address, "0000");
435         return;
436     }
437 
438     if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
439     switch (packet[2]){
440         case A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED:
441             a2dp_subevent_signaling_connection_established_get_bd_addr(packet, address);
442             cid = a2dp_subevent_signaling_connection_established_get_a2dp_cid(packet);
443 
444             if (!media_tracker.a2dp_cid){
445                 media_tracker.a2dp_cid = cid;
446             } else if (cid != media_tracker.a2dp_cid){
447                 printf(" A2DP Source demo: Connection failed, received cid 0x%02x, expected cid 0x%02x\n", cid, media_tracker.a2dp_cid);
448                 break;
449             }
450             printf(" A2DP Source demo: Connected to address %s, a2dp cid 0x%02x.\n", bd_addr_to_str(address), media_tracker.a2dp_cid);
451             break;
452 
453          case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{
454             printf(" A2DP Source demo: Received SBC codec configuration.\n");
455             sbc_configuration.reconfigure = a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet);
456             sbc_configuration.num_channels = a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet);
457             sbc_configuration.sampling_frequency = a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet);
458             sbc_configuration.channel_mode = a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet);
459             sbc_configuration.block_length = a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet);
460             sbc_configuration.subbands = a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet);
461             sbc_configuration.allocation_method = a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet);
462             sbc_configuration.min_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet);
463             sbc_configuration.max_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);
464             sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length;
465 
466             btstack_sbc_encoder_init(&sbc_encoder_state, SBC_MODE_STANDARD,
467                 sbc_configuration.block_length, sbc_configuration.subbands,
468                 sbc_configuration.allocation_method, sbc_configuration.sampling_frequency,
469                 sbc_configuration.max_bitpool_value,
470                 sbc_configuration.channel_mode);
471 
472             // status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
473             // if (status != ERROR_CODE_SUCCESS){
474             //     printf("Could not perform command, status 0x%2x\n", status);
475             // }
476             break;
477         }
478 
479         case A2DP_SUBEVENT_STREAM_ESTABLISHED:
480             a2dp_subevent_stream_established_get_bd_addr(packet, address);
481             status = a2dp_subevent_stream_established_get_status(packet);
482             if (status){
483                 printf(" A2DP Source demo: Stream failed, status 0x%02x.\n", status);
484                 break;
485             }
486             local_seid = a2dp_subevent_stream_established_get_local_seid(packet);
487             if (local_seid != media_tracker.local_seid){
488                 printf(" A2DP Source demo: Stream failed, wrong local seid %d, expected %d.\n", local_seid, media_tracker.local_seid);
489                 break;
490             }
491             printf(" A2DP Source demo: Stream established, address %s, a2dp cid 0x%02x, local seid %d, remote seid %d.\n", bd_addr_to_str(address),
492                 media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet));
493             printf(" A2DP Source demo: Start playing mod, a2dp cid 0x%02x.\n", media_tracker.a2dp_cid);
494             media_tracker.stream_opened = 1;
495             data_source = STREAM_MOD;
496             status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
497             break;
498 
499         case A2DP_SUBEVENT_STREAM_STARTED:
500             play_info.status = AVRCP_PLAYBACK_STATUS_PLAYING;
501             if (avrcp_connected){
502                 avrcp_target_set_now_playing_info(avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t));
503                 avrcp_target_set_playback_status(avrcp_cid, AVRCP_PLAYBACK_STATUS_PLAYING);
504             }
505             a2dp_demo_timer_start(&media_tracker);
506             printf(" A2DP Source demo: Stream started.\n");
507             break;
508 
509         case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:
510             a2dp_demo_send_media_packet();
511             break;
512 
513         case A2DP_SUBEVENT_STREAM_SUSPENDED:
514             play_info.status = AVRCP_PLAYBACK_STATUS_PAUSED;
515             if (avrcp_connected){
516                 avrcp_target_set_playback_status(avrcp_cid, AVRCP_PLAYBACK_STATUS_PAUSED);
517             }
518             printf(" A2DP Source demo: Stream paused.\n");
519             a2dp_demo_timer_stop(&media_tracker);
520             break;
521 
522         case A2DP_SUBEVENT_STREAM_RELEASED:
523             play_info.status = AVRCP_PLAYBACK_STATUS_STOPPED;
524             cid = a2dp_subevent_stream_released_get_a2dp_cid(packet);
525             if (cid == media_tracker.a2dp_cid) {
526                 media_tracker.stream_opened = 0;
527                 printf(" A2DP Source demo: Stream released.\n");
528             }
529             if (avrcp_connected){
530                 avrcp_target_set_now_playing_info(avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t));
531                 avrcp_target_set_playback_status(avrcp_cid, AVRCP_PLAYBACK_STATUS_STOPPED);
532             }
533             a2dp_demo_timer_stop(&media_tracker);
534             break;
535         case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
536             cid = a2dp_subevent_signaling_connection_released_get_a2dp_cid(packet);
537             if (cid == media_tracker.a2dp_cid) {
538                 media_tracker.connected = 0;
539                 media_tracker.a2dp_cid = 0;
540                 printf(" A2DP Source demo: Signaling released.\n\n");
541             }
542             break;
543         default:
544             break;
545     }
546 }
547 
548 static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
549     UNUSED(channel);
550     UNUSED(size);
551     bd_addr_t event_addr;
552     uint16_t local_cid;
553     uint8_t  status = ERROR_CODE_SUCCESS;
554 
555     if (packet_type != HCI_EVENT_PACKET) return;
556     if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
557 
558     switch (packet[2]){
559         case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
560             local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
561             // if (avrcp_cid != 0 && avrcp_cid != local_cid) {
562             //     printf("AVRCP Source demo: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", avrcp_cid, local_cid);
563             //     return;
564             // }
565             // if (avrcp_cid != local_cid) break;
566 
567             status = avrcp_subevent_connection_established_get_status(packet);
568             if (status != ERROR_CODE_SUCCESS){
569                 printf("AVRCP Source demo: Connection failed, status 0x%02x\n", status);
570                 return;
571             }
572             avrcp_connected = 1;
573             avrcp_cid = local_cid;
574             avrcp_subevent_connection_established_get_bd_addr(packet, event_addr);
575             printf("AVRCP Source demo: Connected to %s, avrcp_cid 0x%02x\n", bd_addr_to_str(event_addr), local_cid);
576 
577             avrcp_target_set_now_playing_info(avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t));
578             avrcp_target_set_unit_info(avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, company_id);
579             avrcp_target_set_subunit_info(avrcp_cid, AVRCP_SUBUNIT_TYPE_AUDIO, (uint8_t *)subunit_info, sizeof(subunit_info));
580             return;
581         }
582 
583         case AVRCP_SUBEVENT_EVENT_IDS_QUERY:
584             status = avrcp_target_supported_events(avrcp_cid, events_num, events, sizeof(events));
585             break;
586         case AVRCP_SUBEVENT_COMPANY_IDS_QUERY:
587             status = avrcp_target_supported_companies(avrcp_cid, companies_num, companies, sizeof(companies));
588             break;
589         case AVRCP_SUBEVENT_PLAY_STATUS_QUERY:
590             status = avrcp_target_play_status(avrcp_cid, play_info.song_length_ms, play_info.song_position_ms, play_info.status);
591             break;
592         // case AVRCP_SUBEVENT_NOW_PLAYING_INFO_QUERY:
593         //     status = avrcp_target_now_playing_info(avrcp_cid);
594         //     break;
595         case AVRCP_SUBEVENT_OPERATION:{
596             avrcp_operation_id_t operation_id = avrcp_subevent_operation_get_operation_id(packet);
597             if (!media_tracker.connected) break;
598             switch (operation_id){
599                 case AVRCP_OPERATION_ID_PLAY:
600                     printf("AVRCP Source demo: PLAY\n");
601                     status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
602                     break;
603                 case AVRCP_OPERATION_ID_PAUSE:
604                     printf("AVRCP Source demo: PAUSE\n");
605                     status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
606                     break;
607                 case AVRCP_OPERATION_ID_STOP:
608                     printf("AVRCP Source demo: STOP\n");
609                     status = a2dp_source_disconnect(media_tracker.a2dp_cid);
610                     break;
611                 default:
612                     return;
613             }
614             break;
615         }
616         case AVRCP_SUBEVENT_CONNECTION_RELEASED:
617             printf("AVRCP Source demo: Disconnected, avrcp_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
618             avrcp_cid = 0;
619             avrcp_connected = 0;
620             return;
621         default:
622             break;
623     }
624 
625     if (status != ERROR_CODE_SUCCESS){
626         printf("Responding to event 0x%02x failed with status 0x%02x\n", packet[2], status);
627     }
628 }
629 
630 #ifdef HAVE_BTSTACK_STDIN
631 static void show_usage(void){
632     bd_addr_t      iut_address;
633     gap_local_bd_addr(iut_address);
634     printf("\n--- Bluetooth  A2DP Source/AVRCP Target Demo %s ---\n", bd_addr_to_str(iut_address));
635     printf("b      - AVDTP Source create  connection to addr %s\n", device_addr_string);
636     printf("B      - AVDTP Source disconnect\n");
637     printf("c      - AVRCP Target create connection to addr %s\n", device_addr_string);
638     printf("C      - AVRCP Target disconnect\n");
639     printf("0      - AVRCP reset now playing info\n");
640 
641     printf("x      - start streaming sine\n");
642     if (hxcmod_initialized){
643         printf("z      - start streaming '%s'\n", mod_name);
644     }
645     printf("p      - pause streaming\n");
646 
647     printf("\n--- Bluetooth  AVRCP Target Commands %s ---\n", bd_addr_to_str(iut_address));
648     printf("---\n");
649 }
650 
651 static void stdin_process(char cmd){
652     uint8_t status = ERROR_CODE_SUCCESS;
653     switch (cmd){
654         case 'b':
655             status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
656             printf(" - Create AVDTP Source connection to addr %s, cid 0x%02x.\n", bd_addr_to_str(device_addr), media_tracker.a2dp_cid);
657             break;
658         case 'B':
659             printf(" - AVDTP Source Disconnect from cid 0x%2x\n", media_tracker.a2dp_cid);
660             status = a2dp_source_disconnect(media_tracker.a2dp_cid);
661             break;
662         case 'c':
663             printf(" - Create AVRCP Target connection to addr %s.\n", bd_addr_to_str(device_addr));
664             status = avrcp_target_connect(device_addr, &avrcp_cid);
665             break;
666         case 'C':
667             printf(" - AVRCP Target disconnect\n");
668             status = avrcp_target_disconnect(avrcp_cid);
669             break;
670 
671         case '\n':
672         case '\r':
673             break;
674 
675         case 't':
676             printf("STREAM_PTS_TEST.\n");
677             data_source = STREAM_PTS_TEST;
678             if (avrcp_connected){
679                 avrcp_target_set_now_playing_info(avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t));
680             }
681             if (!media_tracker.stream_opened) break;
682             status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
683             break;
684 
685         case 'x':
686             if (avrcp_connected){
687                 avrcp_target_set_now_playing_info(avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t));
688             }
689             printf("Playing sine.\n");
690             data_source = STREAM_SINE;
691             if (!media_tracker.stream_opened) break;
692             status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
693             break;
694         case 'z':
695             if (avrcp_connected){
696                 avrcp_target_set_now_playing_info(avrcp_cid, &tracks[data_source], sizeof(tracks)/sizeof(avrcp_track_t));
697             }
698             printf("Playing mod.\n");
699             data_source = STREAM_MOD;
700             if (!media_tracker.stream_opened) break;
701             status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
702             break;
703         case 'p':
704             if (!media_tracker.connected) break;
705             printf("Pause stream.\n");
706             status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
707             break;
708         case '0':
709             if (avrcp_connected){
710                 avrcp_target_set_now_playing_info(avrcp_cid, NULL, sizeof(tracks)/sizeof(avrcp_track_t));
711                 printf("Reset now playing info\n");
712             }
713             break;
714         default:
715             show_usage();
716             return;
717     }
718     if (status != ERROR_CODE_SUCCESS){
719         printf("Could not perform command, status 0x%2x\n", status);
720     }
721 }
722 #endif
723 
724 
725 int btstack_main(int argc, const char * argv[]);
726 int btstack_main(int argc, const char * argv[]){
727     (void)argc;
728     (void)argv;
729 
730     int err = a2dp_source_and_avrcp_services_init();
731     if (err) return err;
732     // turn on!
733     hci_power_control(HCI_POWER_ON);
734     return 0;
735 }
736 /* EXAMPLE_END */
737