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 54*4b338011SMilanka Ringwald static void avrcp_target_emit_respond_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t subeventID){ 55*4b338011SMilanka Ringwald if (!callback) return; 56*4b338011SMilanka Ringwald uint8_t event[5]; 57*4b338011SMilanka Ringwald int pos = 0; 58*4b338011SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 59*4b338011SMilanka Ringwald event[pos++] = sizeof(event) - 2; 60*4b338011SMilanka Ringwald event[pos++] = subeventID; 61*4b338011SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 62*4b338011SMilanka Ringwald pos += 2; 63*4b338011SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 64*4b338011SMilanka Ringwald } 65*4b338011SMilanka Ringwald 66*4b338011SMilanka Ringwald static void avrcp_target_emit_respond_subunit_info_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t page){ 67*4b338011SMilanka Ringwald if (!callback) return; 68*4b338011SMilanka Ringwald uint8_t event[6]; 69*4b338011SMilanka Ringwald int pos = 0; 70*4b338011SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 71*4b338011SMilanka Ringwald event[pos++] = sizeof(event) - 2; 72*4b338011SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_SUBUNIT_INFO_QUERY; 73*4b338011SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 74*4b338011SMilanka Ringwald pos += 2; 75*4b338011SMilanka Ringwald event[pos++] = page; 76*4b338011SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 77*4b338011SMilanka Ringwald } 78*4b338011SMilanka Ringwald 79*4b338011SMilanka Ringwald static int avrcp_send_response(uint16_t cid, avrcp_connection_t * connection){ 80*4b338011SMilanka Ringwald uint8_t command[30]; 81*4b338011SMilanka Ringwald int pos = 0; 82*4b338011SMilanka Ringwald // transport header 83*4b338011SMilanka Ringwald // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 84*4b338011SMilanka Ringwald command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_RESPONSE_FRAME << 1) | 0; 85*4b338011SMilanka Ringwald // Profile IDentifier (PID) 86*4b338011SMilanka Ringwald command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 87*4b338011SMilanka Ringwald command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 88*4b338011SMilanka Ringwald 89*4b338011SMilanka Ringwald // command_type 90*4b338011SMilanka Ringwald command[pos++] = connection->command_type; 91*4b338011SMilanka Ringwald // subunit_type | subunit ID 92*4b338011SMilanka Ringwald command[pos++] = (connection->subunit_type << 3) | connection->subunit_id; 93*4b338011SMilanka Ringwald // opcode 94*4b338011SMilanka Ringwald command[pos++] = (uint8_t)connection->command_opcode; 95*4b338011SMilanka Ringwald // operands 96*4b338011SMilanka Ringwald memcpy(command+pos, connection->cmd_operands, connection->cmd_operands_length); 97*4b338011SMilanka Ringwald pos += connection->cmd_operands_length; 98*4b338011SMilanka Ringwald 99*4b338011SMilanka Ringwald return l2cap_send(cid, command, pos); 100*4b338011SMilanka Ringwald } 101*4b338011SMilanka Ringwald 102*4b338011SMilanka Ringwald uint8_t avrcp_target_unit_info(uint16_t avrcp_cid, avrcp_subunit_type_t unit_type, uint32_t company_id){ 103*4b338011SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 104*4b338011SMilanka Ringwald if (!connection){ 105*4b338011SMilanka Ringwald log_error("avrcp_unit_info: could not find a connection."); 106*4b338011SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 107*4b338011SMilanka Ringwald } 108*4b338011SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 109*4b338011SMilanka Ringwald 110*4b338011SMilanka Ringwald uint8_t unit = 0; 111*4b338011SMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_UNIT_INFO; 112*4b338011SMilanka Ringwald connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 113*4b338011SMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT; //vendor unique 114*4b338011SMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; 115*4b338011SMilanka Ringwald 116*4b338011SMilanka Ringwald connection->cmd_operands_length = 5; 117*4b338011SMilanka Ringwald connection->cmd_operands[0] = 0x07; 118*4b338011SMilanka Ringwald connection->cmd_operands[1] = (unit_type << 4) | unit; 119*4b338011SMilanka Ringwald // company id is 3 bytes long 120*4b338011SMilanka Ringwald little_endian_store_32(connection->cmd_operands, 2, company_id); 121*4b338011SMilanka Ringwald return avrcp_send_response(connection->l2cap_signaling_cid, connection); 122*4b338011SMilanka Ringwald } 123*4b338011SMilanka Ringwald 124*4b338011SMilanka 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){ 125*4b338011SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 126*4b338011SMilanka Ringwald if (!connection){ 127*4b338011SMilanka Ringwald log_error("avrcp_unit_info: could not find a connection."); 128*4b338011SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 129*4b338011SMilanka Ringwald } 130*4b338011SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 131*4b338011SMilanka Ringwald 132*4b338011SMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_SUBUNIT_INFO; 133*4b338011SMilanka Ringwald connection->command_type = AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE; 134*4b338011SMilanka Ringwald connection->subunit_type = subunit_type; //vendor unique 135*4b338011SMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; 136*4b338011SMilanka Ringwald 137*4b338011SMilanka Ringwald uint8_t page = offset / 4; 138*4b338011SMilanka Ringwald uint8_t extension_code = 7; 139*4b338011SMilanka Ringwald connection->cmd_operands_length = 5; 140*4b338011SMilanka Ringwald connection->cmd_operands[0] = (page << 4) | extension_code; 141*4b338011SMilanka Ringwald memcpy(connection->cmd_operands+1, subunit_info_data + offset, 4); 142*4b338011SMilanka Ringwald return avrcp_send_response(connection->l2cap_signaling_cid, connection); 143*4b338011SMilanka Ringwald } 144*4b338011SMilanka Ringwald 14501dc6e35SMilanka Ringwald static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){ 14601dc6e35SMilanka Ringwald UNUSED(connection); 14701dc6e35SMilanka Ringwald UNUSED(packet); 14801dc6e35SMilanka Ringwald UNUSED(size); 149*4b338011SMilanka Ringwald 150*4b338011SMilanka Ringwald // uint8_t opcode; 151*4b338011SMilanka Ringwald // int pos = 3; 152*4b338011SMilanka Ringwald uint8_t transport_header = packet[0]; 153*4b338011SMilanka Ringwald connection->transaction_label = transport_header >> 4; 154*4b338011SMilanka Ringwald // uint8_t packet_type = (transport_header & 0x0F) >> 2; 155*4b338011SMilanka Ringwald // uint8_t frame_type = (transport_header & 0x03) >> 1; 156*4b338011SMilanka Ringwald // uint8_t ipid = transport_header & 0x01; 157*4b338011SMilanka Ringwald // uint8_t byte_value = packet[2]; 158*4b338011SMilanka Ringwald // uint16_t pid = (byte_value << 8) | packet[2]; 159*4b338011SMilanka Ringwald 160*4b338011SMilanka Ringwald // avrcp_command_type_t ctype = (avrcp_command_type_t) packet[pos++]; 161*4b338011SMilanka Ringwald // byte_value = packet[pos++]; 162*4b338011SMilanka Ringwald // avrcp_subunit_type_t subunit_type = (avrcp_subunit_type_t) (byte_value >> 3); 163*4b338011SMilanka Ringwald // avrcp_subunit_type_t subunit_id = (avrcp_subunit_type_t) (byte_value & 0x07); 164*4b338011SMilanka Ringwald // opcode = packet[pos++]; 165*4b338011SMilanka Ringwald 166*4b338011SMilanka Ringwald // printf(" Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n", 167*4b338011SMilanka Ringwald // transport_header, transaction_label, packet_type, frame_type, ipid, pid); 168*4b338011SMilanka Ringwald // printf_hexdump(packet+pos, size-pos); 169*4b338011SMilanka Ringwald 170*4b338011SMilanka Ringwald // uint8_t pdu_id; 171*4b338011SMilanka Ringwald // uint16_t param_length; 172*4b338011SMilanka Ringwald uint8_t * operands = packet + 6; 173*4b338011SMilanka Ringwald switch (avrcp_cmd_opcode(packet,size)){ 174*4b338011SMilanka Ringwald case AVRCP_CMD_OPCODE_UNIT_INFO: 175*4b338011SMilanka Ringwald avrcp_target_emit_respond_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_UNIT_INFO_QUERY); 176*4b338011SMilanka Ringwald break; 177*4b338011SMilanka Ringwald case AVRCP_CMD_OPCODE_SUBUNIT_INFO: 178*4b338011SMilanka Ringwald // printf("operands 0x%02x\n", ); 179*4b338011SMilanka Ringwald // printf_hexdump(packet, size) 180*4b338011SMilanka Ringwald avrcp_target_emit_respond_subunit_info_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, 4 * (operands[0]>>4)); 181*4b338011SMilanka Ringwald break; 182*4b338011SMilanka Ringwald default: 183*4b338011SMilanka Ringwald printf("AVRCP source: opcode 0x%02x not implemented\n", avrcp_cmd_opcode(packet,size)); 184*4b338011SMilanka Ringwald break; 185*4b338011SMilanka Ringwald } 18601dc6e35SMilanka Ringwald } 18701dc6e35SMilanka Ringwald 18801dc6e35SMilanka Ringwald static void avrcp_target_handle_can_send_now(avrcp_connection_t * connection){ 18901dc6e35SMilanka Ringwald switch (connection->state){ 19001dc6e35SMilanka Ringwald default: 19101dc6e35SMilanka Ringwald return; 19201dc6e35SMilanka Ringwald } 19301dc6e35SMilanka Ringwald } 19401dc6e35SMilanka Ringwald 19501dc6e35SMilanka Ringwald static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 19601dc6e35SMilanka Ringwald avrcp_connection_t * connection; 19701dc6e35SMilanka Ringwald switch (packet_type) { 19801dc6e35SMilanka Ringwald case L2CAP_DATA_PACKET: 19901dc6e35SMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_target_context); 20001dc6e35SMilanka Ringwald if (!connection) break; 20101dc6e35SMilanka Ringwald avrcp_handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 20201dc6e35SMilanka Ringwald break; 20301dc6e35SMilanka Ringwald case HCI_EVENT_PACKET: 20401dc6e35SMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 20501dc6e35SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 20601dc6e35SMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_target_context); 20701dc6e35SMilanka Ringwald if (!connection) break; 20801dc6e35SMilanka Ringwald avrcp_target_handle_can_send_now(connection); 20901dc6e35SMilanka Ringwald break; 21001dc6e35SMilanka Ringwald default: 21101dc6e35SMilanka Ringwald avrcp_packet_handler(packet_type, channel, packet, size, &avrcp_target_context); 21201dc6e35SMilanka Ringwald break; 21301dc6e35SMilanka Ringwald } 21401dc6e35SMilanka Ringwald default: 21501dc6e35SMilanka Ringwald break; 21601dc6e35SMilanka Ringwald } 21701dc6e35SMilanka Ringwald } 21801dc6e35SMilanka Ringwald 21901dc6e35SMilanka Ringwald void avrcp_target_init(void){ 22001dc6e35SMilanka Ringwald avrcp_target_context.role = AVRCP_TARGET; 22101dc6e35SMilanka Ringwald avrcp_target_context.connections = NULL; 22201dc6e35SMilanka Ringwald avrcp_target_context.packet_handler = avrcp_controller_packet_handler; 22301dc6e35SMilanka Ringwald l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0); 22401dc6e35SMilanka Ringwald } 22501dc6e35SMilanka Ringwald 22601dc6e35SMilanka Ringwald void avrcp_target_register_packet_handler(btstack_packet_handler_t callback){ 22701dc6e35SMilanka Ringwald if (callback == NULL){ 22801dc6e35SMilanka Ringwald log_error("avrcp_register_packet_handler called with NULL callback"); 22901dc6e35SMilanka Ringwald return; 23001dc6e35SMilanka Ringwald } 23101dc6e35SMilanka Ringwald avrcp_target_context.avrcp_callback = callback; 23201dc6e35SMilanka Ringwald } 23301dc6e35SMilanka Ringwald 23401dc6e35SMilanka Ringwald uint8_t avrcp_target_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid){ 23501dc6e35SMilanka Ringwald return avrcp_connect(bd_addr, &avrcp_target_context, avrcp_cid); 23601dc6e35SMilanka Ringwald } 23701dc6e35SMilanka Ringwald 23801dc6e35SMilanka Ringwald uint8_t avrcp_target_disconnect(uint16_t avrcp_cid){ 23901dc6e35SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context); 24001dc6e35SMilanka Ringwald if (!connection){ 24101dc6e35SMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 24201dc6e35SMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 24301dc6e35SMilanka Ringwald } 24401dc6e35SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 24501dc6e35SMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 24601dc6e35SMilanka Ringwald return ERROR_CODE_SUCCESS; 24701dc6e35SMilanka Ringwald } 24801dc6e35SMilanka Ringwald 249