avrcp: fix enable disable

This commit is contained in:
Milanka Ringwald 2017-02-20 17:10:47 +01:00
parent 851e09fd8a
commit 96b12aa570
3 changed files with 75 additions and 62 deletions

View File

@ -178,7 +178,6 @@ static const char * ctype2str(uint8_t index){
}
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void avrcp_register_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id, uint32_t playback_interval_in_seconds);
static void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name){
uint8_t* attribute;
@ -462,6 +461,39 @@ static int avrcp_send_cmd(uint16_t cid, avrcp_connection_t * connection){
return l2cap_send(cid, command, pos);
}
static int avrcp_register_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id){
if (connection->notifications_to_deregister & (1 << event_id)) return 0;
if (connection->notifications_enabled & (1 << event_id)) return 0;
if (connection->notifications_to_register & (1 << event_id)) return 0;
connection->notifications_to_register |= (1 << event_id);
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
return 1;
}
static void avrcp_prepare_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id){
if (connection->state != AVCTP_CONNECTION_OPENED) return;
connection->state = AVCTP_W2_SEND_COMMAND;
connection->transaction_label++;
connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
connection->command_type = AVRCP_CTYPE_NOTIFY;
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
connection->subunit_id = 0;
int pos = 0;
big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
pos += 3;
connection->cmd_operands[pos++] = AVRCP_PDU_ID_REGISTER_NOTIFICATION;
connection->cmd_operands[pos++] = 0; // reserved(upper 6) | packet_type -> 0
big_endian_store_16(connection->cmd_operands, pos, 5); // parameter length
pos += 2;
connection->cmd_operands[pos++] = event_id;
big_endian_store_32(connection->cmd_operands, pos, 0);
pos += 4;
connection->cmd_operands_lenght = pos;
// AVRCP_SPEC_V14.pdf 166
// answer page 61
}
static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){
switch (connection->state){
case AVCTP_W2_RECEIVE_PRESS_RESPONSE:
@ -589,30 +621,33 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
break;
}
case AVRCP_PDU_ID_REGISTER_NOTIFICATION:{
uint8_t event_id = packet[pos++];
uint8_t event_id = packet[pos++];
uint16_t event_mask = (1 << event_id);
uint16_t reset_event_mask = ~event_mask;
switch (ctype){
case AVRCP_CTYPE_RESPONSE_INTERIM:
connection->notifications_to_register &= (0 << event_id);
if (connection->notifications_to_deregister & (1 << event_id)){
connection->notifications_enabled &= (0 << event_id);
connection->notifications_to_deregister &= (0 << event_id);
} else {
connection->notifications_enabled |= (1 << event_id);
}
// register as enabled
connection->notifications_enabled |= event_mask;
// clear registration bit
connection->notifications_to_register &= reset_event_mask;
// printf("INTERIM notifications_enabled 0x%2x, notifications_to_register 0x%2x\n", connection->notifications_enabled, connection->notifications_to_register);
break;
case AVRCP_CTYPE_RESPONSE_CHANGED_STABLE:
if (connection->notifications_to_deregister & (1 << event_id)){
connection->notifications_enabled &= (0 << event_id);
connection->notifications_to_deregister &= (0 << event_id);
// received change, event is considered deregistered
// we are re-enabling it automatically, if it is not
// explicitly disabled
connection->notifications_enabled &= reset_event_mask;
if (! (connection->notifications_to_deregister & event_mask)){
avrcp_register_notification(connection, event_id);
// printf("CHANGED_STABLE notifications_enabled 0x%2x, notifications_to_register 0x%2x\n", connection->notifications_enabled, connection->notifications_to_register);
} else {
connection->notifications_enabled &= (0 << event_id);
avrcp_register_notification(connection, event_id, 2);
connection->notifications_to_deregister &= reset_event_mask;
}
break;
default:
connection->notifications_to_register &= (0 << event_id);
connection->notifications_enabled &= (0 << event_id);
connection->notifications_to_deregister &= (0 << event_id);
connection->notifications_to_register &= reset_event_mask;
connection->notifications_enabled &= reset_event_mask;
connection->notifications_to_deregister &= reset_event_mask;
break;
}
@ -664,6 +699,9 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
printf("not implemented\n");
break;
}
if (connection->notifications_to_register != 0){
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
}
break;
}
case AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES:{
@ -718,6 +756,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
}
static void avrcp_handle_can_send_now(avrcp_connection_t * connection){
int i;
switch (connection->state){
case AVCTP_W2_SEND_PRESS_COMMAND:
connection->state = AVCTP_W2_RECEIVE_PRESS_RESPONSE;
@ -726,8 +765,18 @@ static void avrcp_handle_can_send_now(avrcp_connection_t * connection){
case AVCTP_W2_SEND_RELEASE_COMMAND:
connection->state = AVCTP_W2_RECEIVE_RESPONSE;
break;
case AVCTP_CONNECTION_OPENED:
if (connection->notifications_to_register != 0){
for (i = 1; i < 13; i++){
if (connection->notifications_to_register & (1<<i)){
avrcp_prepare_notification(connection, i);
avrcp_send_cmd(connection->l2cap_signaling_cid, connection);
return;
}
}
}
return;
default:
return;
}
avrcp_send_cmd(connection->l2cap_signaling_cid, connection);
@ -772,7 +821,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
if (!connection) break;
con_handle = l2cap_event_channel_opened_get_handle(packet);
local_cid = l2cap_event_channel_opened_get_local_cid(packet);
local_cid = l2cap_event_channel_opened_get_local_cid(packet);
// printf("L2CAP_EVENT_CHANNEL_OPENED: Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
// bd_addr_to_str(event_addr), con_handle, psm, local_cid, l2cap_event_channel_opened_get_remote_cid(packet));
@ -987,45 +1036,13 @@ void avrcp_get_play_status(uint16_t con_handle){
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
}
static void avrcp_register_notification(avrcp_connection_t * connection, avrcp_notification_event_id_t event_id, uint32_t playback_interval_in_seconds){
if (connection->state != AVCTP_CONNECTION_OPENED) return;
if (connection->notifications_to_deregister & (1 << event_id)) return;
if (connection->notifications_enabled & (1 << event_id)) return;
if (connection->notifications_to_register & (1 << event_id)) return;
printf("avrcp_register_notification \n");
connection->notifications_to_register |= (1 << event_id);
connection->state = AVCTP_W2_SEND_COMMAND;
connection->transaction_label++;
connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
connection->command_type = AVRCP_CTYPE_NOTIFY;
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
connection->subunit_id = 0;
int pos = 0;
big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
pos += 3;
connection->cmd_operands[pos++] = AVRCP_PDU_ID_REGISTER_NOTIFICATION;
connection->cmd_operands[pos++] = 0; // reserved(upper 6) | packet_type -> 0
big_endian_store_16(connection->cmd_operands, pos, 5); // parameter length
pos += 2;
connection->cmd_operands[pos++] = event_id;
big_endian_store_32(connection->cmd_operands, pos, playback_interval_in_seconds);
pos += 4;
connection->cmd_operands_lenght = pos;
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
// AVRCP_SPEC_V14.pdf 166
// answer page 61
}
void avrcp_enable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id, uint32_t playback_interval_in_seconds){
void avrcp_enable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id){
avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
if (!connection){
log_error("avrcp_get_play_status: coud not find a connection.");
return;
}
avrcp_register_notification(connection, event_id, playback_interval_in_seconds);
avrcp_register_notification(connection, event_id);
}
void avrcp_disable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id){
@ -1034,8 +1051,6 @@ void avrcp_disable_notification(uint16_t con_handle, avrcp_notification_event_id
log_error("avrcp_get_play_status: coud not find a connection.");
return;
}
if (connection->state != AVCTP_CONNECTION_OPENED) return;
if (connection->notifications_to_deregister & (1 << event_id)) return;
connection->notifications_to_deregister |= (1 << event_id);
}
@ -1084,8 +1099,6 @@ void avrcp_set_absolute_volume(uint16_t con_handle, uint8_t volume){
if (connection->state != AVCTP_CONNECTION_OPENED) return;
connection->state = AVCTP_W2_SEND_COMMAND;
connection->state = AVCTP_W2_SEND_COMMAND;
connection->transaction_label++;
connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
connection->command_type = AVRCP_CTYPE_CONTROL;

View File

@ -321,7 +321,7 @@ void avrcp_get_play_status(uint16_t con_handle);
* @param con_handle
* @param event_id
*/
void avrcp_enable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id, uint32_t playback_interval_in_seconds);
void avrcp_enable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id);
void avrcp_disable_notification(uint16_t con_handle, avrcp_notification_event_id_t event_id);
/**

View File

@ -66,7 +66,7 @@ static btstack_packet_callback_registration_t hci_event_callback_registration;
// static const char * device_addr_string = "BC:EC:5D:E6:15:03";
static bd_addr_t device_addr;
static const char * device_addr_string = "BC:EC:5D:E6:15:03";
static const char * device_addr_string = "D8:BB:2C:DF:F1:08";
static uint16_t con_handle = 0;
static uint8_t sdp_avrcp_controller_service_buffer[150];
@ -193,11 +193,11 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
avrcp_get_play_status(con_handle);
break;
case 'n':
//avrcp_enable_notification(con_handle, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED, 2);
avrcp_enable_notification(con_handle, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED, 0);
avrcp_enable_notification(con_handle, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED);
avrcp_enable_notification(con_handle, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED);
break;
case 'N':
//avrcp_disable_notification(con_handle, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED);
avrcp_disable_notification(con_handle, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED);
avrcp_disable_notification(con_handle, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED);
break;
case 'I':