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__ "avrcp_target.c" 39 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <inttypes.h> 45 46 #include "btstack.h" 47 #include "classic/avrcp.h" 48 49 static avrcp_context_t avrcp_target_context; 50 51 void avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name){ 52 avrcp_create_sdp_record(0, service, service_record_handle, browsing, supported_features, service_name, service_provider_name); 53 } 54 55 static void avrcp_target_emit_respond_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t subeventID){ 56 if (!callback) return; 57 uint8_t event[5]; 58 int pos = 0; 59 event[pos++] = HCI_EVENT_AVRCP_META; 60 event[pos++] = sizeof(event) - 2; 61 event[pos++] = subeventID; 62 little_endian_store_16(event, pos, avrcp_cid); 63 pos += 2; 64 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 65 } 66 67 static void avrcp_target_emit_respond_subunit_info_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t offset){ 68 if (!callback) return; 69 uint8_t event[6]; 70 int pos = 0; 71 event[pos++] = HCI_EVENT_AVRCP_META; 72 event[pos++] = sizeof(event) - 2; 73 event[pos++] = AVRCP_SUBEVENT_SUBUNIT_INFO_QUERY; 74 little_endian_store_16(event, pos, avrcp_cid); 75 pos += 2; 76 event[pos++] = offset; 77 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 78 } 79 80 static void avrcp_target_emit_respond_vendor_dependent_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t subevent_id){ 81 if (!callback) return; 82 uint8_t event[5]; 83 int pos = 0; 84 event[pos++] = HCI_EVENT_AVRCP_META; 85 event[pos++] = sizeof(event) - 2; 86 event[pos++] = subevent_id; 87 little_endian_store_16(event, pos, avrcp_cid); 88 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 89 } 90 91 static uint16_t avrcp_target_pack_single_element_attribute_number(uint8_t * packet, uint16_t size, uint16_t pos, avrcp_media_attribute_id_t attr_id, uint32_t value){ 92 UNUSED(size); 93 if ((attr_id < 1) || (attr_id > AVRCP_MEDIA_ATTR_COUNT)) return 0; 94 uint16_t attr_value_length = sprintf((char *)(packet+pos+8), "%0" PRIu32, value); 95 big_endian_store_32(packet, pos, attr_id); 96 pos += 4; 97 big_endian_store_16(packet, pos, UTF8); 98 pos += 2; 99 big_endian_store_16(packet, pos, attr_value_length); 100 pos += 2; 101 return 8 + attr_value_length; 102 } 103 104 static uint16_t avrcp_target_pack_single_element_attribute_string(uint8_t * packet, uint16_t size, uint16_t pos, rfc2978_charset_mib_enumid_t mib_enumid, avrcp_media_attribute_id_t attr_id, uint8_t * attr_value, uint16_t attr_value_length){ 105 UNUSED(size); 106 if (attr_value_length == 0) return 0; 107 if ((attr_id < 1) || (attr_id > AVRCP_MEDIA_ATTR_COUNT)) return 0; 108 big_endian_store_32(packet, pos, attr_id); 109 pos += 4; 110 big_endian_store_16(packet, pos, mib_enumid); 111 pos += 2; 112 big_endian_store_16(packet, pos, attr_value_length); 113 pos += 2; 114 memcpy(packet+pos, attr_value, attr_value_length); 115 pos += attr_value_length; 116 return 8 + attr_value_length; 117 } 118 119 static int avrcp_target_send_now_playing_info(uint16_t cid, avrcp_connection_t * connection){ 120 uint16_t pos = 0; 121 l2cap_reserve_packet_buffer(); 122 uint8_t * packet = l2cap_get_outgoing_buffer(); 123 uint16_t size = l2cap_get_remote_mtu_for_local_cid(connection->l2cap_signaling_cid); 124 125 packet[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_RESPONSE_FRAME << 1) | 0; 126 // Profile IDentifier (PID) 127 packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 128 packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 129 130 // command_type 131 packet[pos++] = connection->command_type; 132 // subunit_type | subunit ID 133 packet[pos++] = (connection->subunit_type << 3) | connection->subunit_id; 134 // opcode 135 packet[pos++] = (uint8_t)connection->command_opcode; 136 137 // company id is 3 bytes long 138 big_endian_store_24(packet, pos, BT_SIG_COMPANY_ID); 139 pos += 3; 140 141 packet[pos++] = AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES; 142 packet[pos++] = 0; 143 144 // num_attrs 145 int i; 146 147 uint16_t playing_info_buffer_len = 1; 148 uint16_t playing_info_buffer_len_position = pos; 149 150 uint8_t media_attr_count = 0; 151 uint16_t media_attr_count_position = pos + 2; 152 pos += 3; 153 154 for (i = 0; i < AVRCP_MEDIA_ATTR_COUNT; i++){ 155 int attr_id = i+1; 156 int attr_len; 157 switch (attr_id){ 158 case AVRCP_MEDIA_ATTR_TRACK: 159 attr_len = avrcp_target_pack_single_element_attribute_number(packet, size, pos, attr_id, connection->track_nr); 160 break; 161 case AVRCP_MEDIA_ATTR_TOTAL_TRACKS: 162 attr_len = avrcp_target_pack_single_element_attribute_number(packet, size, pos, attr_id, connection->total_tracks); 163 break; 164 case AVRCP_MEDIA_ATTR_SONG_LENGTH: 165 attr_len = avrcp_target_pack_single_element_attribute_number(packet, size, pos, attr_id, connection->song_length_ms); 166 break; 167 default: 168 attr_len = avrcp_target_pack_single_element_attribute_string(packet, size, pos, UTF8, attr_id, connection->now_playing_info[i].value, connection->now_playing_info[i].len); 169 break; 170 } 171 if (attr_len > 0) { 172 pos += attr_len; 173 playing_info_buffer_len += attr_len; 174 media_attr_count++; 175 } 176 } 177 big_endian_store_16(packet, playing_info_buffer_len_position, playing_info_buffer_len); 178 packet[media_attr_count_position] = media_attr_count; 179 180 // TODO fragmentation 181 if (playing_info_buffer_len + pos > l2cap_get_remote_mtu_for_local_cid(connection->l2cap_signaling_cid)) { 182 return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; 183 } 184 185 connection->wait_to_send = 0; 186 return l2cap_send_prepared(cid, pos); 187 } 188 189 static int avrcp_target_send_response(uint16_t cid, avrcp_connection_t * connection){ 190 int pos = 0; 191 l2cap_reserve_packet_buffer(); 192 uint8_t * packet = l2cap_get_outgoing_buffer(); 193 194 // transport header 195 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 196 packet[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_RESPONSE_FRAME << 1) | 0; 197 // Profile IDentifier (PID) 198 packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 199 packet[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 200 201 // command_type 202 packet[pos++] = connection->command_type; 203 // subunit_type | subunit ID 204 packet[pos++] = (connection->subunit_type << 3) | connection->subunit_id; 205 // opcode 206 packet[pos++] = (uint8_t)connection->command_opcode; 207 // operands 208 memcpy(packet+pos, connection->cmd_operands, connection->cmd_operands_length); 209 pos += connection->cmd_operands_length; 210 connection->wait_to_send = 0; 211 return l2cap_send_prepared(cid, pos); 212 } 213 214 static uint8_t avrcp_target_response_reject(avrcp_connection_t * connection, avrcp_subunit_type_t subunit_type, avrcp_subunit_id_t subunit_id, avrcp_command_opcode_t opcode, avrcp_pdu_id_t pdu_id, avrcp_status_code_t status){ 215 // AVRCP_CTYPE_RESPONSE_REJECTED 216 connection->command_type = AVRCP_CTYPE_RESPONSE_REJECTED; 217 connection->subunit_type = subunit_type; 218 connection->subunit_id = subunit_id; 219 connection->command_opcode = opcode; 220 221 // company id is 3 bytes long 222 int pos = connection->cmd_operands_length; 223 connection->cmd_operands[pos++] = pdu_id; 224 connection->cmd_operands[pos++] = 0; 225 // param length 226 big_endian_store_16(connection->cmd_operands, pos, 1); 227 pos += 2; 228 connection->cmd_operands[pos++] = status; 229 connection->cmd_operands_length = pos; 230 231 connection->state = AVCTP_W2_SEND_RESPONSE; 232 avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 233 return ERROR_CODE_SUCCESS; 234 } 235 236 uint8_t avrcp_target_unit_info(uint16_t avrcp_cid, avrcp_subunit_type_t unit_type, uint32_t company_id){ 237 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 238 if (!connection){ 239 log_error("avrcp_unit_info: could not find a connection."); 240 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 241 } 242 if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 243 244 uint8_t unit = 0; 245 connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 246 connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT; //vendor unique 247 connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; 248 connection->command_opcode = AVRCP_CMD_OPCODE_UNIT_INFO; 249 250 connection->cmd_operands_length = 5; 251 connection->cmd_operands[0] = 0x07; 252 connection->cmd_operands[1] = (unit_type << 4) | unit; 253 // company id is 3 bytes long 254 big_endian_store_32(connection->cmd_operands, 2, company_id); 255 256 connection->state = AVCTP_W2_SEND_RESPONSE; 257 avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 258 return ERROR_CODE_SUCCESS; 259 } 260 261 uint8_t avrcp_target_subunit_info(uint16_t avrcp_cid, avrcp_subunit_type_t subunit_type, uint8_t offset, uint8_t * subunit_info_data){ 262 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 263 if (!connection){ 264 log_error("avrcp_unit_info: could not find a connection."); 265 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 266 } 267 if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 268 269 connection->command_opcode = AVRCP_CMD_OPCODE_SUBUNIT_INFO; 270 connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 271 connection->subunit_type = subunit_type; //vendor unique 272 connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; 273 274 uint8_t page = offset / 4; 275 uint8_t extension_code = 7; 276 connection->cmd_operands_length = 5; 277 connection->cmd_operands[0] = (page << 4) | extension_code; 278 memcpy(connection->cmd_operands+1, subunit_info_data + offset, 4); 279 280 connection->state = AVCTP_W2_SEND_RESPONSE; 281 avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 282 return ERROR_CODE_SUCCESS; 283 } 284 285 static inline uint8_t avrcp_prepare_vendor_dependent_response(uint16_t avrcp_cid, avrcp_connection_t ** out_connection, avrcp_pdu_id_t pdu_id, uint16_t param_length){ 286 *out_connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 287 if (!*out_connection){ 288 log_error("avrcp tartget: could not find a connection."); 289 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 290 } 291 292 if ((*out_connection)->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 293 (*out_connection)->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 294 (*out_connection)->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 295 (*out_connection)->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 296 (*out_connection)->subunit_id = AVRCP_SUBUNIT_ID; 297 298 (*out_connection)->cmd_operands[(*out_connection)->cmd_operands_length++] = pdu_id; 299 // reserved 300 (*out_connection)->cmd_operands[(*out_connection)->cmd_operands_length++] = 0; 301 // param length 302 big_endian_store_16((*out_connection)->cmd_operands, (*out_connection)->cmd_operands_length, param_length); 303 (*out_connection)->cmd_operands_length += 2; 304 return ERROR_CODE_SUCCESS; 305 } 306 307 static uint8_t avrcp_target_capability(uint16_t avrcp_cid, avrcp_capability_id_t capability_id, uint8_t capabilities_num, uint8_t * capabilities, uint8_t size){ 308 avrcp_connection_t * connection = NULL; 309 uint8_t status = avrcp_prepare_vendor_dependent_response(avrcp_cid, &connection, AVRCP_PDU_ID_GET_CAPABILITIES, 2+size); 310 if (status != ERROR_CODE_SUCCESS) return status; 311 312 connection->cmd_operands[connection->cmd_operands_length++] = capability_id; 313 connection->cmd_operands[connection->cmd_operands_length++] = capabilities_num; 314 memcpy(connection->cmd_operands+connection->cmd_operands_length, capabilities, size); 315 connection->cmd_operands_length += size; 316 317 connection->state = AVCTP_W2_SEND_RESPONSE; 318 avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 319 return ERROR_CODE_SUCCESS; 320 } 321 322 uint8_t avrcp_target_supported_events(uint16_t avrcp_cid, uint8_t capabilities_num, uint8_t * capabilities, uint8_t size){ 323 return avrcp_target_capability(avrcp_cid, AVRCP_CAPABILITY_ID_EVENT, capabilities_num, capabilities, size); 324 } 325 326 uint8_t avrcp_target_supported_companies(uint16_t avrcp_cid, uint8_t capabilities_num, uint8_t * capabilities, uint8_t size ){ 327 return avrcp_target_capability(avrcp_cid, AVRCP_CAPABILITY_ID_COMPANY, capabilities_num, capabilities, size); 328 } 329 330 uint8_t avrcp_target_play_status(uint16_t avrcp_cid, uint32_t song_length_ms, uint32_t song_position_ms, avrcp_play_status_t play_status){ 331 avrcp_connection_t * connection = NULL; 332 uint8_t status = avrcp_prepare_vendor_dependent_response(avrcp_cid, &connection, AVRCP_PDU_ID_GET_PLAY_STATUS, 11); 333 if (status != ERROR_CODE_SUCCESS) return status; 334 335 big_endian_store_32(connection->cmd_operands, connection->cmd_operands_length, song_length_ms); 336 connection->cmd_operands_length += 4; 337 big_endian_store_32(connection->cmd_operands, connection->cmd_operands_length, song_position_ms); 338 connection->cmd_operands_length += 4; 339 connection->cmd_operands[connection->cmd_operands_length++] = play_status; 340 341 connection->state = AVCTP_W2_SEND_RESPONSE; 342 avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 343 return ERROR_CODE_SUCCESS; 344 } 345 346 uint8_t avrcp_target_now_playing_info(uint16_t avrcp_cid){ 347 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 348 if (!connection){ 349 log_error("avrcp tartget: could not find a connection."); 350 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 351 } 352 353 if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 354 connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 355 connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 356 connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 357 connection->subunit_id = AVRCP_SUBUNIT_ID; 358 359 connection->now_playing_info_response = 1; 360 connection->state = AVCTP_W2_SEND_RESPONSE; 361 avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 362 return ERROR_CODE_SUCCESS; 363 } 364 365 static uint8_t avrcp_target_store_media_attr(uint16_t avrcp_cid, avrcp_media_attribute_id_t attr_id, const char * value){ 366 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 367 if (!connection){ 368 log_error("avrcp_unit_info: could not find a connection."); 369 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 370 } 371 372 int index = attr_id - 1; 373 connection->now_playing_info[index].value = (uint8_t*)value; 374 connection->now_playing_info[index].len = strlen(value); 375 return ERROR_CODE_SUCCESS; 376 } 377 378 uint8_t avrcp_target_set_now_playing_title(uint16_t avrcp_cid, const char * title){ 379 return avrcp_target_store_media_attr(avrcp_cid, AVRCP_MEDIA_ATTR_TITLE, title); 380 } 381 382 uint8_t avrcp_target_set_now_playing_artist(uint16_t avrcp_cid, const char * artist){ 383 return avrcp_target_store_media_attr(avrcp_cid, AVRCP_MEDIA_ATTR_ARTIST, artist); 384 } 385 386 uint8_t avrcp_target_set_now_playing_album(uint16_t avrcp_cid, const char * album){ 387 return avrcp_target_store_media_attr(avrcp_cid, AVRCP_MEDIA_ATTR_ALBUM, album); 388 } 389 390 uint8_t avrcp_target_set_now_playing_genre(uint16_t avrcp_cid, const char * genre){ 391 return avrcp_target_store_media_attr(avrcp_cid, AVRCP_MEDIA_ATTR_GENRE, genre); 392 } 393 394 uint8_t avrcp_target_set_now_playing_song_length_ms(uint16_t avrcp_cid, const uint32_t song_length_ms){ 395 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 396 if (!connection){ 397 log_error("avrcp_unit_info: could not find a connection."); 398 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 399 } 400 connection->song_length_ms = song_length_ms; 401 return ERROR_CODE_SUCCESS; 402 } 403 404 uint8_t avrcp_target_set_now_playing_total_tracks(uint16_t avrcp_cid, const int total_tracks){ 405 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 406 if (!connection){ 407 log_error("avrcp_unit_info: could not find a connection."); 408 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 409 } 410 connection->total_tracks = total_tracks; 411 return ERROR_CODE_SUCCESS; 412 } 413 414 uint8_t avrcp_target_set_now_playing_track_nr(uint16_t avrcp_cid, const int track_nr){ 415 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 416 if (!connection){ 417 log_error("avrcp_unit_info: could not find a connection."); 418 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 419 } 420 connection->track_nr = track_nr; 421 return ERROR_CODE_SUCCESS; 422 } 423 424 static uint8_t * avrcp_get_company_id(uint8_t *packet, uint16_t size){ 425 UNUSED(size); 426 return packet + 6; 427 } 428 429 static uint8_t * avrcp_get_pdu(uint8_t *packet, uint16_t size){ 430 UNUSED(size); 431 return packet + 9; 432 } 433 434 static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){ 435 UNUSED(connection); 436 UNUSED(packet); 437 UNUSED(size); 438 439 // uint8_t opcode; 440 441 uint8_t transport_header = packet[0]; 442 connection->transaction_label = transport_header >> 4; 443 // uint8_t packet_type = (transport_header & 0x0F) >> 2; 444 // uint8_t frame_type = (transport_header & 0x03) >> 1; 445 // uint8_t ipid = transport_header & 0x01; 446 // uint8_t byte_value = packet[2]; 447 // uint16_t pid = (byte_value << 8) | packet[2]; 448 449 // avrcp_command_type_t ctype = (avrcp_command_type_t) packet[3]; 450 // uint8_t byte_value = packet[4]; 451 avrcp_subunit_type_t subunit_type = (avrcp_subunit_type_t) (packet[4] >> 3); 452 avrcp_subunit_id_t subunit_id = (avrcp_subunit_id_t) (packet[4] & 0x07); 453 // opcode = packet[pos++]; 454 455 // printf(" Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n", 456 // transport_header, transaction_label, packet_type, frame_type, ipid, pid); 457 // printf_hexdump(packet+pos, size-pos); 458 459 avrcp_command_opcode_t opcode = avrcp_cmd_opcode(packet,size); 460 uint8_t * company_id = avrcp_get_company_id(packet, size); 461 uint8_t * pdu = avrcp_get_pdu(packet, size); 462 // uint16_t param_length = big_endian_read_16(pdu, 2); 463 464 int pos = 4; 465 uint8_t pdu_id; 466 connection->cmd_operands_length = 0; 467 468 switch (opcode){ 469 case AVRCP_CMD_OPCODE_UNIT_INFO: 470 avrcp_target_emit_respond_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_UNIT_INFO_QUERY); 471 break; 472 case AVRCP_CMD_OPCODE_SUBUNIT_INFO:{ 473 uint8_t offset = 4 * (packet[pos+2]>>4); 474 avrcp_target_emit_respond_subunit_info_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, offset); 475 break; 476 } 477 case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: 478 pdu_id = pdu[0]; 479 // 1 - reserved 480 // 2-3 param length, 481 memcpy(connection->cmd_operands, company_id, 3); 482 connection->cmd_operands_length = 3; 483 switch (pdu_id){ 484 case AVRCP_PDU_ID_GET_CAPABILITIES:{ 485 avrcp_capability_id_t capability_id = (avrcp_capability_id_t) pdu[pos]; 486 switch (capability_id){ 487 case AVRCP_CAPABILITY_ID_EVENT: 488 avrcp_target_emit_respond_vendor_dependent_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_EVENT_IDS_QUERY); 489 break; 490 case AVRCP_CAPABILITY_ID_COMPANY: 491 avrcp_target_emit_respond_vendor_dependent_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_COMPANY_IDS_QUERY); 492 break; 493 default: 494 avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_PARAMETER); 495 break; 496 } 497 break; 498 } 499 case AVRCP_PDU_ID_GET_PLAY_STATUS: 500 avrcp_target_emit_respond_vendor_dependent_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_PLAY_STATUS_QUERY); 501 break; 502 case AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES:{ 503 uint8_t play_identifier[8]; 504 memset(play_identifier, 0, 8); 505 if (memcmp(pdu+pos, play_identifier, 8) != 0) { 506 avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_PARAMETER); 507 return; 508 } 509 avrcp_target_emit_respond_vendor_dependent_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_NOW_PLAYING_INFO_QUERY); 510 break; 511 } 512 default: 513 printf("unhandled pdu id 0x%02x\n", pdu_id); 514 avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_COMMAND); 515 break; 516 } 517 break; 518 default: 519 printf("AVRCP source: opcode 0x%02x not implemented\n", avrcp_cmd_opcode(packet,size)); 520 break; 521 } 522 } 523 524 static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 525 avrcp_connection_t * connection; 526 switch (packet_type) { 527 case L2CAP_DATA_PACKET: 528 connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_target_context); 529 if (!connection) break; 530 avrcp_handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 531 break; 532 case HCI_EVENT_PACKET: 533 switch (hci_event_packet_get_type(packet)){ 534 case L2CAP_EVENT_CAN_SEND_NOW: 535 connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_target_context); 536 if (!connection) break; 537 switch (connection->state){ 538 case AVCTP_W2_SEND_RESPONSE: 539 connection->state = AVCTP_CONNECTION_OPENED; 540 if (connection->now_playing_info_response){ 541 printf("now_playing_info_response \n"); 542 connection->now_playing_info_response = 0; 543 avrcp_target_send_now_playing_info(connection->l2cap_signaling_cid, connection); 544 break; 545 } 546 avrcp_target_send_response(connection->l2cap_signaling_cid, connection); 547 break; 548 default: 549 return; 550 } 551 break; 552 default: 553 avrcp_packet_handler(packet_type, channel, packet, size, &avrcp_target_context); 554 break; 555 } 556 default: 557 break; 558 } 559 } 560 561 void avrcp_target_init(void){ 562 avrcp_target_context.role = AVRCP_TARGET; 563 avrcp_target_context.connections = NULL; 564 avrcp_target_context.packet_handler = avrcp_controller_packet_handler; 565 l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0); 566 } 567 568 void avrcp_target_register_packet_handler(btstack_packet_handler_t callback){ 569 if (callback == NULL){ 570 log_error("avrcp_register_packet_handler called with NULL callback"); 571 return; 572 } 573 avrcp_target_context.avrcp_callback = callback; 574 } 575 576 uint8_t avrcp_target_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid){ 577 return avrcp_connect(bd_addr, &avrcp_target_context, avrcp_cid); 578 } 579 580 uint8_t avrcp_target_disconnect(uint16_t avrcp_cid){ 581 avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 582 if (!connection){ 583 log_error("avrcp_get_capabilities: could not find a connection."); 584 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 585 } 586 if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 587 l2cap_disconnect(connection->l2cap_signaling_cid, 0); 588 return ERROR_CODE_SUCCESS; 589 } 590 591