avrcp target: crude pass through implemetation

This commit is contained in:
Milanka Ringwald 2017-08-30 17:22:15 +02:00
parent 133becec45
commit 831d3fd526
6 changed files with 149 additions and 7 deletions

View File

@ -383,10 +383,12 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
UNUSED(size);
bd_addr_t event_addr;
uint16_t local_cid;
uint8_t status = 0xFF;
uint8_t a2dp_cmd_status = 0xFF;
uint8_t avrcp_cmd_status = 0xFF;
if (packet_type != HCI_EVENT_PACKET) return;
if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
switch (packet[2]){
case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
@ -395,9 +397,9 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
return;
}
status = avrcp_subevent_connection_established_get_status(packet);
if (status != ERROR_CODE_SUCCESS){
printf("AVRCP: Connection failed: status 0x%02x\n", status);
avrcp_cmd_status = avrcp_subevent_connection_established_get_status(packet);
if (avrcp_cmd_status != ERROR_CODE_SUCCESS){
printf("AVRCP: Connection failed: status 0x%02x\n", avrcp_cmd_status);
avrcp_cid = 0;
return;
}
@ -437,6 +439,37 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
avrcp_target_now_playing_info(avrcp_cid);
break;
case AVRCP_SUBEVENT_OPERATION:{
avrcp_operation_id_t operation_id = avrcp_subevent_operation_get_operation_id(packet);
uint8_t operands_length = avrcp_subevent_operation_get_operands_length(packet);
uint8_t operand = avrcp_subevent_operation_get_operand(packet);
printf("AVRCP: operation 0x%02x, operands length %d\n", operation_id, operands_length);
switch (operation_id){
case AVRCP_OPERATION_ID_PLAY:
a2dp_cmd_status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
break;
case AVRCP_OPERATION_ID_PAUSE:
a2dp_cmd_status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
break;
case AVRCP_OPERATION_ID_STOP:
case AVRCP_OPERATION_ID_REWIND:
case AVRCP_OPERATION_ID_FAST_FORWARD:
case AVRCP_OPERATION_ID_FORWARD:
case AVRCP_OPERATION_ID_BACKWARD:
case AVRCP_OPERATION_ID_SKIP:
case AVRCP_OPERATION_ID_VOLUME_UP:
case AVRCP_OPERATION_ID_VOLUME_DOWN:
case AVRCP_OPERATION_ID_MUTE:
case AVRCP_OPERATION_ID_UNDEFINED:
avrcp_cmd_status = avrcp_target_operation_not_implemented(avrcp_cid, operation_id, operands_length, operand);
return;
}
// printf("a2dp_cmd_status 0x%02x \n", a2dp_cmd_status);
avrcp_cmd_status = avrcp_target_operation_accepted(avrcp_cid, operation_id, operands_length, operand);
break;
}
case AVRCP_SUBEVENT_CONNECTION_RELEASED:
printf("AVRCP: Channel released: avrcp_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
avrcp_cid = 0;

View File

@ -1733,6 +1733,15 @@ typedef uint8_t sm_key_t[16];
*/
#define AVRCP_SUBEVENT_NOW_PLAYING_INFO_QUERY 0x15
/**
* @format 12111
* @param subevent_code
* @param avrcp_cid
* @param operation_id
* @param operands_length
* @param operand
*/
#define AVRCP_SUBEVENT_OPERATION 0x16
/**
* @format 121BH1

View File

@ -5555,6 +5555,43 @@ static inline uint16_t avrcp_subevent_now_playing_info_query_get_avrcp_cid(const
return little_endian_read_16(event, 3);
}
/**
* @brief Get field avrcp_cid from event AVRCP_SUBEVENT_OPERATION
* @param event packet
* @return avrcp_cid
* @note: btstack_type 2
*/
static inline uint16_t avrcp_subevent_operation_get_avrcp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field operation_id from event AVRCP_SUBEVENT_OPERATION
* @param event packet
* @return operation_id
* @note: btstack_type 1
*/
static inline uint8_t avrcp_subevent_operation_get_operation_id(const uint8_t * event){
return event[5];
}
/**
* @brief Get field operands_length from event AVRCP_SUBEVENT_OPERATION
* @param event packet
* @return operands_length
* @note: btstack_type 1
*/
static inline uint8_t avrcp_subevent_operation_get_operands_length(const uint8_t * event){
return event[6];
}
/**
* @brief Get field operand from event AVRCP_SUBEVENT_OPERATION
* @param event packet
* @return operand
* @note: btstack_type 1
*/
static inline uint8_t avrcp_subevent_operation_get_operand(const uint8_t * event){
return event[7];
}
/**
* @brief Get field goep_cid from event GOEP_SUBEVENT_CONNECTION_OPENED
* @param event packet

View File

@ -623,7 +623,6 @@ void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
case L2CAP_EVENT_CHANNEL_CLOSED:
// data: event (8), len(8), channel (16)
printf("L2CAP_EVENT_CHANNEL_CLOSED \n");
local_cid = l2cap_event_channel_closed_get_local_cid(packet);
connection = get_avrcp_connection_for_l2cap_signaling_cid(local_cid, context);
if (connection){

View File

@ -52,6 +52,21 @@ void avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_h
avrcp_create_sdp_record(0, service, service_record_handle, browsing, supported_features, service_name, service_provider_name);
}
static void avrcp_target_emit_operation(btstack_packet_handler_t callback, uint16_t avrcp_cid, avrcp_operation_id_t operation_id, uint8_t operands_length, uint8_t operand){
if (!callback) return;
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_AVRCP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVRCP_SUBEVENT_OPERATION;
little_endian_store_16(event, pos, avrcp_cid);
pos += 2;
event[pos++] = operation_id;
event[pos++] = operands_length;
event[pos++] = operand;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void avrcp_target_emit_respond_query(btstack_packet_handler_t callback, uint16_t avrcp_cid, uint8_t subeventID){
if (!callback) return;
uint8_t event[5];
@ -206,6 +221,8 @@ static int avrcp_target_send_response(uint16_t cid, avrcp_connection_t * connect
packet[pos++] = (uint8_t)connection->command_opcode;
// operands
memcpy(packet+pos, connection->cmd_operands, connection->cmd_operands_length);
// printf_hexdump(packet+pos, connection->cmd_operands_length);
pos += connection->cmd_operands_length;
connection->wait_to_send = 0;
return l2cap_send_prepared(cid, pos);
@ -233,6 +250,45 @@ static uint8_t avrcp_target_response_reject(avrcp_connection_t * connection, avr
return ERROR_CODE_SUCCESS;
}
static uint8_t avrcp_target_pass_through_response(uint16_t avrcp_cid, avrcp_command_type_t cmd_type, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand){
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context);
if (!connection){
log_error("avrcp_target_operation_reject: could not find a connection.");
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED;
printf("avrcp_target_pass_through_response: operation 0x%02x, operands length %d\n", opid, operands_length);
connection->command_type = cmd_type;
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
connection->subunit_id = AVRCP_SUBUNIT_ID;
connection->command_opcode = AVRCP_CMD_OPCODE_PASS_THROUGH;
int pos = 0;
connection->cmd_operands[pos++] = opid;
connection->cmd_operands[pos++] = operands_length;
if (operands_length == 1){
connection->cmd_operands[pos++] = operand;
}
connection->cmd_operands_length = pos;
connection->state = AVCTP_W2_SEND_RESPONSE;
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
return ERROR_CODE_SUCCESS;
}
uint8_t avrcp_target_operation_rejected(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand){
return avrcp_target_pass_through_response(avrcp_cid, AVRCP_CTYPE_RESPONSE_REJECTED, opid, operands_length, operand);
}
uint8_t avrcp_target_operation_accepted(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand){
return avrcp_target_pass_through_response(avrcp_cid, AVRCP_CTYPE_RESPONSE_ACCEPTED, opid, operands_length, operand);
}
uint8_t avrcp_target_operation_not_implemented(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand){
return avrcp_target_pass_through_response(avrcp_cid, AVRCP_CTYPE_RESPONSE_ACCEPTED, opid, operands_length, operand);
}
uint8_t avrcp_target_unit_info(uint16_t avrcp_cid, avrcp_subunit_type_t unit_type, uint32_t company_id){
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_target_context);
if (!connection){
@ -474,6 +530,10 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
avrcp_target_emit_respond_subunit_info_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, offset);
break;
}
case AVRCP_CMD_OPCODE_PASS_THROUGH:
log_info("AVRCP_OPERATION_ID 0x%02x, operands length %d, operand %d", packet[6], packet[7], packet[8]);
avrcp_target_emit_operation(avrcp_target_context.avrcp_callback, connection->avrcp_cid, packet[6], packet[7], packet[8]);
break;
case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT:
pdu_id = pdu[0];
// 1 - reserved
@ -516,7 +576,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
}
break;
default:
printf("AVRCP source: opcode 0x%02x not implemented\n", avrcp_cmd_opcode(packet,size));
printf("AVRCP target: opcode 0x%02x not implemented\n", avrcp_cmd_opcode(packet,size));
break;
}
}

View File

@ -91,6 +91,10 @@ uint8_t avrcp_target_set_now_playing_total_tracks(uint16_t avrcp_cid, const int
uint8_t avrcp_target_set_now_playing_track_nr(uint16_t avrcp_cid, const int track_nr);
uint8_t avrcp_target_now_playing_info(uint16_t avrcp_cid);
uint8_t avrcp_target_operation_rejected(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand);
uint8_t avrcp_target_operation_accepted(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand);
uint8_t avrcp_target_operation_not_implemented(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint8_t operands_length, uint8_t operand);
/* API_END */
#if defined __cplusplus
}