101dc6e35SMilanka Ringwald /* 201dc6e35SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 301dc6e35SMilanka Ringwald * 401dc6e35SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 501dc6e35SMilanka Ringwald * modification, are permitted provided that the following conditions 601dc6e35SMilanka Ringwald * are met: 701dc6e35SMilanka Ringwald * 801dc6e35SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 901dc6e35SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 1001dc6e35SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1101dc6e35SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 1201dc6e35SMilanka Ringwald * documentation and/or other materials provided with the distribution. 1301dc6e35SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 1401dc6e35SMilanka Ringwald * contributors may be used to endorse or promote products derived 1501dc6e35SMilanka Ringwald * from this software without specific prior written permission. 1601dc6e35SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 1701dc6e35SMilanka Ringwald * personal benefit and not for any commercial purpose or for 1801dc6e35SMilanka Ringwald * monetary gain. 1901dc6e35SMilanka Ringwald * 2001dc6e35SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2101dc6e35SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2201dc6e35SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2301dc6e35SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 2401dc6e35SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2501dc6e35SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2601dc6e35SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2701dc6e35SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2801dc6e35SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2901dc6e35SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3001dc6e35SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3101dc6e35SMilanka Ringwald * SUCH DAMAGE. 3201dc6e35SMilanka Ringwald * 3301dc6e35SMilanka Ringwald * Please inquire about commercial licensing options at 3401dc6e35SMilanka Ringwald * [email protected] 3501dc6e35SMilanka Ringwald * 3601dc6e35SMilanka Ringwald */ 3701dc6e35SMilanka Ringwald 3801dc6e35SMilanka Ringwald #define __BTSTACK_FILE__ "avrcp_target.c" 3901dc6e35SMilanka Ringwald 4001dc6e35SMilanka Ringwald #include <stdint.h> 4101dc6e35SMilanka Ringwald #include <stdio.h> 4201dc6e35SMilanka Ringwald #include <stdlib.h> 4301dc6e35SMilanka Ringwald #include <string.h> 4401dc6e35SMilanka Ringwald 4501dc6e35SMilanka Ringwald #include "btstack.h" 4601dc6e35SMilanka Ringwald #include "classic/avrcp.h" 4701dc6e35SMilanka Ringwald 4801dc6e35SMilanka Ringwald static avrcp_context_t avrcp_target_context; 4901dc6e35SMilanka Ringwald 5001dc6e35SMilanka Ringwald 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){ 5101dc6e35SMilanka Ringwald avrcp_create_sdp_record(0, service, service_record_handle, browsing, supported_features, service_name, service_provider_name); 5201dc6e35SMilanka Ringwald } 5301dc6e35SMilanka Ringwald 544b338011SMilanka Ringwald static void avrcp_target_emit_respond_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t subeventID){ 554b338011SMilanka Ringwald if (!callback) return; 564b338011SMilanka Ringwald uint8_t event[5]; 574b338011SMilanka Ringwald int pos = 0; 584b338011SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 594b338011SMilanka Ringwald event[pos++] = sizeof(event) - 2; 604b338011SMilanka Ringwald event[pos++] = subeventID; 614b338011SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 624b338011SMilanka Ringwald pos += 2; 634b338011SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 644b338011SMilanka Ringwald } 654b338011SMilanka Ringwald 66*e0bbf3edSMilanka Ringwald static void avrcp_target_emit_respond_subunit_info_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t offset){ 674b338011SMilanka Ringwald if (!callback) return; 684b338011SMilanka Ringwald uint8_t event[6]; 694b338011SMilanka Ringwald int pos = 0; 704b338011SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 714b338011SMilanka Ringwald event[pos++] = sizeof(event) - 2; 724b338011SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_SUBUNIT_INFO_QUERY; 734b338011SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 744b338011SMilanka Ringwald pos += 2; 75*e0bbf3edSMilanka Ringwald event[pos++] = offset; 76*e0bbf3edSMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 77*e0bbf3edSMilanka Ringwald } 78*e0bbf3edSMilanka Ringwald 79*e0bbf3edSMilanka Ringwald static void avrcp_target_emit_respond_get_capabilities(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t subevent_id, uint8_t * company_id){ 80*e0bbf3edSMilanka Ringwald if (!callback) return; 81*e0bbf3edSMilanka Ringwald uint8_t event[8]; 82*e0bbf3edSMilanka Ringwald int pos = 0; 83*e0bbf3edSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 84*e0bbf3edSMilanka Ringwald event[pos++] = sizeof(event) - 2; 85*e0bbf3edSMilanka Ringwald event[pos++] = subevent_id; 86*e0bbf3edSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 87*e0bbf3edSMilanka Ringwald pos += 2; 88*e0bbf3edSMilanka Ringwald memcpy(event+pos, company_id, 3); 894b338011SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 904b338011SMilanka Ringwald } 914b338011SMilanka Ringwald 924b338011SMilanka Ringwald static int avrcp_send_response(uint16_t cid, avrcp_connection_t * connection){ 934b338011SMilanka Ringwald uint8_t command[30]; 944b338011SMilanka Ringwald int pos = 0; 954b338011SMilanka Ringwald // transport header 964b338011SMilanka Ringwald // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 974b338011SMilanka Ringwald command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_RESPONSE_FRAME << 1) | 0; 984b338011SMilanka Ringwald // Profile IDentifier (PID) 994b338011SMilanka Ringwald command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 1004b338011SMilanka Ringwald command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 1014b338011SMilanka Ringwald 1024b338011SMilanka Ringwald // command_type 1034b338011SMilanka Ringwald command[pos++] = connection->command_type; 1044b338011SMilanka Ringwald // subunit_type | subunit ID 1054b338011SMilanka Ringwald command[pos++] = (connection->subunit_type << 3) | connection->subunit_id; 1064b338011SMilanka Ringwald // opcode 1074b338011SMilanka Ringwald command[pos++] = (uint8_t)connection->command_opcode; 1084b338011SMilanka Ringwald // operands 1094b338011SMilanka Ringwald memcpy(command+pos, connection->cmd_operands, connection->cmd_operands_length); 1104b338011SMilanka Ringwald pos += connection->cmd_operands_length; 1114b338011SMilanka Ringwald return l2cap_send(cid, command, pos); 1124b338011SMilanka Ringwald } 1134b338011SMilanka Ringwald 114*e0bbf3edSMilanka Ringwald 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){ 115*e0bbf3edSMilanka Ringwald // AVRCP_CTYPE_RESPONSE_REJECTED 116*e0bbf3edSMilanka Ringwald connection->command_type = AVRCP_CTYPE_RESPONSE_REJECTED; 117*e0bbf3edSMilanka Ringwald connection->subunit_type = subunit_type; 118*e0bbf3edSMilanka Ringwald connection->subunit_id = subunit_id; 119*e0bbf3edSMilanka Ringwald connection->command_opcode = opcode; 120*e0bbf3edSMilanka Ringwald 121*e0bbf3edSMilanka Ringwald // company id is 3 bytes long 122*e0bbf3edSMilanka Ringwald int pos = connection->cmd_operands_length; 123*e0bbf3edSMilanka Ringwald connection->cmd_operands[pos++] = pdu_id; 124*e0bbf3edSMilanka Ringwald connection->cmd_operands[pos++] = 0; 125*e0bbf3edSMilanka Ringwald // param length 126*e0bbf3edSMilanka Ringwald big_endian_store_32(connection->cmd_operands, pos, 1); 127*e0bbf3edSMilanka Ringwald pos += 2; 128*e0bbf3edSMilanka Ringwald connection->cmd_operands[pos++] = status; 129*e0bbf3edSMilanka Ringwald connection->cmd_operands_length = pos; 130*e0bbf3edSMilanka Ringwald return avrcp_send_response(connection->l2cap_signaling_cid, connection); 131*e0bbf3edSMilanka Ringwald } 132*e0bbf3edSMilanka Ringwald 1334b338011SMilanka Ringwald uint8_t avrcp_target_unit_info(uint16_t avrcp_cid, avrcp_subunit_type_t unit_type, uint32_t company_id){ 1344b338011SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 1354b338011SMilanka Ringwald if (!connection){ 1364b338011SMilanka Ringwald log_error("avrcp_unit_info: could not find a connection."); 1374b338011SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1384b338011SMilanka Ringwald } 1394b338011SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 1404b338011SMilanka Ringwald 1414b338011SMilanka Ringwald uint8_t unit = 0; 1424b338011SMilanka Ringwald connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 1434b338011SMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT; //vendor unique 1444b338011SMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; 145*e0bbf3edSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_UNIT_INFO; 1464b338011SMilanka Ringwald 1474b338011SMilanka Ringwald connection->cmd_operands_length = 5; 1484b338011SMilanka Ringwald connection->cmd_operands[0] = 0x07; 1494b338011SMilanka Ringwald connection->cmd_operands[1] = (unit_type << 4) | unit; 1504b338011SMilanka Ringwald // company id is 3 bytes long 151*e0bbf3edSMilanka Ringwald big_endian_store_32(connection->cmd_operands, 2, company_id); 1524b338011SMilanka Ringwald return avrcp_send_response(connection->l2cap_signaling_cid, connection); 1534b338011SMilanka Ringwald } 1544b338011SMilanka Ringwald 1554b338011SMilanka Ringwald uint8_t avrcp_target_subunit_info(uint16_t avrcp_cid, avrcp_subunit_type_t subunit_type, uint8_t offset, uint8_t * subunit_info_data){ 1564b338011SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 1574b338011SMilanka Ringwald if (!connection){ 1584b338011SMilanka Ringwald log_error("avrcp_unit_info: could not find a connection."); 1594b338011SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1604b338011SMilanka Ringwald } 1614b338011SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 1624b338011SMilanka Ringwald 1634b338011SMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_SUBUNIT_INFO; 1644b338011SMilanka Ringwald connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 1654b338011SMilanka Ringwald connection->subunit_type = subunit_type; //vendor unique 1664b338011SMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; 1674b338011SMilanka Ringwald 1684b338011SMilanka Ringwald uint8_t page = offset / 4; 1694b338011SMilanka Ringwald uint8_t extension_code = 7; 1704b338011SMilanka Ringwald connection->cmd_operands_length = 5; 1714b338011SMilanka Ringwald connection->cmd_operands[0] = (page << 4) | extension_code; 1724b338011SMilanka Ringwald memcpy(connection->cmd_operands+1, subunit_info_data + offset, 4); 1734b338011SMilanka Ringwald return avrcp_send_response(connection->l2cap_signaling_cid, connection); 1744b338011SMilanka Ringwald } 1754b338011SMilanka Ringwald 176*e0bbf3edSMilanka Ringwald 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){ 177*e0bbf3edSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 178*e0bbf3edSMilanka Ringwald if (!connection){ 179*e0bbf3edSMilanka Ringwald log_error("avrcp_unit_info: could not find a connection."); 180*e0bbf3edSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 181*e0bbf3edSMilanka Ringwald } 182*e0bbf3edSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 183*e0bbf3edSMilanka Ringwald 184*e0bbf3edSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 185*e0bbf3edSMilanka Ringwald connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 186*e0bbf3edSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; //AVRCP_SUBUNIT_TYPE_UNIT; 187*e0bbf3edSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 188*e0bbf3edSMilanka Ringwald 189*e0bbf3edSMilanka Ringwald int pos = connection->cmd_operands_length; 190*e0bbf3edSMilanka Ringwald connection->cmd_operands[pos++] = AVRCP_PDU_ID_GET_CAPABILITIES; 191*e0bbf3edSMilanka Ringwald connection->cmd_operands[pos++] = 0; 192*e0bbf3edSMilanka Ringwald // param length 193*e0bbf3edSMilanka Ringwald big_endian_store_16(connection->cmd_operands, pos, 2+size); 194*e0bbf3edSMilanka Ringwald pos += 2; 195*e0bbf3edSMilanka Ringwald connection->cmd_operands[pos++] = capability_id; 196*e0bbf3edSMilanka Ringwald connection->cmd_operands[pos++] = capabilities_num; 197*e0bbf3edSMilanka Ringwald memcpy(connection->cmd_operands+pos, capabilities, size); 198*e0bbf3edSMilanka Ringwald pos += size; 199*e0bbf3edSMilanka Ringwald connection->cmd_operands_length = pos; 200*e0bbf3edSMilanka Ringwald return avrcp_send_response(connection->l2cap_signaling_cid, connection); 201*e0bbf3edSMilanka Ringwald } 202*e0bbf3edSMilanka Ringwald 203*e0bbf3edSMilanka Ringwald 204*e0bbf3edSMilanka Ringwald uint8_t avrcp_target_supported_companies(uint16_t avrcp_cid, uint8_t capabilities_num, uint8_t * capabilities, uint8_t size ){ 205*e0bbf3edSMilanka Ringwald return avrcp_target_capability(avrcp_cid, AVRCP_CAPABILITY_ID_COMPANY, capabilities_num, capabilities, size); 206*e0bbf3edSMilanka Ringwald } 207*e0bbf3edSMilanka Ringwald 208*e0bbf3edSMilanka Ringwald uint8_t avrcp_target_supported_events(uint16_t avrcp_cid, uint8_t capabilities_num, uint8_t * capabilities, uint8_t size){ 209*e0bbf3edSMilanka Ringwald return avrcp_target_capability(avrcp_cid, AVRCP_CAPABILITY_ID_EVENT, capabilities_num, capabilities, size); 210*e0bbf3edSMilanka Ringwald } 211*e0bbf3edSMilanka Ringwald 212*e0bbf3edSMilanka Ringwald 213*e0bbf3edSMilanka Ringwald static uint8_t * avrcp_get_company_id(uint8_t *packet, uint16_t size){ 214*e0bbf3edSMilanka Ringwald UNUSED(size); 215*e0bbf3edSMilanka Ringwald return packet + 6; 216*e0bbf3edSMilanka Ringwald } 217*e0bbf3edSMilanka Ringwald 218*e0bbf3edSMilanka Ringwald static uint8_t * avrcp_get_pdu(uint8_t *packet, uint16_t size){ 219*e0bbf3edSMilanka Ringwald UNUSED(size); 220*e0bbf3edSMilanka Ringwald return packet + 9; 221*e0bbf3edSMilanka Ringwald } 222*e0bbf3edSMilanka Ringwald 223*e0bbf3edSMilanka Ringwald 22401dc6e35SMilanka Ringwald static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){ 22501dc6e35SMilanka Ringwald UNUSED(connection); 22601dc6e35SMilanka Ringwald UNUSED(packet); 22701dc6e35SMilanka Ringwald UNUSED(size); 2284b338011SMilanka Ringwald 2294b338011SMilanka Ringwald // uint8_t opcode; 230*e0bbf3edSMilanka Ringwald 2314b338011SMilanka Ringwald uint8_t transport_header = packet[0]; 2324b338011SMilanka Ringwald connection->transaction_label = transport_header >> 4; 2334b338011SMilanka Ringwald // uint8_t packet_type = (transport_header & 0x0F) >> 2; 2344b338011SMilanka Ringwald // uint8_t frame_type = (transport_header & 0x03) >> 1; 2354b338011SMilanka Ringwald // uint8_t ipid = transport_header & 0x01; 2364b338011SMilanka Ringwald // uint8_t byte_value = packet[2]; 2374b338011SMilanka Ringwald // uint16_t pid = (byte_value << 8) | packet[2]; 2384b338011SMilanka Ringwald 239*e0bbf3edSMilanka Ringwald // avrcp_command_type_t ctype = (avrcp_command_type_t) packet[3]; 240*e0bbf3edSMilanka Ringwald // uint8_t byte_value = packet[4]; 241*e0bbf3edSMilanka Ringwald avrcp_subunit_type_t subunit_type = (avrcp_subunit_type_t) (packet[4] >> 3); 242*e0bbf3edSMilanka Ringwald avrcp_subunit_id_t subunit_id = (avrcp_subunit_id_t) (packet[4] & 0x07); 2434b338011SMilanka Ringwald // opcode = packet[pos++]; 2444b338011SMilanka Ringwald 2454b338011SMilanka Ringwald // printf(" Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n", 2464b338011SMilanka Ringwald // transport_header, transaction_label, packet_type, frame_type, ipid, pid); 2474b338011SMilanka Ringwald // printf_hexdump(packet+pos, size-pos); 2484b338011SMilanka Ringwald 249*e0bbf3edSMilanka Ringwald avrcp_command_opcode_t opcode = avrcp_cmd_opcode(packet,size); 250*e0bbf3edSMilanka Ringwald // uint16_t param_length = big_endian_read_16(operands, 5); 251*e0bbf3edSMilanka Ringwald uint8_t * company_id = avrcp_get_company_id(packet, size); 252*e0bbf3edSMilanka Ringwald uint8_t * pdu = avrcp_get_pdu(packet, size); 253*e0bbf3edSMilanka Ringwald 254*e0bbf3edSMilanka Ringwald uint8_t pdu_id = pdu[0]; 255*e0bbf3edSMilanka Ringwald connection->cmd_operands_length = 0; 256*e0bbf3edSMilanka Ringwald 257*e0bbf3edSMilanka Ringwald switch (opcode){ 2584b338011SMilanka Ringwald case AVRCP_CMD_OPCODE_UNIT_INFO: 2594b338011SMilanka Ringwald avrcp_target_emit_respond_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_UNIT_INFO_QUERY); 2604b338011SMilanka Ringwald break; 261*e0bbf3edSMilanka Ringwald case AVRCP_CMD_OPCODE_SUBUNIT_INFO:{ 262*e0bbf3edSMilanka Ringwald uint8_t offset = 4 * (packet[6]>>4); 263*e0bbf3edSMilanka Ringwald avrcp_target_emit_respond_subunit_info_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, offset); 264*e0bbf3edSMilanka Ringwald break; 265*e0bbf3edSMilanka Ringwald } 266*e0bbf3edSMilanka Ringwald case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: 267*e0bbf3edSMilanka Ringwald pdu_id = pdu[0]; 268*e0bbf3edSMilanka Ringwald // 1 - reserved 269*e0bbf3edSMilanka Ringwald // 2-3 param length, 270*e0bbf3edSMilanka Ringwald switch (pdu_id){ 271*e0bbf3edSMilanka Ringwald case AVRCP_PDU_ID_GET_CAPABILITIES:{ 272*e0bbf3edSMilanka Ringwald avrcp_capability_id_t capability_id = (avrcp_capability_id_t) pdu[4]; 273*e0bbf3edSMilanka Ringwald memcpy(connection->cmd_operands, company_id, 3); 274*e0bbf3edSMilanka Ringwald connection->cmd_operands_length = 3; 275*e0bbf3edSMilanka Ringwald switch (capability_id){ 276*e0bbf3edSMilanka Ringwald case AVRCP_CAPABILITY_ID_EVENT: 277*e0bbf3edSMilanka Ringwald avrcp_target_emit_respond_get_capabilities(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_EVENT_IDS_QUERY, company_id); 278*e0bbf3edSMilanka Ringwald break; 279*e0bbf3edSMilanka Ringwald case AVRCP_CAPABILITY_ID_COMPANY: 280*e0bbf3edSMilanka Ringwald avrcp_target_emit_respond_get_capabilities(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_COMPANY_IDS_QUERY, company_id); 281*e0bbf3edSMilanka Ringwald break; 282*e0bbf3edSMilanka Ringwald default: 283*e0bbf3edSMilanka Ringwald avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_PARAMETER); 284*e0bbf3edSMilanka Ringwald break; 285*e0bbf3edSMilanka Ringwald } 286*e0bbf3edSMilanka Ringwald break; 287*e0bbf3edSMilanka Ringwald } 288*e0bbf3edSMilanka Ringwald default: 289*e0bbf3edSMilanka Ringwald break; 290*e0bbf3edSMilanka Ringwald } 2914b338011SMilanka Ringwald break; 2924b338011SMilanka Ringwald default: 2934b338011SMilanka Ringwald printf("AVRCP source: opcode 0x%02x not implemented\n", avrcp_cmd_opcode(packet,size)); 2944b338011SMilanka Ringwald break; 2954b338011SMilanka Ringwald } 29601dc6e35SMilanka Ringwald } 29701dc6e35SMilanka Ringwald 29801dc6e35SMilanka Ringwald static void avrcp_target_handle_can_send_now(avrcp_connection_t * connection){ 29901dc6e35SMilanka Ringwald switch (connection->state){ 30001dc6e35SMilanka Ringwald default: 30101dc6e35SMilanka Ringwald return; 30201dc6e35SMilanka Ringwald } 30301dc6e35SMilanka Ringwald } 30401dc6e35SMilanka Ringwald 30501dc6e35SMilanka Ringwald static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 30601dc6e35SMilanka Ringwald avrcp_connection_t * connection; 30701dc6e35SMilanka Ringwald switch (packet_type) { 30801dc6e35SMilanka Ringwald case L2CAP_DATA_PACKET: 30901dc6e35SMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_target_context); 31001dc6e35SMilanka Ringwald if (!connection) break; 31101dc6e35SMilanka Ringwald avrcp_handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 31201dc6e35SMilanka Ringwald break; 31301dc6e35SMilanka Ringwald case HCI_EVENT_PACKET: 31401dc6e35SMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 31501dc6e35SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 31601dc6e35SMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_target_context); 31701dc6e35SMilanka Ringwald if (!connection) break; 31801dc6e35SMilanka Ringwald avrcp_target_handle_can_send_now(connection); 31901dc6e35SMilanka Ringwald break; 32001dc6e35SMilanka Ringwald default: 32101dc6e35SMilanka Ringwald avrcp_packet_handler(packet_type, channel, packet, size, &avrcp_target_context); 32201dc6e35SMilanka Ringwald break; 32301dc6e35SMilanka Ringwald } 32401dc6e35SMilanka Ringwald default: 32501dc6e35SMilanka Ringwald break; 32601dc6e35SMilanka Ringwald } 32701dc6e35SMilanka Ringwald } 32801dc6e35SMilanka Ringwald 32901dc6e35SMilanka Ringwald void avrcp_target_init(void){ 33001dc6e35SMilanka Ringwald avrcp_target_context.role = AVRCP_TARGET; 33101dc6e35SMilanka Ringwald avrcp_target_context.connections = NULL; 33201dc6e35SMilanka Ringwald avrcp_target_context.packet_handler = avrcp_controller_packet_handler; 33301dc6e35SMilanka Ringwald l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0); 33401dc6e35SMilanka Ringwald } 33501dc6e35SMilanka Ringwald 33601dc6e35SMilanka Ringwald void avrcp_target_register_packet_handler(btstack_packet_handler_t callback){ 33701dc6e35SMilanka Ringwald if (callback == NULL){ 33801dc6e35SMilanka Ringwald log_error("avrcp_register_packet_handler called with NULL callback"); 33901dc6e35SMilanka Ringwald return; 34001dc6e35SMilanka Ringwald } 34101dc6e35SMilanka Ringwald avrcp_target_context.avrcp_callback = callback; 34201dc6e35SMilanka Ringwald } 34301dc6e35SMilanka Ringwald 34401dc6e35SMilanka Ringwald uint8_t avrcp_target_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid){ 34501dc6e35SMilanka Ringwald return avrcp_connect(bd_addr, &avrcp_target_context, avrcp_cid); 34601dc6e35SMilanka Ringwald } 34701dc6e35SMilanka Ringwald 34801dc6e35SMilanka Ringwald uint8_t avrcp_target_disconnect(uint16_t avrcp_cid){ 34901dc6e35SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 35001dc6e35SMilanka Ringwald if (!connection){ 35101dc6e35SMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 35201dc6e35SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 35301dc6e35SMilanka Ringwald } 35401dc6e35SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 35501dc6e35SMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 35601dc6e35SMilanka Ringwald return ERROR_CODE_SUCCESS; 35701dc6e35SMilanka Ringwald } 35801dc6e35SMilanka Ringwald 359