a2dp_source_demo.c 47 KB

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