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