1*6983e65eSMilanka Ringwald /* 2*6983e65eSMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3*6983e65eSMilanka Ringwald * 4*6983e65eSMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5*6983e65eSMilanka Ringwald * modification, are permitted provided that the following conditions 6*6983e65eSMilanka Ringwald * are met: 7*6983e65eSMilanka Ringwald * 8*6983e65eSMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9*6983e65eSMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10*6983e65eSMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*6983e65eSMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12*6983e65eSMilanka Ringwald * documentation and/or other materials provided with the distribution. 13*6983e65eSMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14*6983e65eSMilanka Ringwald * contributors may be used to endorse or promote products derived 15*6983e65eSMilanka Ringwald * from this software without specific prior written permission. 16*6983e65eSMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17*6983e65eSMilanka Ringwald * personal benefit and not for any commercial purpose or for 18*6983e65eSMilanka Ringwald * monetary gain. 19*6983e65eSMilanka Ringwald * 20*6983e65eSMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*6983e65eSMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*6983e65eSMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*6983e65eSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*6983e65eSMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*6983e65eSMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*6983e65eSMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*6983e65eSMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*6983e65eSMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*6983e65eSMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*6983e65eSMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*6983e65eSMilanka Ringwald * SUCH DAMAGE. 32*6983e65eSMilanka Ringwald * 33*6983e65eSMilanka Ringwald * Please inquire about commercial licensing options at 34*6983e65eSMilanka Ringwald * [email protected] 35*6983e65eSMilanka Ringwald * 36*6983e65eSMilanka Ringwald */ 37*6983e65eSMilanka Ringwald 38*6983e65eSMilanka Ringwald #define __BTSTACK_FILE__ "avrcp.c" 39*6983e65eSMilanka Ringwald 40*6983e65eSMilanka Ringwald #include <stdint.h> 41*6983e65eSMilanka Ringwald #include <stdio.h> 42*6983e65eSMilanka Ringwald #include <stdlib.h> 43*6983e65eSMilanka Ringwald #include <string.h> 44*6983e65eSMilanka Ringwald 45*6983e65eSMilanka Ringwald #include "btstack.h" 46*6983e65eSMilanka Ringwald #include "classic/avrcp.h" 47*6983e65eSMilanka Ringwald #include "classic/avrcp_controller.h" 48*6983e65eSMilanka Ringwald 49*6983e65eSMilanka Ringwald 50*6983e65eSMilanka Ringwald /* 51*6983e65eSMilanka Ringwald Category 1: Player/Recorder 52*6983e65eSMilanka Ringwald Category 2: Monitor/Amplifier 53*6983e65eSMilanka Ringwald Category 3: Tuner 54*6983e65eSMilanka Ringwald Category 4: Menu 55*6983e65eSMilanka Ringwald */ 56*6983e65eSMilanka Ringwald 57*6983e65eSMilanka Ringwald /* controller supported features 58*6983e65eSMilanka Ringwald Bit 0 = Category 1 59*6983e65eSMilanka Ringwald Bit 1 = Category 2 60*6983e65eSMilanka Ringwald Bit 2 = Category 3 61*6983e65eSMilanka Ringwald Bit 3 = Category 4 62*6983e65eSMilanka Ringwald Bit 4-5 = RFA 63*6983e65eSMilanka Ringwald Bit 6 = Supports browsing 64*6983e65eSMilanka Ringwald Bit 7-15 = RFA 65*6983e65eSMilanka Ringwald The bits for supported categories are set to 1. Others are set to 0. 66*6983e65eSMilanka Ringwald */ 67*6983e65eSMilanka Ringwald 68*6983e65eSMilanka Ringwald /* target supported features 69*6983e65eSMilanka Ringwald Bit 0 = Category 1 70*6983e65eSMilanka Ringwald Bit 1 = Category 2 71*6983e65eSMilanka Ringwald Bit 2 = Category 3 72*6983e65eSMilanka Ringwald Bit 3 = Category 4 73*6983e65eSMilanka Ringwald Bit 4 = Player Application Settings. Bit 0 should be set for this bit to be set. 74*6983e65eSMilanka Ringwald Bit 5 = Group Navigation. Bit 0 should be set for this bit to be set. 75*6983e65eSMilanka Ringwald Bit 6 = Supports browsing*4 76*6983e65eSMilanka Ringwald Bit 7 = Supports multiple media player applications 77*6983e65eSMilanka Ringwald Bit 8-15 = RFA 78*6983e65eSMilanka Ringwald The bits for supported categories are set to 1. Others are set to 0. 79*6983e65eSMilanka Ringwald */ 80*6983e65eSMilanka Ringwald 81*6983e65eSMilanka Ringwald static avrcp_context_t avrcp_controller_context; 82*6983e65eSMilanka Ringwald 83*6983e65eSMilanka Ringwald void avrcp_controller_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){ 84*6983e65eSMilanka Ringwald avrcp_create_sdp_record(1, service, service_record_handle, browsing, supported_features, service_name, service_provider_name); 85*6983e65eSMilanka Ringwald } 86*6983e65eSMilanka Ringwald 87*6983e65eSMilanka Ringwald static void avrcp_emit_repeat_and_shuffle_mode(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t ctype, avrcp_repeat_mode_t repeat_mode, avrcp_shuffle_mode_t shuffle_mode){ 88*6983e65eSMilanka Ringwald if (!callback) return; 89*6983e65eSMilanka Ringwald uint8_t event[8]; 90*6983e65eSMilanka Ringwald int pos = 0; 91*6983e65eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 92*6983e65eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 93*6983e65eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE; 94*6983e65eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 95*6983e65eSMilanka Ringwald pos += 2; 96*6983e65eSMilanka Ringwald event[pos++] = ctype; 97*6983e65eSMilanka Ringwald event[pos++] = repeat_mode; 98*6983e65eSMilanka Ringwald event[pos++] = shuffle_mode; 99*6983e65eSMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 100*6983e65eSMilanka Ringwald } 101*6983e65eSMilanka Ringwald 102*6983e65eSMilanka Ringwald static void avrcp_emit_operation_status(btstack_packet_handler_t callback, uint8_t subevent, uint16_t avrcp_cid, uint8_t ctype, uint8_t operation_id){ 103*6983e65eSMilanka Ringwald if (!callback) return; 104*6983e65eSMilanka Ringwald uint8_t event[7]; 105*6983e65eSMilanka Ringwald int pos = 0; 106*6983e65eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 107*6983e65eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 108*6983e65eSMilanka Ringwald event[pos++] = subevent; 109*6983e65eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 110*6983e65eSMilanka Ringwald pos += 2; 111*6983e65eSMilanka Ringwald event[pos++] = ctype; 112*6983e65eSMilanka Ringwald event[pos++] = operation_id; 113*6983e65eSMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 114*6983e65eSMilanka Ringwald } 115*6983e65eSMilanka Ringwald 116*6983e65eSMilanka Ringwald static void avrcp_press_and_hold_timeout_handler(btstack_timer_source_t * timer){ 117*6983e65eSMilanka Ringwald UNUSED(timer); 118*6983e65eSMilanka Ringwald avrcp_connection_t * connection = btstack_run_loop_get_timer_context(timer); 119*6983e65eSMilanka Ringwald btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout 120*6983e65eSMilanka Ringwald btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer); 121*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_PRESS_COMMAND; 122*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 123*6983e65eSMilanka Ringwald } 124*6983e65eSMilanka Ringwald 125*6983e65eSMilanka Ringwald static void avrcp_press_and_hold_timer_start(avrcp_connection_t * connection){ 126*6983e65eSMilanka Ringwald btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer); 127*6983e65eSMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->press_and_hold_cmd_timer, avrcp_press_and_hold_timeout_handler); 128*6983e65eSMilanka Ringwald btstack_run_loop_set_timer_context(&connection->press_and_hold_cmd_timer, connection); 129*6983e65eSMilanka Ringwald btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout 130*6983e65eSMilanka Ringwald btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer); 131*6983e65eSMilanka Ringwald } 132*6983e65eSMilanka Ringwald 133*6983e65eSMilanka Ringwald static void avrcp_press_and_hold_timer_stop(avrcp_connection_t * connection){ 134*6983e65eSMilanka Ringwald connection->continuous_fast_forward_cmd = 0; 135*6983e65eSMilanka Ringwald btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer); 136*6983e65eSMilanka Ringwald } 137*6983e65eSMilanka Ringwald 138*6983e65eSMilanka Ringwald static uint8_t request_pass_through_release_control_cmd(avrcp_connection_t * connection){ 139*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_RELEASE_COMMAND; 140*6983e65eSMilanka Ringwald if (connection->continuous_fast_forward_cmd){ 141*6983e65eSMilanka Ringwald avrcp_press_and_hold_timer_stop(connection); 142*6983e65eSMilanka Ringwald } 143*6983e65eSMilanka Ringwald connection->cmd_operands[0] = 0x80 | connection->cmd_operands[0]; 144*6983e65eSMilanka Ringwald connection->transaction_label++; 145*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 146*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 147*6983e65eSMilanka Ringwald } 148*6983e65eSMilanka Ringwald 149*6983e65eSMilanka Ringwald static inline uint8_t request_pass_through_press_control_cmd(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint16_t playback_speed, uint8_t continuous_fast_forward_cmd, avrcp_context_t * context){ 150*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, context); 151*6983e65eSMilanka Ringwald if (!connection){ 152*6983e65eSMilanka Ringwald log_error("avrcp: could not find a connection."); 153*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 154*6983e65eSMilanka Ringwald } 155*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 156*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_PRESS_COMMAND; 157*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_PASS_THROUGH; 158*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_CONTROL; 159*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 160*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 161*6983e65eSMilanka Ringwald connection->cmd_operands_length = 0; 162*6983e65eSMilanka Ringwald 163*6983e65eSMilanka Ringwald connection->continuous_fast_forward_cmd = continuous_fast_forward_cmd; 164*6983e65eSMilanka Ringwald connection->cmd_operands_length = 2; 165*6983e65eSMilanka Ringwald connection->cmd_operands[0] = opid; 166*6983e65eSMilanka Ringwald if (playback_speed > 0){ 167*6983e65eSMilanka Ringwald connection->cmd_operands[2] = playback_speed; 168*6983e65eSMilanka Ringwald connection->cmd_operands_length++; 169*6983e65eSMilanka Ringwald } 170*6983e65eSMilanka Ringwald connection->cmd_operands[1] = connection->cmd_operands_length - 2; 171*6983e65eSMilanka Ringwald 172*6983e65eSMilanka Ringwald if (connection->continuous_fast_forward_cmd){ 173*6983e65eSMilanka Ringwald avrcp_press_and_hold_timer_start(connection); 174*6983e65eSMilanka Ringwald } 175*6983e65eSMilanka Ringwald 176*6983e65eSMilanka Ringwald connection->transaction_label++; 177*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 178*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 179*6983e65eSMilanka Ringwald } 180*6983e65eSMilanka Ringwald 181*6983e65eSMilanka Ringwald static uint8_t request_single_pass_through_press_control_cmd(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint16_t playback_speed){ 182*6983e65eSMilanka Ringwald return request_pass_through_press_control_cmd(avrcp_cid, opid, playback_speed, 0, &avrcp_controller_context); 183*6983e65eSMilanka Ringwald } 184*6983e65eSMilanka Ringwald 185*6983e65eSMilanka Ringwald static uint8_t request_continuous_pass_through_press_control_cmd(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint16_t playback_speed){ 186*6983e65eSMilanka Ringwald return request_pass_through_press_control_cmd(avrcp_cid, opid, playback_speed, 1, &avrcp_controller_context); 187*6983e65eSMilanka Ringwald } 188*6983e65eSMilanka Ringwald 189*6983e65eSMilanka Ringwald static int avrcp_send_cmd(uint16_t cid, avrcp_connection_t * connection){ 190*6983e65eSMilanka Ringwald uint8_t command[30]; 191*6983e65eSMilanka Ringwald int pos = 0; 192*6983e65eSMilanka Ringwald // transport header 193*6983e65eSMilanka Ringwald // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 194*6983e65eSMilanka Ringwald command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 195*6983e65eSMilanka Ringwald // Profile IDentifier (PID) 196*6983e65eSMilanka Ringwald command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 197*6983e65eSMilanka Ringwald command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 198*6983e65eSMilanka Ringwald 199*6983e65eSMilanka Ringwald // command_type 200*6983e65eSMilanka Ringwald command[pos++] = connection->command_type; 201*6983e65eSMilanka Ringwald // subunit_type | subunit ID 202*6983e65eSMilanka Ringwald command[pos++] = (connection->subunit_type << 3) | connection->subunit_id; 203*6983e65eSMilanka Ringwald // opcode 204*6983e65eSMilanka Ringwald command[pos++] = (uint8_t)connection->command_opcode; 205*6983e65eSMilanka Ringwald // operands 206*6983e65eSMilanka Ringwald memcpy(command+pos, connection->cmd_operands, connection->cmd_operands_length); 207*6983e65eSMilanka Ringwald pos += connection->cmd_operands_length; 208*6983e65eSMilanka Ringwald 209*6983e65eSMilanka Ringwald return l2cap_send(cid, command, pos); 210*6983e65eSMilanka Ringwald } 211*6983e65eSMilanka Ringwald 212*6983e65eSMilanka Ringwald static int avrcp_register_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id){ 213*6983e65eSMilanka Ringwald if (connection->notifications_to_deregister & (1 << event_id)) return 0; 214*6983e65eSMilanka Ringwald if (connection->notifications_enabled & (1 << event_id)) return 0; 215*6983e65eSMilanka Ringwald if (connection->notifications_to_register & (1 << event_id)) return 0; 216*6983e65eSMilanka Ringwald connection->notifications_to_register |= (1 << event_id); 217*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 218*6983e65eSMilanka Ringwald return 1; 219*6983e65eSMilanka Ringwald } 220*6983e65eSMilanka Ringwald 221*6983e65eSMilanka Ringwald static void avrcp_prepare_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id){ 222*6983e65eSMilanka Ringwald connection->transaction_label++; 223*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 224*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_NOTIFY; 225*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 226*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 227*6983e65eSMilanka Ringwald int pos = 0; 228*6983e65eSMilanka Ringwald big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); 229*6983e65eSMilanka Ringwald pos += 3; 230*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = AVRCP_PDU_ID_REGISTER_NOTIFICATION; 231*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = 0; // reserved(upper 6) | packet_type -> 0 232*6983e65eSMilanka Ringwald big_endian_store_16(connection->cmd_operands, pos, 5); // parameter length 233*6983e65eSMilanka Ringwald pos += 2; 234*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = event_id; 235*6983e65eSMilanka Ringwald big_endian_store_32(connection->cmd_operands, pos, 0); 236*6983e65eSMilanka Ringwald pos += 4; 237*6983e65eSMilanka Ringwald connection->cmd_operands_length = pos; 238*6983e65eSMilanka Ringwald // AVRCP_SPEC_V14.pdf 166 239*6983e65eSMilanka Ringwald // answer page 61 240*6983e65eSMilanka Ringwald } 241*6983e65eSMilanka Ringwald 242*6983e65eSMilanka Ringwald static uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ 243*6983e65eSMilanka Ringwald uint8_t cmd_opcode_index = 5; 244*6983e65eSMilanka Ringwald if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; 245*6983e65eSMilanka Ringwald return packet[cmd_opcode_index]; 246*6983e65eSMilanka Ringwald } 247*6983e65eSMilanka Ringwald 248*6983e65eSMilanka Ringwald 249*6983e65eSMilanka Ringwald static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){ 250*6983e65eSMilanka Ringwald uint8_t operands[20]; 251*6983e65eSMilanka Ringwald uint8_t opcode; 252*6983e65eSMilanka Ringwald int pos = 3; 253*6983e65eSMilanka Ringwald // uint8_t transport_header = packet[0]; 254*6983e65eSMilanka Ringwald // uint8_t transaction_label = transport_header >> 4; 255*6983e65eSMilanka Ringwald // uint8_t packet_type = (transport_header & 0x0F) >> 2; 256*6983e65eSMilanka Ringwald // uint8_t frame_type = (transport_header & 0x03) >> 1; 257*6983e65eSMilanka Ringwald // uint8_t ipid = transport_header & 0x01; 258*6983e65eSMilanka Ringwald // uint8_t byte_value = packet[2]; 259*6983e65eSMilanka Ringwald // uint16_t pid = (byte_value << 8) | packet[2]; 260*6983e65eSMilanka Ringwald 261*6983e65eSMilanka Ringwald avrcp_command_type_t ctype = (avrcp_command_type_t) packet[pos++]; 262*6983e65eSMilanka Ringwald uint8_t byte_value = packet[pos++]; 263*6983e65eSMilanka Ringwald avrcp_subunit_type_t subunit_type = (avrcp_subunit_type_t) (byte_value >> 3); 264*6983e65eSMilanka Ringwald avrcp_subunit_type_t subunit_id = (avrcp_subunit_type_t) (byte_value & 0x07); 265*6983e65eSMilanka Ringwald opcode = packet[pos++]; 266*6983e65eSMilanka Ringwald 267*6983e65eSMilanka Ringwald // printf(" Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n", 268*6983e65eSMilanka Ringwald // transport_header, transaction_label, packet_type, frame_type, ipid, pid); 269*6983e65eSMilanka Ringwald // // printf_hexdump(packet+pos, size-pos); 270*6983e65eSMilanka Ringwald 271*6983e65eSMilanka Ringwald uint8_t pdu_id; 272*6983e65eSMilanka Ringwald uint16_t param_length; 273*6983e65eSMilanka Ringwald switch (avrcp_cmd_opcode(packet,size)){ 274*6983e65eSMilanka Ringwald case AVRCP_CMD_OPCODE_UNIT_INFO:{ 275*6983e65eSMilanka Ringwald if (connection->state != AVCTP_W2_RECEIVE_RESPONSE) return; 276*6983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 277*6983e65eSMilanka Ringwald 278*6983e65eSMilanka Ringwald // operands: 279*6983e65eSMilanka Ringwald memcpy(operands, packet+pos, 5); 280*6983e65eSMilanka Ringwald uint8_t unit_type = operands[1] >> 3; 281*6983e65eSMilanka Ringwald uint8_t unit = operands[1] & 0x07; 282*6983e65eSMilanka Ringwald uint32_t company_id = operands[2] << 16 | operands[3] << 8 | operands[4]; 283*6983e65eSMilanka Ringwald log_info(" UNIT INFO response: ctype 0x%02x (0C), subunit_type 0x%02x (1F), subunit_id 0x%02x (07), opcode 0x%02x (30), unit_type 0x%02x, unit %d, company_id 0x%06x", 284*6983e65eSMilanka Ringwald ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id ); 285*6983e65eSMilanka Ringwald break; 286*6983e65eSMilanka Ringwald } 287*6983e65eSMilanka Ringwald case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: 288*6983e65eSMilanka Ringwald if (size - pos < 7) { 289*6983e65eSMilanka Ringwald log_error("avrcp: wrong packet size"); 290*6983e65eSMilanka Ringwald return; 291*6983e65eSMilanka Ringwald }; 292*6983e65eSMilanka Ringwald // operands: 293*6983e65eSMilanka Ringwald memcpy(operands, packet+pos, 7); 294*6983e65eSMilanka Ringwald pos += 7; 295*6983e65eSMilanka Ringwald // uint32_t company_id = operands[0] << 16 | operands[1] << 8 | operands[2]; 296*6983e65eSMilanka Ringwald pdu_id = operands[3]; 297*6983e65eSMilanka Ringwald 298*6983e65eSMilanka Ringwald if (connection->state != AVCTP_W2_RECEIVE_RESPONSE && pdu_id != AVRCP_PDU_ID_REGISTER_NOTIFICATION){ 299*6983e65eSMilanka Ringwald log_info("AVRCP_CMD_OPCODE_VENDOR_DEPENDENT state %d", connection->state); 300*6983e65eSMilanka Ringwald return; 301*6983e65eSMilanka Ringwald } 302*6983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 303*6983e65eSMilanka Ringwald 304*6983e65eSMilanka Ringwald 305*6983e65eSMilanka Ringwald // uint8_t unit_type = operands[4] >> 3; 306*6983e65eSMilanka Ringwald // uint8_t unit = operands[4] & 0x07; 307*6983e65eSMilanka Ringwald param_length = big_endian_read_16(operands, 5); 308*6983e65eSMilanka Ringwald 309*6983e65eSMilanka Ringwald // printf(" VENDOR DEPENDENT response: ctype 0x%02x (0C), subunit_type 0x%02x (1F), subunit_id 0x%02x (07), opcode 0x%02x (30), unit_type 0x%02x, unit %d, company_id 0x%06x\n", 310*6983e65eSMilanka Ringwald // ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id ); 311*6983e65eSMilanka Ringwald 312*6983e65eSMilanka Ringwald // if (ctype == AVRCP_CTYPE_RESPONSE_INTERIM) return; 313*6983e65eSMilanka Ringwald log_info(" VENDOR DEPENDENT response: pdu id 0x%02x, param_length %d, status %s", pdu_id, param_length, avrcp_ctype2str(ctype)); 314*6983e65eSMilanka Ringwald switch (pdu_id){ 315*6983e65eSMilanka Ringwald case AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue:{ 316*6983e65eSMilanka Ringwald uint8_t num_attributes = packet[pos++]; 317*6983e65eSMilanka Ringwald int i; 318*6983e65eSMilanka Ringwald avrcp_repeat_mode_t repeat_mode = AVRCP_REPEAT_MODE_INVALID; 319*6983e65eSMilanka Ringwald avrcp_shuffle_mode_t shuffle_mode = AVRCP_SHUFFLE_MODE_INVALID; 320*6983e65eSMilanka Ringwald for (i = 0; i < num_attributes; i++){ 321*6983e65eSMilanka Ringwald uint8_t attribute_id = packet[pos++]; 322*6983e65eSMilanka Ringwald uint8_t value = packet[pos++]; 323*6983e65eSMilanka Ringwald switch (attribute_id){ 324*6983e65eSMilanka Ringwald case 0x02: 325*6983e65eSMilanka Ringwald repeat_mode = (avrcp_repeat_mode_t) value; 326*6983e65eSMilanka Ringwald break; 327*6983e65eSMilanka Ringwald case 0x03: 328*6983e65eSMilanka Ringwald shuffle_mode = (avrcp_shuffle_mode_t) value; 329*6983e65eSMilanka Ringwald break; 330*6983e65eSMilanka Ringwald default: 331*6983e65eSMilanka Ringwald break; 332*6983e65eSMilanka Ringwald } 333*6983e65eSMilanka Ringwald } 334*6983e65eSMilanka Ringwald avrcp_emit_repeat_and_shuffle_mode(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, repeat_mode, shuffle_mode); 335*6983e65eSMilanka Ringwald break; 336*6983e65eSMilanka Ringwald } 337*6983e65eSMilanka Ringwald case AVRCP_PDU_ID_SetPlayerApplicationSettingValue:{ 338*6983e65eSMilanka Ringwald uint8_t event[6]; 339*6983e65eSMilanka Ringwald int offset = 0; 340*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 341*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 342*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE; 343*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 344*6983e65eSMilanka Ringwald offset += 2; 345*6983e65eSMilanka Ringwald event[offset++] = ctype; 346*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 347*6983e65eSMilanka Ringwald break; 348*6983e65eSMilanka Ringwald } 349*6983e65eSMilanka Ringwald case AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME:{ 350*6983e65eSMilanka Ringwald uint8_t event[7]; 351*6983e65eSMilanka Ringwald int offset = 0; 352*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 353*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 354*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE; 355*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 356*6983e65eSMilanka Ringwald offset += 2; 357*6983e65eSMilanka Ringwald event[offset++] = ctype; 358*6983e65eSMilanka Ringwald event[offset++] = packet[pos++]; 359*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 360*6983e65eSMilanka Ringwald break; 361*6983e65eSMilanka Ringwald } 362*6983e65eSMilanka Ringwald case AVRCP_PDU_ID_GET_CAPABILITIES:{ 363*6983e65eSMilanka Ringwald avrcp_capability_id_t capability_id = (avrcp_capability_id_t) packet[pos++]; 364*6983e65eSMilanka Ringwald uint8_t capability_count = packet[pos++]; 365*6983e65eSMilanka Ringwald int i; 366*6983e65eSMilanka Ringwald switch (capability_id){ 367*6983e65eSMilanka Ringwald case AVRCP_CAPABILITY_ID_COMPANY: 368*6983e65eSMilanka Ringwald // log_info("Supported companies %d: ", capability_count); 369*6983e65eSMilanka Ringwald for (i = 0; i < capability_count; i++){ 370*6983e65eSMilanka Ringwald uint32_t company_id = big_endian_read_24(packet, pos); 371*6983e65eSMilanka Ringwald pos += 3; 372*6983e65eSMilanka Ringwald log_info(" 0x%06x, ", company_id); 373*6983e65eSMilanka Ringwald } 374*6983e65eSMilanka Ringwald break; 375*6983e65eSMilanka Ringwald case AVRCP_CAPABILITY_ID_EVENT: 376*6983e65eSMilanka Ringwald // log_info("Supported events %d: ", capability_count); 377*6983e65eSMilanka Ringwald for (i = 0; i < capability_count; i++){ 378*6983e65eSMilanka Ringwald uint8_t event_id = packet[pos++]; 379*6983e65eSMilanka Ringwald log_info(" 0x%02x %s", event_id, avrcp_event2str(event_id)); 380*6983e65eSMilanka Ringwald } 381*6983e65eSMilanka Ringwald break; 382*6983e65eSMilanka Ringwald } 383*6983e65eSMilanka Ringwald break; 384*6983e65eSMilanka Ringwald } 385*6983e65eSMilanka Ringwald case AVRCP_PDU_ID_GET_PLAY_STATUS:{ 386*6983e65eSMilanka Ringwald uint32_t song_length = big_endian_read_32(packet, pos); 387*6983e65eSMilanka Ringwald pos += 4; 388*6983e65eSMilanka Ringwald uint32_t song_position = big_endian_read_32(packet, pos); 389*6983e65eSMilanka Ringwald pos += 4; 390*6983e65eSMilanka Ringwald uint8_t play_status = packet[pos]; 391*6983e65eSMilanka Ringwald // log_info(" GET_PLAY_STATUS length 0x%04X, position 0x%04X, status %s", song_length, song_position, avrcp_play_status2str(play_status)); 392*6983e65eSMilanka Ringwald 393*6983e65eSMilanka Ringwald uint8_t event[15]; 394*6983e65eSMilanka Ringwald int offset = 0; 395*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 396*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 397*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_PLAY_STATUS; 398*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 399*6983e65eSMilanka Ringwald offset += 2; 400*6983e65eSMilanka Ringwald event[offset++] = ctype; 401*6983e65eSMilanka Ringwald little_endian_store_32(event, offset, song_length); 402*6983e65eSMilanka Ringwald offset += 4; 403*6983e65eSMilanka Ringwald little_endian_store_32(event, offset, song_position); 404*6983e65eSMilanka Ringwald offset += 4; 405*6983e65eSMilanka Ringwald event[offset++] = play_status; 406*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 407*6983e65eSMilanka Ringwald break; 408*6983e65eSMilanka Ringwald } 409*6983e65eSMilanka Ringwald case AVRCP_PDU_ID_REGISTER_NOTIFICATION:{ 410*6983e65eSMilanka Ringwald avrcp_notification_event_id_t event_id = (avrcp_notification_event_id_t) packet[pos++]; 411*6983e65eSMilanka Ringwald uint16_t event_mask = (1 << event_id); 412*6983e65eSMilanka Ringwald uint16_t reset_event_mask = ~event_mask; 413*6983e65eSMilanka Ringwald switch (ctype){ 414*6983e65eSMilanka Ringwald case AVRCP_CTYPE_RESPONSE_INTERIM: 415*6983e65eSMilanka Ringwald // register as enabled 416*6983e65eSMilanka Ringwald connection->notifications_enabled |= event_mask; 417*6983e65eSMilanka Ringwald // printf("INTERIM notifications_enabled 0x%2x, notifications_to_register 0x%2x\n", connection->notifications_enabled, connection->notifications_to_register); 418*6983e65eSMilanka Ringwald break; 419*6983e65eSMilanka Ringwald case AVRCP_CTYPE_RESPONSE_CHANGED_STABLE: 420*6983e65eSMilanka Ringwald // received change, event is considered deregistered 421*6983e65eSMilanka Ringwald // we are re-enabling it automatically, if it is not 422*6983e65eSMilanka Ringwald // explicitly disabled 423*6983e65eSMilanka Ringwald connection->notifications_enabled &= reset_event_mask; 424*6983e65eSMilanka Ringwald if (! (connection->notifications_to_deregister & event_mask)){ 425*6983e65eSMilanka Ringwald avrcp_register_notification(connection, event_id); 426*6983e65eSMilanka Ringwald // printf("CHANGED_STABLE notifications_enabled 0x%2x, notifications_to_register 0x%2x\n", connection->notifications_enabled, connection->notifications_to_register); 427*6983e65eSMilanka Ringwald } else { 428*6983e65eSMilanka Ringwald connection->notifications_to_deregister &= reset_event_mask; 429*6983e65eSMilanka Ringwald } 430*6983e65eSMilanka Ringwald break; 431*6983e65eSMilanka Ringwald default: 432*6983e65eSMilanka Ringwald connection->notifications_to_register &= reset_event_mask; 433*6983e65eSMilanka Ringwald connection->notifications_enabled &= reset_event_mask; 434*6983e65eSMilanka Ringwald connection->notifications_to_deregister &= reset_event_mask; 435*6983e65eSMilanka Ringwald break; 436*6983e65eSMilanka Ringwald } 437*6983e65eSMilanka Ringwald 438*6983e65eSMilanka Ringwald switch (event_id){ 439*6983e65eSMilanka Ringwald case AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED:{ 440*6983e65eSMilanka Ringwald uint8_t event[7]; 441*6983e65eSMilanka Ringwald int offset = 0; 442*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 443*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 444*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_PLAYBACK_STATUS_CHANGED; 445*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 446*6983e65eSMilanka Ringwald offset += 2; 447*6983e65eSMilanka Ringwald event[offset++] = ctype; 448*6983e65eSMilanka Ringwald event[offset++] = packet[pos]; 449*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 450*6983e65eSMilanka Ringwald break; 451*6983e65eSMilanka Ringwald } 452*6983e65eSMilanka Ringwald case AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED:{ 453*6983e65eSMilanka Ringwald uint8_t event[6]; 454*6983e65eSMilanka Ringwald int offset = 0; 455*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 456*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 457*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED; 458*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 459*6983e65eSMilanka Ringwald offset += 2; 460*6983e65eSMilanka Ringwald event[offset++] = ctype; 461*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 462*6983e65eSMilanka Ringwald break; 463*6983e65eSMilanka Ringwald } 464*6983e65eSMilanka Ringwald case AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED:{ 465*6983e65eSMilanka Ringwald uint8_t event[6]; 466*6983e65eSMilanka Ringwald int offset = 0; 467*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 468*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 469*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_NOW_PLAYING_CONTENT_CHANGED; 470*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 471*6983e65eSMilanka Ringwald offset += 2; 472*6983e65eSMilanka Ringwald event[offset++] = ctype; 473*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 474*6983e65eSMilanka Ringwald break; 475*6983e65eSMilanka Ringwald } 476*6983e65eSMilanka Ringwald case AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED:{ 477*6983e65eSMilanka Ringwald uint8_t event[6]; 478*6983e65eSMilanka Ringwald int offset = 0; 479*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 480*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 481*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_AVAILABLE_PLAYERS_CHANGED; 482*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 483*6983e65eSMilanka Ringwald offset += 2; 484*6983e65eSMilanka Ringwald event[offset++] = ctype; 485*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 486*6983e65eSMilanka Ringwald break; 487*6983e65eSMilanka Ringwald } 488*6983e65eSMilanka Ringwald case AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED:{ 489*6983e65eSMilanka Ringwald uint8_t event[7]; 490*6983e65eSMilanka Ringwald int offset = 0; 491*6983e65eSMilanka Ringwald event[offset++] = HCI_EVENT_AVRCP_META; 492*6983e65eSMilanka Ringwald event[offset++] = sizeof(event) - 2; 493*6983e65eSMilanka Ringwald event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED; 494*6983e65eSMilanka Ringwald little_endian_store_16(event, offset, connection->avrcp_cid); 495*6983e65eSMilanka Ringwald offset += 2; 496*6983e65eSMilanka Ringwald event[offset++] = ctype; 497*6983e65eSMilanka Ringwald event[offset++] = packet[pos++] & 0x7F; 498*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 499*6983e65eSMilanka Ringwald break; 500*6983e65eSMilanka Ringwald } 501*6983e65eSMilanka Ringwald // case AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:{ 502*6983e65eSMilanka Ringwald // uint8_t num_PlayerApplicationSettingAttributes = packet[pos++]; 503*6983e65eSMilanka Ringwald // int i; 504*6983e65eSMilanka Ringwald // for (i = 0; i < num_PlayerApplicationSettingAttributes; i++){ 505*6983e65eSMilanka Ringwald // uint8_t PlayerApplicationSetting_AttributeID = packet[pos++]; 506*6983e65eSMilanka Ringwald // uint8_t PlayerApplicationSettingValueID = packet[pos++]; 507*6983e65eSMilanka Ringwald // } 508*6983e65eSMilanka Ringwald // break; 509*6983e65eSMilanka Ringwald // } 510*6983e65eSMilanka Ringwald // case AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED: 511*6983e65eSMilanka Ringwald // uint16_t player_id = big_endian_read_16(packet, pos); 512*6983e65eSMilanka Ringwald // pos += 2; 513*6983e65eSMilanka Ringwald // uint16_t uid_counter = big_endian_read_16(packet, pos); 514*6983e65eSMilanka Ringwald // pos += 2; 515*6983e65eSMilanka Ringwald // break; 516*6983e65eSMilanka Ringwald // case AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED: 517*6983e65eSMilanka Ringwald // uint16_t uid_counter = big_endian_read_16(packet, pos); 518*6983e65eSMilanka Ringwald // pos += 2; 519*6983e65eSMilanka Ringwald // break; 520*6983e65eSMilanka Ringwald default: 521*6983e65eSMilanka Ringwald log_info("avrcp: not implemented"); 522*6983e65eSMilanka Ringwald break; 523*6983e65eSMilanka Ringwald } 524*6983e65eSMilanka Ringwald if (connection->notifications_to_register != 0){ 525*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 526*6983e65eSMilanka Ringwald } 527*6983e65eSMilanka Ringwald break; 528*6983e65eSMilanka Ringwald } 529*6983e65eSMilanka Ringwald 530*6983e65eSMilanka Ringwald case AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES:{ 531*6983e65eSMilanka Ringwald uint8_t num_attributes = packet[pos++]; 532*6983e65eSMilanka Ringwald int i; 533*6983e65eSMilanka Ringwald struct item { 534*6983e65eSMilanka Ringwald uint16_t len; 535*6983e65eSMilanka Ringwald uint8_t * value; 536*6983e65eSMilanka Ringwald } items[AVRCP_MEDIA_ATTR_COUNT]; 537*6983e65eSMilanka Ringwald memset(items, 0, sizeof(items)); 538*6983e65eSMilanka Ringwald 539*6983e65eSMilanka Ringwald uint16_t string_attributes_len = 0; 540*6983e65eSMilanka Ringwald uint8_t num_string_attributes = 0; 541*6983e65eSMilanka Ringwald uint16_t total_event_payload_for_string_attributes = HCI_EVENT_PAYLOAD_SIZE-2; 542*6983e65eSMilanka Ringwald uint16_t max_string_attribute_value_len = 0; 543*6983e65eSMilanka Ringwald if (ctype == AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE || ctype == AVRCP_CTYPE_RESPONSE_CHANGED_STABLE){ 544*6983e65eSMilanka Ringwald for (i = 0; i < num_attributes; i++){ 545*6983e65eSMilanka Ringwald avrcp_media_attribute_id_t attr_id = (avrcp_media_attribute_id_t) big_endian_read_32(packet, pos); 546*6983e65eSMilanka Ringwald pos += 4; 547*6983e65eSMilanka Ringwald // uint16_t character_set = big_endian_read_16(packet, pos); 548*6983e65eSMilanka Ringwald pos += 2; 549*6983e65eSMilanka Ringwald uint16_t attr_value_length = big_endian_read_16(packet, pos); 550*6983e65eSMilanka Ringwald pos += 2; 551*6983e65eSMilanka Ringwald 552*6983e65eSMilanka Ringwald // debug - to remove later 553*6983e65eSMilanka Ringwald uint8_t value[100]; 554*6983e65eSMilanka Ringwald uint16_t value_len = sizeof(value) <= attr_value_length? sizeof(value) - 1 : attr_value_length; 555*6983e65eSMilanka Ringwald memcpy(value, packet+pos, value_len); 556*6983e65eSMilanka Ringwald value[value_len] = 0; 557*6983e65eSMilanka Ringwald // printf("Now Playing Info %s: %s \n", attribute2str(attr_id), value); 558*6983e65eSMilanka Ringwald // end debug 559*6983e65eSMilanka Ringwald 560*6983e65eSMilanka Ringwald if ((attr_id >= 1) || (attr_id <= AVRCP_MEDIA_ATTR_COUNT)) { 561*6983e65eSMilanka Ringwald items[attr_id-1].len = attr_value_length; 562*6983e65eSMilanka Ringwald items[attr_id-1].value = &packet[pos]; 563*6983e65eSMilanka Ringwald switch (attr_id){ 564*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_TITLE: 565*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_ARTIST: 566*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_ALBUM: 567*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_GENRE: 568*6983e65eSMilanka Ringwald num_string_attributes++; 569*6983e65eSMilanka Ringwald string_attributes_len += attr_value_length; 570*6983e65eSMilanka Ringwald if (max_string_attribute_value_len < attr_value_length){ 571*6983e65eSMilanka Ringwald max_string_attribute_value_len = attr_value_length; 572*6983e65eSMilanka Ringwald } 573*6983e65eSMilanka Ringwald break; 574*6983e65eSMilanka Ringwald default: 575*6983e65eSMilanka Ringwald break; 576*6983e65eSMilanka Ringwald } 577*6983e65eSMilanka Ringwald } 578*6983e65eSMilanka Ringwald pos += attr_value_length; 579*6983e65eSMilanka Ringwald } 580*6983e65eSMilanka Ringwald } 581*6983e65eSMilanka Ringwald 582*6983e65eSMilanka Ringwald // subtract space for fixed fields 583*6983e65eSMilanka Ringwald total_event_payload_for_string_attributes -= 14 + 4; // 4 for '\0' 584*6983e65eSMilanka Ringwald 585*6983e65eSMilanka Ringwald // @TODO optimize space by repeatedly decreasing max_string_attribute_value_len until it fits into buffer instead of crude divion 586*6983e65eSMilanka Ringwald uint16_t max_value_len = total_event_payload_for_string_attributes > string_attributes_len? max_string_attribute_value_len : total_event_payload_for_string_attributes/(string_attributes_len+1) - 1; 587*6983e65eSMilanka Ringwald // printf("num_string_attributes %d, string_attributes_len %d, total_event_payload_for_string_attributes %d, max_value_len %d \n", num_string_attributes, string_attributes_len, total_event_payload_for_string_attributes, max_value_len); 588*6983e65eSMilanka Ringwald 589*6983e65eSMilanka Ringwald const uint8_t attribute_order[] = { 590*6983e65eSMilanka Ringwald AVRCP_MEDIA_ATTR_TRACK, 591*6983e65eSMilanka Ringwald AVRCP_MEDIA_ATTR_TOTAL_TRACKS, 592*6983e65eSMilanka Ringwald AVRCP_MEDIA_ATTR_SONG_LENGTH, 593*6983e65eSMilanka Ringwald AVRCP_MEDIA_ATTR_TITLE, 594*6983e65eSMilanka Ringwald AVRCP_MEDIA_ATTR_ARTIST, 595*6983e65eSMilanka Ringwald AVRCP_MEDIA_ATTR_ALBUM, 596*6983e65eSMilanka Ringwald AVRCP_MEDIA_ATTR_GENRE 597*6983e65eSMilanka Ringwald }; 598*6983e65eSMilanka Ringwald 599*6983e65eSMilanka Ringwald uint8_t event[HCI_EVENT_BUFFER_SIZE]; 600*6983e65eSMilanka Ringwald event[0] = HCI_EVENT_AVRCP_META; 601*6983e65eSMilanka Ringwald pos = 2; 602*6983e65eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_NOW_PLAYING_INFO; 603*6983e65eSMilanka Ringwald little_endian_store_16(event, pos, connection->avrcp_cid); 604*6983e65eSMilanka Ringwald pos += 2; 605*6983e65eSMilanka Ringwald event[pos++] = ctype; 606*6983e65eSMilanka Ringwald for (i = 0; i < sizeof(attribute_order); i++){ 607*6983e65eSMilanka Ringwald avrcp_media_attribute_id_t attr_id = (avrcp_media_attribute_id_t) attribute_order[i]; 608*6983e65eSMilanka Ringwald uint16_t value_len = 0; 609*6983e65eSMilanka Ringwald switch (attr_id){ 610*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_TITLE: 611*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_ARTIST: 612*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_ALBUM: 613*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_GENRE: 614*6983e65eSMilanka Ringwald if (items[attr_id-1].value){ 615*6983e65eSMilanka Ringwald value_len = items[attr_id-1].len <= max_value_len ? items[attr_id-1].len : max_value_len; 616*6983e65eSMilanka Ringwald } 617*6983e65eSMilanka Ringwald event[pos++] = value_len + 1; 618*6983e65eSMilanka Ringwald if (value_len){ 619*6983e65eSMilanka Ringwald memcpy(event+pos, items[attr_id-1].value, value_len); 620*6983e65eSMilanka Ringwald pos += value_len; 621*6983e65eSMilanka Ringwald } 622*6983e65eSMilanka Ringwald event[pos++] = 0; 623*6983e65eSMilanka Ringwald break; 624*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_SONG_LENGTH: 625*6983e65eSMilanka Ringwald if (items[attr_id-1].value){ 626*6983e65eSMilanka Ringwald little_endian_store_32(event, pos, btstack_atoi((char *)items[attr_id-1].value)); 627*6983e65eSMilanka Ringwald } else { 628*6983e65eSMilanka Ringwald little_endian_store_32(event, pos, 0); 629*6983e65eSMilanka Ringwald } 630*6983e65eSMilanka Ringwald pos += 4; 631*6983e65eSMilanka Ringwald break; 632*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_TRACK: 633*6983e65eSMilanka Ringwald case AVRCP_MEDIA_ATTR_TOTAL_TRACKS: 634*6983e65eSMilanka Ringwald if (items[attr_id-1].value){ 635*6983e65eSMilanka Ringwald event[pos++] = btstack_atoi((char *)items[attr_id-1].value); 636*6983e65eSMilanka Ringwald } else { 637*6983e65eSMilanka Ringwald event[pos++] = 0; 638*6983e65eSMilanka Ringwald } 639*6983e65eSMilanka Ringwald break; 640*6983e65eSMilanka Ringwald } 641*6983e65eSMilanka Ringwald } 642*6983e65eSMilanka Ringwald event[1] = pos - 2; 643*6983e65eSMilanka Ringwald // printf_hexdump(event, pos); 644*6983e65eSMilanka Ringwald (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, pos); 645*6983e65eSMilanka Ringwald break; 646*6983e65eSMilanka Ringwald } 647*6983e65eSMilanka Ringwald default: 648*6983e65eSMilanka Ringwald break; 649*6983e65eSMilanka Ringwald } 650*6983e65eSMilanka Ringwald break; 651*6983e65eSMilanka Ringwald case AVRCP_CMD_OPCODE_PASS_THROUGH:{ 652*6983e65eSMilanka Ringwald // 0x80 | connection->cmd_operands[0] 653*6983e65eSMilanka Ringwald uint8_t operation_id = packet[pos++]; 654*6983e65eSMilanka Ringwald switch (connection->state){ 655*6983e65eSMilanka Ringwald case AVCTP_W2_RECEIVE_PRESS_RESPONSE: 656*6983e65eSMilanka Ringwald if (connection->continuous_fast_forward_cmd){ 657*6983e65eSMilanka Ringwald connection->state = AVCTP_W4_STOP; 658*6983e65eSMilanka Ringwald } else { 659*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_RELEASE_COMMAND; 660*6983e65eSMilanka Ringwald } 661*6983e65eSMilanka Ringwald break; 662*6983e65eSMilanka Ringwald case AVCTP_W2_RECEIVE_RESPONSE: 663*6983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 664*6983e65eSMilanka Ringwald break; 665*6983e65eSMilanka Ringwald default: 666*6983e65eSMilanka Ringwald // check for notifications? move state transition down 667*6983e65eSMilanka Ringwald // log_info("AVRCP_CMD_OPCODE_PASS_THROUGH state %d\n", connection->state); 668*6983e65eSMilanka Ringwald break; 669*6983e65eSMilanka Ringwald } 670*6983e65eSMilanka Ringwald if (connection->state == AVCTP_W4_STOP){ 671*6983e65eSMilanka Ringwald avrcp_emit_operation_status(avrcp_controller_context.avrcp_callback, AVRCP_SUBEVENT_OPERATION_START, connection->avrcp_cid, ctype, operation_id); 672*6983e65eSMilanka Ringwald } 673*6983e65eSMilanka Ringwald if (connection->state == AVCTP_CONNECTION_OPENED) { 674*6983e65eSMilanka Ringwald // RELEASE response 675*6983e65eSMilanka Ringwald operation_id = operation_id & 0x7F; 676*6983e65eSMilanka Ringwald avrcp_emit_operation_status(avrcp_controller_context.avrcp_callback, AVRCP_SUBEVENT_OPERATION_COMPLETE, connection->avrcp_cid, ctype, operation_id); 677*6983e65eSMilanka Ringwald } 678*6983e65eSMilanka Ringwald if (connection->state == AVCTP_W2_SEND_RELEASE_COMMAND){ 679*6983e65eSMilanka Ringwald // PRESS response 680*6983e65eSMilanka Ringwald request_pass_through_release_control_cmd(connection); 681*6983e65eSMilanka Ringwald } 682*6983e65eSMilanka Ringwald break; 683*6983e65eSMilanka Ringwald } 684*6983e65eSMilanka Ringwald default: 685*6983e65eSMilanka Ringwald break; 686*6983e65eSMilanka Ringwald } 687*6983e65eSMilanka Ringwald } 688*6983e65eSMilanka Ringwald 689*6983e65eSMilanka Ringwald static void avrcp_controller_handle_can_send_now(avrcp_connection_t * connection){ 690*6983e65eSMilanka Ringwald int i; 691*6983e65eSMilanka Ringwald switch (connection->state){ 692*6983e65eSMilanka Ringwald case AVCTP_W2_SEND_PRESS_COMMAND: 693*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_RECEIVE_PRESS_RESPONSE; 694*6983e65eSMilanka Ringwald avrcp_send_cmd(connection->l2cap_signaling_cid, connection); 695*6983e65eSMilanka Ringwald break; 696*6983e65eSMilanka Ringwald case AVCTP_W2_SEND_COMMAND: 697*6983e65eSMilanka Ringwald case AVCTP_W2_SEND_RELEASE_COMMAND: 698*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_RECEIVE_RESPONSE; 699*6983e65eSMilanka Ringwald avrcp_send_cmd(connection->l2cap_signaling_cid, connection); 700*6983e65eSMilanka Ringwald break; 701*6983e65eSMilanka Ringwald case AVCTP_CONNECTION_OPENED: 702*6983e65eSMilanka Ringwald if (connection->notifications_to_register != 0){ 703*6983e65eSMilanka Ringwald for (i = 1; i <= AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED; i++){ 704*6983e65eSMilanka Ringwald if (connection->notifications_to_register & (1<<i)){ 705*6983e65eSMilanka Ringwald connection->notifications_to_register &= ~ (1 << i); 706*6983e65eSMilanka Ringwald avrcp_prepare_notification(connection, (avrcp_notification_event_id_t) i); 707*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_RECEIVE_RESPONSE; 708*6983e65eSMilanka Ringwald avrcp_send_cmd(connection->l2cap_signaling_cid, connection); 709*6983e65eSMilanka Ringwald return; 710*6983e65eSMilanka Ringwald } 711*6983e65eSMilanka Ringwald } 712*6983e65eSMilanka Ringwald } 713*6983e65eSMilanka Ringwald return; 714*6983e65eSMilanka Ringwald default: 715*6983e65eSMilanka Ringwald return; 716*6983e65eSMilanka Ringwald } 717*6983e65eSMilanka Ringwald } 718*6983e65eSMilanka Ringwald 719*6983e65eSMilanka Ringwald static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 720*6983e65eSMilanka Ringwald avrcp_connection_t * connection; 721*6983e65eSMilanka Ringwald 722*6983e65eSMilanka Ringwald switch (packet_type) { 723*6983e65eSMilanka Ringwald case L2CAP_DATA_PACKET: 724*6983e65eSMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_controller_context); 725*6983e65eSMilanka Ringwald if (!connection) break; 726*6983e65eSMilanka Ringwald avrcp_handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 727*6983e65eSMilanka Ringwald break; 728*6983e65eSMilanka Ringwald case HCI_EVENT_PACKET: 729*6983e65eSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 730*6983e65eSMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 731*6983e65eSMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_controller_context); 732*6983e65eSMilanka Ringwald if (!connection) break; 733*6983e65eSMilanka Ringwald avrcp_controller_handle_can_send_now(connection); 734*6983e65eSMilanka Ringwald break; 735*6983e65eSMilanka Ringwald default: 736*6983e65eSMilanka Ringwald avrcp_packet_handler(packet_type, channel, packet, size, &avrcp_controller_context); 737*6983e65eSMilanka Ringwald break; 738*6983e65eSMilanka Ringwald } 739*6983e65eSMilanka Ringwald default: 740*6983e65eSMilanka Ringwald break; 741*6983e65eSMilanka Ringwald } 742*6983e65eSMilanka Ringwald } 743*6983e65eSMilanka Ringwald 744*6983e65eSMilanka Ringwald void avrcp_controller_init(void){ 745*6983e65eSMilanka Ringwald avrcp_controller_context.role = AVRCP_CONTROLLER; 746*6983e65eSMilanka Ringwald avrcp_controller_context.connections = NULL; 747*6983e65eSMilanka Ringwald avrcp_controller_context.packet_handler = avrcp_controller_packet_handler; 748*6983e65eSMilanka Ringwald l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0); 749*6983e65eSMilanka Ringwald } 750*6983e65eSMilanka Ringwald 751*6983e65eSMilanka Ringwald void avrcp_controller_register_packet_handler(btstack_packet_handler_t callback){ 752*6983e65eSMilanka Ringwald if (callback == NULL){ 753*6983e65eSMilanka Ringwald log_error("avrcp_register_packet_handler called with NULL callback"); 754*6983e65eSMilanka Ringwald return; 755*6983e65eSMilanka Ringwald } 756*6983e65eSMilanka Ringwald avrcp_controller_context.avrcp_callback = callback; 757*6983e65eSMilanka Ringwald } 758*6983e65eSMilanka Ringwald 759*6983e65eSMilanka Ringwald uint8_t avrcp_controller_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid){ 760*6983e65eSMilanka Ringwald return avrcp_connect(bd_addr, &avrcp_controller_context, avrcp_cid); 761*6983e65eSMilanka Ringwald } 762*6983e65eSMilanka Ringwald 763*6983e65eSMilanka Ringwald uint8_t avrcp_controller_unit_info(uint16_t avrcp_cid){ 764*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 765*6983e65eSMilanka Ringwald if (!connection){ 766*6983e65eSMilanka Ringwald log_error("avrcp_unit_info: could not find a connection."); 767*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 768*6983e65eSMilanka Ringwald } 769*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 770*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_COMMAND; 771*6983e65eSMilanka Ringwald 772*6983e65eSMilanka Ringwald connection->transaction_label++; 773*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_UNIT_INFO; 774*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_STATUS; 775*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT; //vendor unique 776*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; 777*6983e65eSMilanka Ringwald memset(connection->cmd_operands, 0xFF, connection->cmd_operands_length); 778*6983e65eSMilanka Ringwald connection->cmd_operands_length = 5; 779*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 780*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 781*6983e65eSMilanka Ringwald } 782*6983e65eSMilanka Ringwald 783*6983e65eSMilanka Ringwald static uint8_t avrcp_controller_get_capabilities(uint16_t avrcp_cid, uint8_t capability_id){ 784*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 785*6983e65eSMilanka Ringwald if (!connection){ 786*6983e65eSMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 787*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 788*6983e65eSMilanka Ringwald } 789*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 790*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_COMMAND; 791*6983e65eSMilanka Ringwald 792*6983e65eSMilanka Ringwald connection->transaction_label++; 793*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 794*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_STATUS; 795*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 796*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 797*6983e65eSMilanka Ringwald big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); 798*6983e65eSMilanka Ringwald connection->cmd_operands[3] = AVRCP_PDU_ID_GET_CAPABILITIES; // PDU ID 799*6983e65eSMilanka Ringwald connection->cmd_operands[4] = 0; 800*6983e65eSMilanka Ringwald big_endian_store_16(connection->cmd_operands, 5, 1); // parameter length 801*6983e65eSMilanka Ringwald connection->cmd_operands[7] = capability_id; // capability ID 802*6983e65eSMilanka Ringwald connection->cmd_operands_length = 8; 803*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 804*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 805*6983e65eSMilanka Ringwald } 806*6983e65eSMilanka Ringwald 807*6983e65eSMilanka Ringwald uint8_t avrcp_controller_get_supported_company_ids(uint16_t avrcp_cid){ 808*6983e65eSMilanka Ringwald return avrcp_controller_get_capabilities(avrcp_cid, AVRCP_CAPABILITY_ID_COMPANY); 809*6983e65eSMilanka Ringwald } 810*6983e65eSMilanka Ringwald 811*6983e65eSMilanka Ringwald uint8_t avrcp_controller_get_supported_events(uint16_t avrcp_cid){ 812*6983e65eSMilanka Ringwald return avrcp_controller_get_capabilities(avrcp_cid, AVRCP_CAPABILITY_ID_EVENT); 813*6983e65eSMilanka Ringwald } 814*6983e65eSMilanka Ringwald 815*6983e65eSMilanka Ringwald 816*6983e65eSMilanka Ringwald uint8_t avrcp_controller_play(uint16_t avrcp_cid){ 817*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_PLAY, 0); 818*6983e65eSMilanka Ringwald } 819*6983e65eSMilanka Ringwald 820*6983e65eSMilanka Ringwald uint8_t avrcp_controller_stop(uint16_t avrcp_cid){ 821*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_STOP, 0); 822*6983e65eSMilanka Ringwald } 823*6983e65eSMilanka Ringwald 824*6983e65eSMilanka Ringwald uint8_t avrcp_controller_pause(uint16_t avrcp_cid){ 825*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_PAUSE, 0); 826*6983e65eSMilanka Ringwald } 827*6983e65eSMilanka Ringwald 828*6983e65eSMilanka Ringwald uint8_t avrcp_controller_forward(uint16_t avrcp_cid){ 829*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FORWARD, 0); 830*6983e65eSMilanka Ringwald } 831*6983e65eSMilanka Ringwald 832*6983e65eSMilanka Ringwald uint8_t avrcp_controller_backward(uint16_t avrcp_cid){ 833*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_BACKWARD, 0); 834*6983e65eSMilanka Ringwald } 835*6983e65eSMilanka Ringwald 836*6983e65eSMilanka Ringwald uint8_t avrcp_controller_start_rewind(uint16_t avrcp_cid){ 837*6983e65eSMilanka Ringwald return request_continuous_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_REWIND, 0); 838*6983e65eSMilanka Ringwald } 839*6983e65eSMilanka Ringwald 840*6983e65eSMilanka Ringwald uint8_t avrcp_controller_volume_up(uint16_t avrcp_cid){ 841*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_VOLUME_UP, 0); 842*6983e65eSMilanka Ringwald } 843*6983e65eSMilanka Ringwald 844*6983e65eSMilanka Ringwald uint8_t avrcp_controller_volume_down(uint16_t avrcp_cid){ 845*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_VOLUME_DOWN, 0); 846*6983e65eSMilanka Ringwald } 847*6983e65eSMilanka Ringwald 848*6983e65eSMilanka Ringwald uint8_t avrcp_controller_mute(uint16_t avrcp_cid){ 849*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_MUTE, 0); 850*6983e65eSMilanka Ringwald } 851*6983e65eSMilanka Ringwald 852*6983e65eSMilanka Ringwald uint8_t avrcp_controller_skip(uint16_t avrcp_cid){ 853*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_SKIP, 0); 854*6983e65eSMilanka Ringwald } 855*6983e65eSMilanka Ringwald 856*6983e65eSMilanka Ringwald uint8_t avrcp_controller_stop_rewind(uint16_t avrcp_cid){ 857*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 858*6983e65eSMilanka Ringwald if (!connection){ 859*6983e65eSMilanka Ringwald log_error("avrcp_stop_rewind: could not find a connection."); 860*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 861*6983e65eSMilanka Ringwald } 862*6983e65eSMilanka Ringwald if (connection->state != AVCTP_W4_STOP) return ERROR_CODE_COMMAND_DISALLOWED; 863*6983e65eSMilanka Ringwald return request_pass_through_release_control_cmd(connection); 864*6983e65eSMilanka Ringwald } 865*6983e65eSMilanka Ringwald 866*6983e65eSMilanka Ringwald uint8_t avrcp_controller_start_fast_forward(uint16_t avrcp_cid){ 867*6983e65eSMilanka Ringwald return request_continuous_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FAST_FORWARD, 0); 868*6983e65eSMilanka Ringwald } 869*6983e65eSMilanka Ringwald 870*6983e65eSMilanka Ringwald uint8_t avrcp_controller_fast_forward(uint16_t avrcp_cid){ 871*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FAST_FORWARD, 0); 872*6983e65eSMilanka Ringwald } 873*6983e65eSMilanka Ringwald 874*6983e65eSMilanka Ringwald uint8_t avrcp_controller_rewind(uint16_t avrcp_cid){ 875*6983e65eSMilanka Ringwald return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_REWIND, 0); 876*6983e65eSMilanka Ringwald } 877*6983e65eSMilanka Ringwald 878*6983e65eSMilanka Ringwald 879*6983e65eSMilanka Ringwald uint8_t avrcp_controller_stop_fast_forward(uint16_t avrcp_cid){ 880*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 881*6983e65eSMilanka Ringwald if (!connection){ 882*6983e65eSMilanka Ringwald log_error("avrcp_stop_fast_forward: could not find a connection."); 883*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 884*6983e65eSMilanka Ringwald } 885*6983e65eSMilanka Ringwald if (connection->state != AVCTP_W4_STOP) return ERROR_CODE_COMMAND_DISALLOWED; 886*6983e65eSMilanka Ringwald return request_pass_through_release_control_cmd(connection); 887*6983e65eSMilanka Ringwald } 888*6983e65eSMilanka Ringwald 889*6983e65eSMilanka Ringwald uint8_t avrcp_controller_get_play_status(uint16_t avrcp_cid){ 890*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 891*6983e65eSMilanka Ringwald if (!connection){ 892*6983e65eSMilanka Ringwald log_error("avrcp_get_play_status: could not find a connection."); 893*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 894*6983e65eSMilanka Ringwald } 895*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 896*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_COMMAND; 897*6983e65eSMilanka Ringwald connection->transaction_label++; 898*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 899*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_STATUS; 900*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 901*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 902*6983e65eSMilanka Ringwald big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); 903*6983e65eSMilanka Ringwald connection->cmd_operands[3] = AVRCP_PDU_ID_GET_PLAY_STATUS; 904*6983e65eSMilanka Ringwald connection->cmd_operands[4] = 0; // reserved(upper 6) | packet_type -> 0 905*6983e65eSMilanka Ringwald big_endian_store_16(connection->cmd_operands, 5, 0); // parameter length 906*6983e65eSMilanka Ringwald connection->cmd_operands_length = 7; 907*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 908*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 909*6983e65eSMilanka Ringwald } 910*6983e65eSMilanka Ringwald 911*6983e65eSMilanka Ringwald uint8_t avrcp_controller_enable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id){ 912*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 913*6983e65eSMilanka Ringwald if (!connection){ 914*6983e65eSMilanka Ringwald log_error("avrcp_get_play_status: could not find a connection."); 915*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 916*6983e65eSMilanka Ringwald } 917*6983e65eSMilanka Ringwald avrcp_register_notification(connection, event_id); 918*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 919*6983e65eSMilanka Ringwald } 920*6983e65eSMilanka Ringwald 921*6983e65eSMilanka Ringwald uint8_t avrcp_controller_disable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id){ 922*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 923*6983e65eSMilanka Ringwald if (!connection){ 924*6983e65eSMilanka Ringwald log_error("avrcp_get_play_status: could not find a connection."); 925*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 926*6983e65eSMilanka Ringwald } 927*6983e65eSMilanka Ringwald connection->notifications_to_deregister |= (1 << event_id); 928*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 929*6983e65eSMilanka Ringwald } 930*6983e65eSMilanka Ringwald 931*6983e65eSMilanka Ringwald uint8_t avrcp_controller_get_now_playing_info(uint16_t avrcp_cid){ 932*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 933*6983e65eSMilanka Ringwald if (!connection){ 934*6983e65eSMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 935*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 936*6983e65eSMilanka Ringwald } 937*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 938*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_COMMAND; 939*6983e65eSMilanka Ringwald 940*6983e65eSMilanka Ringwald connection->transaction_label++; 941*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 942*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_STATUS; 943*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 944*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 945*6983e65eSMilanka Ringwald int pos = 0; 946*6983e65eSMilanka Ringwald big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); 947*6983e65eSMilanka Ringwald pos += 3; 948*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES; // PDU ID 949*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = 0; 950*6983e65eSMilanka Ringwald 951*6983e65eSMilanka Ringwald // Parameter Length 952*6983e65eSMilanka Ringwald big_endian_store_16(connection->cmd_operands, pos, 9); 953*6983e65eSMilanka Ringwald pos += 2; 954*6983e65eSMilanka Ringwald 955*6983e65eSMilanka Ringwald // write 8 bytes value 956*6983e65eSMilanka Ringwald memset(connection->cmd_operands + pos, 0, 8); // identifier: PLAYING 957*6983e65eSMilanka Ringwald pos += 8; 958*6983e65eSMilanka Ringwald 959*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = 0; // attribute count, if 0 get all attributes 960*6983e65eSMilanka Ringwald // every attribute is 4 bytes long 961*6983e65eSMilanka Ringwald 962*6983e65eSMilanka Ringwald connection->cmd_operands_length = pos; 963*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 964*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 965*6983e65eSMilanka Ringwald } 966*6983e65eSMilanka Ringwald 967*6983e65eSMilanka Ringwald uint8_t avrcp_controller_set_absolute_volume(uint16_t avrcp_cid, uint8_t volume){ 968*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 969*6983e65eSMilanka Ringwald if (!connection){ 970*6983e65eSMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 971*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 972*6983e65eSMilanka Ringwald } 973*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 974*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_COMMAND; 975*6983e65eSMilanka Ringwald 976*6983e65eSMilanka Ringwald connection->transaction_label++; 977*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 978*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_CONTROL; 979*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 980*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 981*6983e65eSMilanka Ringwald int pos = 0; 982*6983e65eSMilanka Ringwald big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); 983*6983e65eSMilanka Ringwald pos += 3; 984*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME; // PDU ID 985*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = 0; 986*6983e65eSMilanka Ringwald 987*6983e65eSMilanka Ringwald // Parameter Length 988*6983e65eSMilanka Ringwald big_endian_store_16(connection->cmd_operands, pos, 1); 989*6983e65eSMilanka Ringwald pos += 2; 990*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = volume; 991*6983e65eSMilanka Ringwald 992*6983e65eSMilanka Ringwald connection->cmd_operands_length = pos; 993*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 994*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 995*6983e65eSMilanka Ringwald } 996*6983e65eSMilanka Ringwald 997*6983e65eSMilanka Ringwald uint8_t avrcp_controller_query_shuffle_and_repeat_modes(uint16_t avrcp_cid){ 998*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 999*6983e65eSMilanka Ringwald if (!connection){ 1000*6983e65eSMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 1001*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1002*6983e65eSMilanka Ringwald } 1003*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 1004*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_COMMAND; 1005*6983e65eSMilanka Ringwald 1006*6983e65eSMilanka Ringwald connection->transaction_label++; 1007*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 1008*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_STATUS; 1009*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 1010*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 1011*6983e65eSMilanka Ringwald big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); 1012*6983e65eSMilanka Ringwald connection->cmd_operands[3] = AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue; // PDU ID 1013*6983e65eSMilanka Ringwald connection->cmd_operands[4] = 0; 1014*6983e65eSMilanka Ringwald big_endian_store_16(connection->cmd_operands, 5, 5); // parameter length 1015*6983e65eSMilanka Ringwald connection->cmd_operands[7] = 4; // NumPlayerApplicationSettingAttributeID 1016*6983e65eSMilanka Ringwald // PlayerApplicationSettingAttributeID1 AVRCP Spec, Appendix F, 133 1017*6983e65eSMilanka Ringwald connection->cmd_operands[8] = 0x01; // equalizer (1-OFF, 2-ON) 1018*6983e65eSMilanka Ringwald connection->cmd_operands[9] = 0x02; // repeat (1-off, 2-single track, 3-all tracks, 4-group repeat) 1019*6983e65eSMilanka Ringwald connection->cmd_operands[10] = 0x03; // shuffle (1-off, 2-all tracks, 3-group shuffle) 1020*6983e65eSMilanka Ringwald connection->cmd_operands[11] = 0x04; // scan (1-off, 2-all tracks, 3-group scan) 1021*6983e65eSMilanka Ringwald connection->cmd_operands_length = 12; 1022*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 1023*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 1024*6983e65eSMilanka Ringwald } 1025*6983e65eSMilanka Ringwald 1026*6983e65eSMilanka Ringwald static uint8_t avrcp_controller_set_current_player_application_setting_value(uint16_t avrcp_cid, uint8_t attr_id, uint8_t attr_value){ 1027*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 1028*6983e65eSMilanka Ringwald if (!connection){ 1029*6983e65eSMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 1030*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1031*6983e65eSMilanka Ringwald } 1032*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 1033*6983e65eSMilanka Ringwald connection->state = AVCTP_W2_SEND_COMMAND; 1034*6983e65eSMilanka Ringwald 1035*6983e65eSMilanka Ringwald connection->transaction_label++; 1036*6983e65eSMilanka Ringwald connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; 1037*6983e65eSMilanka Ringwald connection->command_type = AVRCP_CTYPE_CONTROL; 1038*6983e65eSMilanka Ringwald connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; 1039*6983e65eSMilanka Ringwald connection->subunit_id = AVRCP_SUBUNIT_ID; 1040*6983e65eSMilanka Ringwald int pos = 0; 1041*6983e65eSMilanka Ringwald big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); 1042*6983e65eSMilanka Ringwald pos += 3; 1043*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = AVRCP_PDU_ID_SetPlayerApplicationSettingValue; // PDU ID 1044*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = 0; 1045*6983e65eSMilanka Ringwald // Parameter Length 1046*6983e65eSMilanka Ringwald big_endian_store_16(connection->cmd_operands, pos, 3); 1047*6983e65eSMilanka Ringwald pos += 2; 1048*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = 2; 1049*6983e65eSMilanka Ringwald connection->cmd_operands_length = pos; 1050*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = attr_id; 1051*6983e65eSMilanka Ringwald connection->cmd_operands[pos++] = attr_value; 1052*6983e65eSMilanka Ringwald connection->cmd_operands_length = pos; 1053*6983e65eSMilanka Ringwald avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); 1054*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 1055*6983e65eSMilanka Ringwald } 1056*6983e65eSMilanka Ringwald 1057*6983e65eSMilanka Ringwald uint8_t avrcp_controller_set_shuffle_mode(uint16_t avrcp_cid, avrcp_shuffle_mode_t mode){ 1058*6983e65eSMilanka Ringwald if (mode < AVRCP_SHUFFLE_MODE_OFF || mode > AVRCP_SHUFFLE_MODE_GROUP) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 1059*6983e65eSMilanka Ringwald return avrcp_controller_set_current_player_application_setting_value(avrcp_cid, 0x03, mode); 1060*6983e65eSMilanka Ringwald } 1061*6983e65eSMilanka Ringwald 1062*6983e65eSMilanka Ringwald uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode){ 1063*6983e65eSMilanka Ringwald if (mode < AVRCP_REPEAT_MODE_OFF || mode > AVRCP_REPEAT_MODE_GROUP) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 1064*6983e65eSMilanka Ringwald return avrcp_controller_set_current_player_application_setting_value(avrcp_cid, 0x02, mode); 1065*6983e65eSMilanka Ringwald } 1066*6983e65eSMilanka Ringwald 1067*6983e65eSMilanka Ringwald uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid){ 1068*6983e65eSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); 1069*6983e65eSMilanka Ringwald if (!connection){ 1070*6983e65eSMilanka Ringwald log_error("avrcp_get_capabilities: could not find a connection."); 1071*6983e65eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1072*6983e65eSMilanka Ringwald } 1073*6983e65eSMilanka Ringwald if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 1074*6983e65eSMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 1075*6983e65eSMilanka Ringwald return ERROR_CODE_SUCCESS; 1076*6983e65eSMilanka Ringwald }