mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-29 13:20:39 +00:00
avrcp target: crude pass through implemetation
This commit is contained in:
parent
133becec45
commit
831d3fd526
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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){
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user