avrcp_browsing_client.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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__ "avrcp_browsing_client.c"
  38. /*
  39. * avrcp_browsing_client.c
  40. */
  41. // *****************************************************************************
  42. /* EXAMPLE_START(avrcp_browsing_client): Browse media players and media information on a remote device.
  43. *
  44. * @text This example demonstrates how to use the AVRCP Controller Browsing service to
  45. * browse madia players and media information on a remote AVRCP Source device.
  46. *
  47. * @text To test with a remote device, e.g. a mobile phone,
  48. * pair from the remote device with the demo, then use the UI for browsing. If HAVE_BTSTACK_STDIN is set,
  49. * press SPACE on the console to show the available AVDTP and AVRCP commands.
  50. *
  51. */
  52. // *****************************************************************************
  53. #include <stdint.h>
  54. #include <inttypes.h>
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <string.h>
  58. #include "btstack.h"
  59. #ifdef HAVE_BTSTACK_STDIN
  60. #include "btstack_stdin.h"
  61. #endif
  62. #define AVRCP_BROWSING_ENABLED
  63. #define AVRCP_BROWSING_MAX_PLAYERS 10
  64. #define AVRCP_BROWSING_MAX_FOLDERS 10
  65. #define AVRCP_BROWSING_MAX_FOLDER_NAME_LEN 30
  66. #ifdef HAVE_BTSTACK_STDIN
  67. // mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
  68. // pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
  69. // mac 2013:
  70. // static const char * device_addr_string = "84:38:35:65:d1:15";
  71. // iPhone 5S: static const char * device_addr_string = "54:E4:3A:26:A2:39";
  72. // phone 2013:
  73. // static const char * device_addr_string = "B0:34:95:CB:97:C4";
  74. // iPod
  75. // static const char * device_addr_string = "B0:34:95:CB:97:C4";
  76. // iPhone
  77. static const char * device_addr_string = "6C:72:E7:10:22:EE";
  78. static bd_addr_t device_addr;
  79. #endif
  80. static uint16_t avrcp_cid = 0;
  81. static bool avrcp_connected = false;
  82. static uint16_t browsing_cid = 0;
  83. static uint8_t avrcp_browsing_connected = 0;
  84. static uint8_t sdp_avrcp_browsing_controller_service_buffer[200];
  85. static bool browsing_query_active = false;
  86. static avrcp_media_item_context_t media_item_context;
  87. typedef struct {
  88. uint16_t charset;
  89. uint8_t depth;
  90. uint16_t name_len;
  91. char name[AVRCP_BROWSING_MAX_FOLDER_NAME_LEN];
  92. } avrcp_browsing_root_folder_t;
  93. typedef struct {
  94. uint8_t uid[8];
  95. uint16_t name_len;
  96. char name[AVRCP_BROWSING_MAX_FOLDER_NAME_LEN];
  97. } avrcp_browsing_folders_t;
  98. static uint8_t parent_folder_set = 0;
  99. static uint8_t parent_folder_uid[8];
  100. static char parent_folder_name[AVRCP_BROWSING_MAX_FOLDER_NAME_LEN];
  101. static avrcp_browsing_folders_t folders[AVRCP_BROWSING_MAX_FOLDERS];
  102. static int folder_index = -1;
  103. static uint16_t players[AVRCP_BROWSING_MAX_PLAYERS];
  104. static int player_index = -1;
  105. static uint16_t browsing_uid_counter = 0;
  106. static btstack_packet_callback_registration_t hci_event_callback_registration;
  107. static uint8_t ertm_buffer[10000];
  108. static l2cap_ertm_config_t ertm_config = {
  109. 1, // ertm mandatory
  110. 2, // max transmit, some tests require > 1
  111. 2000,
  112. 12000,
  113. 144, // l2cap ertm mtu
  114. 4,
  115. 4,
  116. 0, // No FCS
  117. };
  118. static inline int next_index(int * index, int max_value){
  119. if ((*index) < max_value){
  120. (*index)++;
  121. } else {
  122. (*index) = 0;
  123. }
  124. return (*index);
  125. }
  126. static int next_folder_index(void){
  127. return next_index(&folder_index, AVRCP_BROWSING_MAX_FOLDERS);
  128. }
  129. static int next_player_index(void){
  130. return next_index(&player_index, AVRCP_BROWSING_MAX_PLAYERS);
  131. }
  132. /* @section Main Application Setup
  133. *
  134. * @text The Listing MainConfiguration shows how to setup AVRCP Controller Browsing service.
  135. * To announce AVRCP Controller Browsing service, you need to create corresponding
  136. * SDP record and register it with the SDP service.
  137. * You'll also need to register several packet handlers:
  138. * - stdin_process callback - used to trigger AVRCP commands, such are get media players, playlists, albums, etc. Requires HAVE_BTSTACK_STDIN.
  139. * - avrcp_browsing_packet_handler - used to receive answers for AVRCP commands.
  140. *
  141. */
  142. /* LISTING_START(MainConfiguration): Setup Audio Sink and AVRCP Controller services */
  143. static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
  144. static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
  145. #ifdef HAVE_BTSTACK_STDIN
  146. static void stdin_process(char cmd);
  147. #endif
  148. int btstack_main(int argc, const char * argv[]);
  149. int btstack_main(int argc, const char * argv[]){
  150. (void)argc;
  151. (void)argv;
  152. // Initialize L2CAP.
  153. l2cap_init();
  154. // Initialize AVRCP service.
  155. avrcp_init();
  156. // Initialize AVRCP Controller & Target Service.
  157. avrcp_controller_init();
  158. avrcp_target_init();
  159. avrcp_register_packet_handler(&avrcp_packet_handler);
  160. avrcp_controller_register_packet_handler(&avrcp_packet_handler);
  161. avrcp_target_register_packet_handler(&avrcp_packet_handler);
  162. // Initialize AVRCP Browsing Service.
  163. avrcp_browsing_init();
  164. avrcp_browsing_controller_init();
  165. avrcp_browsing_target_init();
  166. // Register for HCI events.
  167. avrcp_browsing_controller_register_packet_handler(&avrcp_browsing_packet_handler);
  168. avrcp_browsing_target_register_packet_handler(&avrcp_browsing_packet_handler);
  169. avrcp_browsing_register_packet_handler(&avrcp_browsing_packet_handler);
  170. // Initialize SDP.
  171. sdp_init();
  172. // Create AVRCP service record and register it with SDP.
  173. memset(sdp_avrcp_browsing_controller_service_buffer, 0, sizeof(sdp_avrcp_browsing_controller_service_buffer));
  174. uint16_t supported_features = AVRCP_FEATURE_MASK_CATEGORY_PLAYER_OR_RECORDER;
  175. #ifdef AVRCP_BROWSING_ENABLED
  176. supported_features |= AVRCP_FEATURE_MASK_BROWSING;
  177. #endif
  178. avrcp_controller_create_sdp_record(sdp_avrcp_browsing_controller_service_buffer, 0x10001, supported_features, NULL, NULL);
  179. sdp_register_service(sdp_avrcp_browsing_controller_service_buffer);
  180. // Set local name with a template Bluetooth address, that will be automatically
  181. // replaced with a actual address once it is available, i.e. when BTstack boots
  182. // up and starts talking to a Bluetooth module.
  183. gap_set_local_name("AVRCP Browsing Client 00:00:00:00:00:00");
  184. gap_discoverable_control(1);
  185. gap_set_class_of_device(0x200408);
  186. // Register for HCI events.
  187. hci_event_callback_registration.callback = &avrcp_browsing_packet_handler;
  188. hci_add_event_handler(&hci_event_callback_registration);
  189. #ifdef HAVE_BTSTACK_STDIN
  190. // Parse human readable Bluetooth address.
  191. sscanf_bd_addr(device_addr_string, device_addr);
  192. btstack_stdin_setup(stdin_process);
  193. #endif
  194. printf("Starting BTstack ...\n");
  195. hci_power_control(HCI_POWER_ON);
  196. return 0;
  197. }
  198. /* LISTING_END */
  199. static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
  200. UNUSED(channel);
  201. UNUSED(size);
  202. uint16_t local_cid;
  203. uint8_t status = 0xFF;
  204. bd_addr_t adress;
  205. if (packet_type != HCI_EVENT_PACKET) return;
  206. if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
  207. switch (packet[2]){
  208. case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
  209. local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
  210. status = avrcp_subevent_connection_established_get_status(packet);
  211. if (status != ERROR_CODE_SUCCESS){
  212. printf("AVRCP: Connection failed: status 0x%02x\n", status);
  213. avrcp_cid = 0;
  214. return;
  215. }
  216. avrcp_cid = local_cid;
  217. avrcp_connected = true;
  218. avrcp_subevent_connection_established_get_bd_addr(packet, adress);
  219. printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid);
  220. return;
  221. }
  222. case AVRCP_SUBEVENT_CONNECTION_RELEASED:
  223. printf("AVRCP: Channel released: cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
  224. avrcp_cid = 0;
  225. avrcp_connected = false;
  226. return;
  227. default:
  228. break;
  229. }
  230. }
  231. static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
  232. UNUSED(channel);
  233. int pos;
  234. switch(packet_type){
  235. case AVRCP_BROWSING_DATA_PACKET:
  236. pos = 0;
  237. browsing_query_active = true;
  238. avrcp_browsing_item_type_t data_type = (avrcp_browsing_item_type_t)packet[pos++];
  239. pos += 2; // length
  240. switch (data_type){
  241. case AVRCP_BROWSING_MEDIA_ROOT_FOLDER:{
  242. avrcp_browsing_root_folder_t root_folder;
  243. root_folder.charset = big_endian_read_16(packet, pos);
  244. pos += 2;
  245. root_folder.depth = packet[pos++];
  246. root_folder.name_len = big_endian_read_16(packet, pos);
  247. pos += 2;
  248. memset(root_folder.name, 0, AVRCP_BROWSING_MAX_FOLDER_NAME_LEN);
  249. root_folder.name_len = btstack_min(big_endian_read_16(packet, pos), AVRCP_BROWSING_MAX_FOLDER_NAME_LEN - 1);
  250. memcpy(root_folder.name, packet+pos, root_folder.name_len);
  251. printf("Found root folder: name %s, depth %d \n", (char *)root_folder.name, root_folder.depth);
  252. break;
  253. }
  254. case AVRCP_BROWSING_MEDIA_PLAYER_ITEM:{
  255. printf("Received media player: ");
  256. uint16_t player_id = big_endian_read_16(packet, pos);
  257. pos += 2;
  258. avrcp_browsing_media_player_major_type_t major_type = packet[pos++];
  259. avrcp_browsing_media_player_subtype_t subtype = big_endian_read_32(packet, pos);
  260. pos += 4;
  261. uint8_t status = packet[pos++];
  262. uint8_t feature_bitmask[16];
  263. memcpy(feature_bitmask, packet, 16);
  264. pos += 16;
  265. printf("player ID 0x%04x, major_type %d, subtype %d, status %d\n", player_id, major_type, subtype, status);
  266. players[next_player_index()] = player_id;
  267. break;
  268. }
  269. case AVRCP_BROWSING_FOLDER_ITEM:{
  270. int index = next_folder_index();
  271. // printf("Found folder [%d]: ", index);
  272. memcpy(folders[index].uid, packet+pos, 8);
  273. uint32_t folder_uid_high = big_endian_read_32(packet, pos);
  274. pos += 4;
  275. uint32_t folder_uid_low = big_endian_read_32(packet, pos);
  276. pos += 4;
  277. avrcp_browsing_folder_type_t folder_type = packet[pos++];
  278. uint8_t is_playable = packet[pos++];
  279. uint16_t charset = big_endian_read_16(packet, pos);
  280. pos += 2;
  281. uint16_t displayable_name_length = big_endian_read_16(packet, pos);
  282. pos += 2;
  283. char value[AVRCP_BROWSING_MAX_FOLDER_NAME_LEN];
  284. memset(value, 0, AVRCP_BROWSING_MAX_FOLDER_NAME_LEN);
  285. uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_FOLDER_NAME_LEN - 1);
  286. memcpy(value, packet+pos, value_len);
  287. printf("UID 0x%08" PRIx32 "%08" PRIx32 ", type 0x%02x, is_playable %d, charset 0x%02x, name %s\n",
  288. folder_uid_high, folder_uid_low, folder_type, is_playable, charset, value);
  289. memcpy(folders[index].name, value, value_len);
  290. folders[index].name_len = value_len;
  291. break;
  292. }
  293. case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM:{
  294. printf("Found media: ");
  295. uint32_t media_uid_high = big_endian_read_32(packet, pos);
  296. pos += 4;
  297. uint32_t media_uid_low = big_endian_read_32(packet, pos+4);
  298. pos += 4;
  299. avrcp_browsing_media_type_t media_type = packet[pos++];
  300. uint16_t charset = big_endian_read_16(packet, pos);
  301. pos += 2;
  302. uint16_t displayable_name_length = big_endian_read_16(packet, pos);
  303. pos += 2;
  304. pos += displayable_name_length;
  305. printf("Media UID: 0x%08" PRIx32 "%08" PRIx32 ", media_type 0x%02x, charset 0x%02x, displayable_name_length %d\n", media_uid_high, media_uid_low, media_type, charset, displayable_name_length);
  306. uint8_t num_attributes = packet[pos++];
  307. printf("Num media attributes %d\n", num_attributes);
  308. for (avrcp_media_item_iterator_init(&media_item_context, size-pos, packet+pos); avrcp_media_item_iterator_has_more(&media_item_context); avrcp_media_item_iterator_next(&media_item_context)){
  309. uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context);
  310. uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
  311. uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
  312. const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context);
  313. printf("Attr ID 0x%08" PRIx32 ", charset %d, attr_value_length %d, value %s", attr_id, attr_charset, attr_value_length, attr_value);
  314. }
  315. break;
  316. }
  317. default:
  318. log_error("AVRCP Browsing: unknown browsable item type 0%02x", data_type);
  319. break;
  320. }
  321. break;
  322. case HCI_EVENT_PACKET:
  323. if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
  324. uint16_t local_cid;
  325. uint8_t status = 0xFF;
  326. bd_addr_t address;
  327. if (packet[0] != HCI_EVENT_AVRCP_META) break;
  328. switch (packet[2]){
  329. case AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION:
  330. local_cid = avrcp_subevent_incoming_browsing_connection_get_browsing_cid(packet);
  331. printf("AVRCP Browsing: incoming connection cid 0x%02x\n", local_cid);
  332. if (browsing_cid != 0 && browsing_cid != local_cid) {
  333. printf("AVRCP Browsing: decline incoming connection, expected 0x%02X l2cap cid, received 0x%02X\n", browsing_cid, local_cid);
  334. avrcp_browsing_decline_incoming_connection(browsing_cid);
  335. return;
  336. }
  337. browsing_cid = local_cid;
  338. printf("AVRCP Browsing: configure incoming connection, browsing cid 0x%02x\n", browsing_cid);
  339. avrcp_browsing_configure_incoming_connection(browsing_cid, ertm_buffer, sizeof(ertm_buffer), &ertm_config);
  340. break;
  341. case AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED: {
  342. local_cid = avrcp_subevent_browsing_connection_established_get_browsing_cid(packet);
  343. if (browsing_cid != 0 && browsing_cid != local_cid) {
  344. printf("AVRCP Browsing: connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", browsing_cid, local_cid);
  345. return;
  346. }
  347. status = avrcp_subevent_browsing_connection_established_get_status(packet);
  348. if (status != ERROR_CODE_SUCCESS){
  349. printf("AVRCP Browsing: connection failed: status 0x%02x\n", status);
  350. browsing_cid = 0;
  351. return;
  352. }
  353. browsing_cid = local_cid;
  354. avrcp_browsing_connected = 1;
  355. avrcp_subevent_browsing_connection_established_get_bd_addr(packet, address);
  356. printf("AVRCP Browsing: connected, browsing cid 0x%02x\n", browsing_cid);
  357. return;
  358. }
  359. case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED:
  360. printf("AVRCP Browsing: disconnected, browsing cid 0x%02x\n", browsing_cid);
  361. browsing_cid = 0;
  362. avrcp_browsing_connected = 0;
  363. return;
  364. case AVRCP_SUBEVENT_BROWSING_DONE:
  365. browsing_query_active = false;
  366. browsing_uid_counter = 0;
  367. if (avrcp_subevent_browsing_done_get_browsing_status(packet) != AVRCP_BROWSING_ERROR_CODE_SUCCESS){
  368. printf("AVRCP Browsing: query done with browsing status 0x%02x, bluetooth status 0x%02x\n",
  369. avrcp_subevent_browsing_done_get_browsing_status(packet),
  370. avrcp_subevent_browsing_done_get_bluetooth_status(packet));
  371. break;
  372. }
  373. browsing_uid_counter = avrcp_subevent_browsing_done_get_uid_counter(packet);
  374. printf("AVRCP Browsing: browsing_uid_counter %d\n", browsing_uid_counter);
  375. break;
  376. default:
  377. break;
  378. }
  379. break;
  380. default:
  381. break;
  382. }
  383. }
  384. #ifdef HAVE_BTSTACK_STDIN
  385. static void show_usage(void){
  386. bd_addr_t iut_address;
  387. gap_local_bd_addr(iut_address);
  388. printf("\n--- Bluetooth AVRCP Browsing Service Test Console %s ---\n", bd_addr_to_str(iut_address));
  389. printf("c - AVRCP Service create connection to addr %s\n", bd_addr_to_str(device_addr));
  390. printf("C - AVRCP Service disconnect\n");
  391. printf("e - AVRCP Browsing Service create connection to addr %s\n", bd_addr_to_str(device_addr));
  392. printf("E - AVRCP Browsing Service disconnect\n");
  393. printf("I - Set first found player as addressed player\n");
  394. printf("O - Set first found player as browsed player\n");
  395. printf("p - Get media players\n");
  396. printf("Q - Browse folders\n");
  397. printf("P - Go up one level\n");
  398. printf("W - Go down one level\n");
  399. printf("T - Browse media items\n");
  400. printf("---\n");
  401. }
  402. #endif
  403. #ifdef HAVE_BTSTACK_STDIN
  404. static void stdin_process(char cmd){
  405. uint8_t status = ERROR_CODE_SUCCESS;
  406. if (cmd != 'a' && cmd != 'A' && cmd != 'c' && cmd != 'C'){
  407. if (browsing_query_active){
  408. printf("Query active, try later!\n");
  409. return;
  410. }
  411. }
  412. switch (cmd){
  413. case 'c':
  414. printf(" - Connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr));
  415. status = avrcp_connect(device_addr, &avrcp_cid);
  416. break;
  417. case 'C':
  418. if (avrcp_connected){
  419. printf(" - AVRCP Service disconnect from addr %s.\n", bd_addr_to_str(device_addr));
  420. status = avrcp_disconnect(avrcp_cid);
  421. break;
  422. }
  423. printf("AVRCP Service already disconnected\n");
  424. break;
  425. case 'e':
  426. if (!avrcp_connected) {
  427. printf(" You must first connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr));
  428. break;
  429. }
  430. printf(" - Connect to AVRCP Browsing Service at addr %s.\n", bd_addr_to_str(device_addr));
  431. status = avrcp_browsing_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid);
  432. break;
  433. case 'E':
  434. if (avrcp_browsing_connected){
  435. printf(" - AVRCP Browsing Service disconnect from addr %s.\n", bd_addr_to_str(device_addr));
  436. status = avrcp_browsing_disconnect(browsing_cid);
  437. break;
  438. }
  439. printf("AVRCP Browsing Service already disconnected\n");
  440. break;
  441. case '\n':
  442. case '\r':
  443. break;
  444. default:
  445. if (!avrcp_browsing_connected){
  446. show_usage();
  447. break;
  448. }
  449. switch (cmd) {
  450. case 'I':
  451. if (player_index < 0) {
  452. printf("AVRCP Browsing:Get media players first\n");
  453. break;
  454. }
  455. printf("AVRCP Browsing:Set addressed player\n");
  456. status = avrcp_controller_set_addressed_player(avrcp_cid, players[0]);
  457. break;
  458. case 'O':
  459. if (player_index < 0) {
  460. printf("AVRCP Browsing:Get media players first\n");
  461. break;
  462. }
  463. printf("Set browsed player\n");
  464. status = avrcp_browsing_controller_set_browsed_player(browsing_cid, players[0]);
  465. break;
  466. case 'p':
  467. printf("AVRCP Browsing: get media players\n");
  468. player_index = -1;
  469. status = avrcp_browsing_controller_get_media_players(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
  470. break;
  471. case 'Q':
  472. printf("AVRCP Browsing: browse folders\n");
  473. folder_index = -1;
  474. status = avrcp_browsing_controller_browse_file_system(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
  475. break;
  476. case 'P':
  477. printf("AVRCP Browsing: browse media items\n");
  478. avrcp_browsing_controller_browse_media(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
  479. break;
  480. case 'W':
  481. printf("AVRCP Browsing: go up one level\n");
  482. status = avrcp_browsing_controller_go_up_one_level(browsing_cid);
  483. folder_index = -1;
  484. break;
  485. case 'T':
  486. if (folder_index < 0 && !parent_folder_set){
  487. printf("AVRCP Browsing: no folders available\n");
  488. break;
  489. }
  490. if (!parent_folder_set){
  491. parent_folder_set = 1;
  492. memcpy(parent_folder_name, folders[0].name, folders[0].name_len);
  493. memcpy(parent_folder_uid, folders[0].uid, 8);
  494. }
  495. printf("AVRCP Browsing: go down one level of %s\n", (char *)parent_folder_name);
  496. status = avrcp_browsing_controller_go_down_one_level(browsing_cid, parent_folder_uid);
  497. folder_index = -1;
  498. break;
  499. default:
  500. show_usage();
  501. break;
  502. }
  503. break;
  504. }
  505. if (status != ERROR_CODE_SUCCESS){
  506. printf("AVRCP Browsing: Could not perform command, status 0x%2x\n", status);
  507. }
  508. }
  509. #endif
  510. /* EXAMPLE_END */