From 6983e65e8fc2d4d8998d4365fc3aeee49461fe5d Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Fri, 21 Jul 2017 11:55:25 +0200 Subject: [PATCH] avrcp: extract avrcp controller --- src/btstack.h | 2 + src/classic/avrcp.c | 1337 ++--------------- src/classic/avrcp.h | 273 +--- src/classic/avrcp_controller.c | 1076 +++++++++++++ src/classic/avrcp_controller.h | 287 ++++ src/classic/avrcp_target.h | 74 + test/avrcp/Makefile | 4 +- test/avrcp/avrcp_controller_test | Bin 0 -> 375192 bytes .../{avrcp_test.c => avrcp_controller_test.c} | 65 +- test/pts/Makefile | 4 +- test/pts/avrcp_test.c | 101 +- 11 files changed, 1699 insertions(+), 1524 deletions(-) create mode 100644 src/classic/avrcp_controller.c create mode 100644 src/classic/avrcp_controller.h create mode 100644 src/classic/avrcp_target.h create mode 100755 test/avrcp/avrcp_controller_test rename test/avrcp/{avrcp_test.c => avrcp_controller_test.c} (89%) diff --git a/src/btstack.h b/src/btstack.h index aefc40e91..b3915d2a6 100644 --- a/src/btstack.h +++ b/src/btstack.h @@ -91,6 +91,8 @@ #include "classic/avdtp_source.h" #include "classic/avdtp_util.h" #include "classic/avrcp.h" +#include "classic/avrcp_controller.h" +#include "classic/avrcp_target.h" #include "classic/bnep.h" #include "classic/btstack_link_key_db.h" #include "classic/device_id_server.h" diff --git a/src/classic/avrcp.c b/src/classic/avrcp.c index 3f75ec71a..eb527aa74 100644 --- a/src/classic/avrcp.c +++ b/src/classic/avrcp.c @@ -44,67 +44,24 @@ #include "btstack.h" #include "classic/avrcp.h" +#include "classic/avrcp_controller.h" #define PSM_AVCTP BLUETOOTH_PROTOCOL_AVCTP #define PSM_AVCTP_BROWSING 0x001b -/* -Category 1: Player/Recorder -Category 2: Monitor/Amplifier -Category 3: Tuner -Category 4: Menu -*/ - -/* controller supported features -Bit 0 = Category 1 -Bit 1 = Category 2 -Bit 2 = Category 3 -Bit 3 = Category 4 -Bit 4-5 = RFA -Bit 6 = Supports browsing -Bit 7-15 = RFA -The bits for supported categories are set to 1. Others are set to 0. -*/ - -/* target supported features -Bit 0 = Category 1 -Bit 1 = Category 2 -Bit 2 = Category 3 -Bit 3 = Category 4 -Bit 4 = Player Application Settings. Bit 0 should be set for this bit to be set. -Bit 5 = Group Navigation. Bit 0 should be set for this bit to be set. -Bit 6 = Supports browsing*4 -Bit 7 = Supports multiple media player applications -Bit 8-15 = RFA -The bits for supported categories are set to 1. Others are set to 0. -*/ - -// TODO: merge with avdtp_packet_type_t -typedef enum { - AVRCP_SINGLE_PACKET= 0, - AVRCP_START_PACKET , - AVRCP_CONTINUE_PACKET , - AVRCP_END_PACKET -} avrcp_packet_type_t; - -typedef enum { - AVRCP_COMMAND_FRAME = 0, - AVRCP_RESPONSE_FRAME -} avrcp_frame_type_t; - -static int record_id = -1; -static uint16_t avrcp_cid_counter = 0; -static uint8_t attribute_value[1000]; -static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); - static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service"; static const char * default_avrcp_controller_service_provider_name = "BTstack AVRCP Controller Service Provider"; static const char * default_avrcp_target_service_name = "BTstack AVRCP Target Service"; static const char * default_avrcp_target_service_provider_name = "BTstack AVRCP Target Service Provider"; -static btstack_packet_handler_t avrcp_callback; +static uint16_t avrcp_cid_counter = 0; -static avrcp_context_t avrcp_controller_context; +static avrcp_context_t * sdp_query_context; +static int record_id = -1; +static uint8_t attribute_value[1000]; +static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); + +static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static const char * avrcp_subunit_type_name[] = { "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER", @@ -112,6 +69,7 @@ static const char * avrcp_subunit_type_name[] = { "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES", "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR" }; + const char * avrcp_subunit2str(uint16_t index){ if (index <= 11) return avrcp_subunit_type_name[index]; if (index >= 0x1C && index <= 0x1F) return avrcp_subunit_type_name[index - 0x10]; @@ -205,12 +163,8 @@ const char * avrcp_repeat2str(uint8_t index){ if (index >= 1 && index <= 4) return avrcp_repeat_mode_name[index-1]; return "NONE"; } -static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context); -static avrcp_sdp_query_context_t sdp_query_context; -static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); - -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){ +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; de_create_sequence(service); @@ -328,15 +282,66 @@ static void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint3 de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); } -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){ - avrcp_create_sdp_record(1, service, service_record_handle, browsing, supported_features, service_name, service_provider_name); +static avrcp_connection_t * get_avrcp_connection_for_bd_addr(bd_addr_t addr, avrcp_context_t * context){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &context->connections); + while (btstack_linked_list_iterator_has_next(&it)){ + avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); + if (memcmp(addr, connection->remote_addr, 6) != 0) continue; + return connection; + } + return NULL; } -void avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name){ - avrcp_create_sdp_record(0, service, service_record_handle, browsing, supported_features, service_name, service_provider_name); +avrcp_connection_t * get_avrcp_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid, avrcp_context_t * context){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &context->connections); + while (btstack_linked_list_iterator_has_next(&it)){ + avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); + if (connection->l2cap_signaling_cid != l2cap_cid) continue; + return connection; + } + return NULL; } -static void avrcp_emit_connection_established(btstack_packet_handler_t callback, uint16_t avrcp_cid, bd_addr_t addr, uint8_t status){ +avrcp_connection_t * get_avrcp_connection_for_avrcp_cid(uint16_t l2cap_cid, avrcp_context_t * context){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &context->connections); + while (btstack_linked_list_iterator_has_next(&it)){ + avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); + if (connection->avrcp_cid != l2cap_cid) continue; + return connection; + } + return NULL; +} + +void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ + connection->wait_to_send = 1; + l2cap_request_can_send_now_event(l2cap_cid); +} + + +static uint16_t avdtp_get_next_avrcp_cid(void){ + avrcp_cid_counter++; + if (avrcp_cid_counter == 0){ + avrcp_cid_counter = 1; + } + return avrcp_cid_counter; +} + +static avrcp_connection_t * avrcp_create_connection(bd_addr_t remote_addr, avrcp_context_t * context){ + avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); + memset(connection, 0, sizeof(avrcp_connection_t)); + connection->state = AVCTP_CONNECTION_IDLE; + connection->transaction_label = 0xFF; + connection->avrcp_cid = avdtp_get_next_avrcp_cid(); + memcpy(connection->remote_addr, remote_addr, 6); + btstack_linked_list_add(&context->connections, (btstack_linked_item_t *) connection); + return connection; +} + + +void avrcp_emit_connection_established(btstack_packet_handler_t callback, uint16_t avrcp_cid, bd_addr_t addr, uint8_t status){ if (!callback) return; uint8_t event[12]; int pos = 0; @@ -351,36 +356,7 @@ static void avrcp_emit_connection_established(btstack_packet_handler_t callback, (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -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){ - 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_SHUFFLE_AND_REPEAT_MODE; - little_endian_store_16(event, pos, avrcp_cid); - pos += 2; - event[pos++] = ctype; - event[pos++] = repeat_mode; - event[pos++] = shuffle_mode; - (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); -} - -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){ - if (!callback) return; - uint8_t event[7]; - int pos = 0; - event[pos++] = HCI_EVENT_AVRCP_META; - event[pos++] = sizeof(event) - 2; - event[pos++] = subevent; - little_endian_store_16(event, pos, avrcp_cid); - pos += 2; - event[pos++] = ctype; - event[pos++] = operation_id; - (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); -} - -static void avrcp_emit_connection_closed(btstack_packet_handler_t callback, uint16_t avrcp_cid){ +void avrcp_emit_connection_closed(btstack_packet_handler_t callback, uint16_t avrcp_cid){ if (!callback) return; uint8_t event[5]; int pos = 0; @@ -392,179 +368,11 @@ static void avrcp_emit_connection_closed(btstack_packet_handler_t callback, uint (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } -static avrcp_connection_t * get_avrcp_connection_for_bd_addr(bd_addr_t addr, avrcp_context_t * context){ - btstack_linked_list_iterator_t it; - btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &context->connections); - while (btstack_linked_list_iterator_has_next(&it)){ - avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); - if (memcmp(addr, connection->remote_addr, 6) != 0) continue; - return connection; - } - return NULL; -} - -static avrcp_connection_t * get_avrcp_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid, avrcp_context_t * context){ - btstack_linked_list_iterator_t it; - btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &context->connections); - while (btstack_linked_list_iterator_has_next(&it)){ - avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); - if (connection->l2cap_signaling_cid != l2cap_cid) continue; - return connection; - } - return NULL; -} - -static avrcp_connection_t * get_avrcp_connection_for_avrcp_cid(uint16_t l2cap_cid, avrcp_context_t * context){ - btstack_linked_list_iterator_t it; - btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &context->connections); - while (btstack_linked_list_iterator_has_next(&it)){ - avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); - if (connection->avrcp_cid != l2cap_cid) continue; - return connection; - } - return NULL; -} - -static void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ - connection->wait_to_send = 1; - l2cap_request_can_send_now_event(l2cap_cid); -} - -static void avrcp_press_and_hold_timeout_handler(btstack_timer_source_t * timer){ - UNUSED(timer); - avrcp_connection_t * connection = btstack_run_loop_get_timer_context(timer); - btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout - btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer); - connection->state = AVCTP_W2_SEND_PRESS_COMMAND; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); -} - -static void avrcp_press_and_hold_timer_start(avrcp_connection_t * connection){ - btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer); - btstack_run_loop_set_timer_handler(&connection->press_and_hold_cmd_timer, avrcp_press_and_hold_timeout_handler); - btstack_run_loop_set_timer_context(&connection->press_and_hold_cmd_timer, connection); - btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout - btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer); -} - -static void avrcp_press_and_hold_timer_stop(avrcp_connection_t * connection){ - connection->continuous_fast_forward_cmd = 0; - btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer); -} - -static uint8_t request_pass_through_release_control_cmd(avrcp_connection_t * connection){ - connection->state = AVCTP_W2_SEND_RELEASE_COMMAND; - if (connection->continuous_fast_forward_cmd){ - avrcp_press_and_hold_timer_stop(connection); - } - connection->cmd_operands[0] = 0x80 | connection->cmd_operands[0]; - connection->transaction_label++; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -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){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, context); - if (!connection){ - log_error("avrcp: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_PRESS_COMMAND; - connection->command_opcode = AVRCP_CMD_OPCODE_PASS_THROUGH; - connection->command_type = AVRCP_CTYPE_CONTROL; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - connection->cmd_operands_length = 0; - - connection->continuous_fast_forward_cmd = continuous_fast_forward_cmd; - connection->cmd_operands_length = 2; - connection->cmd_operands[0] = opid; - if (playback_speed > 0){ - connection->cmd_operands[2] = playback_speed; - connection->cmd_operands_length++; - } - connection->cmd_operands[1] = connection->cmd_operands_length - 2; - - if (connection->continuous_fast_forward_cmd){ - avrcp_press_and_hold_timer_start(connection); - } - - connection->transaction_label++; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -static uint8_t request_single_pass_through_press_control_cmd(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint16_t playback_speed){ - return request_pass_through_press_control_cmd(avrcp_cid, opid, playback_speed, 0, &avrcp_controller_context); -} - -static uint8_t request_continuous_pass_through_press_control_cmd(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint16_t playback_speed){ - return request_pass_through_press_control_cmd(avrcp_cid, opid, playback_speed, 1, &avrcp_controller_context); -} - -static int avrcp_send_cmd(uint16_t cid, avrcp_connection_t * connection){ - uint8_t command[30]; - int pos = 0; - // transport header - // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) - command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; - // Profile IDentifier (PID) - command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; - command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; - - // command_type - command[pos++] = connection->command_type; - // subunit_type | subunit ID - command[pos++] = (connection->subunit_type << 3) | connection->subunit_id; - // opcode - command[pos++] = (uint8_t)connection->command_opcode; - // operands - memcpy(command+pos, connection->cmd_operands, connection->cmd_operands_length); - pos += connection->cmd_operands_length; - - 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){ - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; - connection->command_type = AVRCP_CTYPE_NOTIFY; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - 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_length = pos; - // AVRCP_SPEC_V14.pdf 166 - // answer page 61 -} - -static uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ - uint8_t cmd_opcode_index = 5; - if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; - return packet[cmd_opcode_index]; -} - static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ - if (!sdp_query_context.connection) return; - if (sdp_query_context.connection->state != AVCTP_SIGNALING_W4_SDP_QUERY_COMPLETE) return; + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(sdp_query_context->avrcp_cid, sdp_query_context); + + if (!connection) return; + if (connection->state != AVCTP_SIGNALING_W4_SDP_QUERY_COMPLETE) return; UNUSED(packet_type); UNUSED(channel); UNUSED(size); @@ -594,15 +402,15 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c uint32_t uuid = de_get_uuid32(element); switch (uuid){ case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: - if (sdp_query_context.avrcp_context->role == AVRCP_CONTROLLER) { - sdp_query_context.role_supported = 1; + if (sdp_query_context->role == AVRCP_CONTROLLER) { + sdp_query_context->role_supported = 1; break; } break; case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: - if (sdp_query_context.avrcp_context->role == AVRCP_TARGET) { - sdp_query_context.role_supported = 1; + if (sdp_query_context->role == AVRCP_TARGET) { + sdp_query_context->role_supported = 1; break; } break; @@ -632,12 +440,12 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c case BLUETOOTH_PROTOCOL_L2CAP: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); - de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_l2cap_psm); + de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_l2cap_psm); break; case BLUETOOTH_PROTOCOL_AVCTP: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); - de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_version); + de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_version); break; default: break; @@ -673,12 +481,12 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c case BLUETOOTH_PROTOCOL_L2CAP: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); - de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_browsing_l2cap_psm); + de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_browsing_l2cap_psm); break; case BLUETOOTH_PROTOCOL_AVCTP: if (!des_iterator_has_more(&prot_it)) continue; des_iterator_next(&prot_it); - de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_browsing_version); + de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_browsing_version); break; default: break; @@ -696,588 +504,85 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c break; case SDP_EVENT_QUERY_COMPLETE: - log_info("General query done with status %d, role supported %d.\n", sdp_event_query_complete_get_status(packet), sdp_query_context.role_supported); - if (!sdp_query_context.role_supported || !sdp_query_context.avrcp_l2cap_psm){ - sdp_query_context.connection->state = AVCTP_CONNECTION_IDLE; - avrcp_emit_connection_established(sdp_query_context.avrcp_context->avrcp_callback, sdp_query_context.connection->avrcp_cid, sdp_query_context.connection->remote_addr, SDP_SERVICE_NOT_FOUND); + log_info("General query done with status %d, role supported %d.\n", sdp_event_query_complete_get_status(packet), sdp_query_context->role_supported); + if (!sdp_query_context->role_supported || !sdp_query_context->avrcp_l2cap_psm){ + connection->state = AVCTP_CONNECTION_IDLE; + avrcp_emit_connection_established(sdp_query_context->avrcp_callback, connection->avrcp_cid, connection->remote_addr, SDP_SERVICE_NOT_FOUND); break; } - log_info("AVRCP Control PSM 0x%02x, Browsing PSM 0x%02x", sdp_query_context.avrcp_l2cap_psm, sdp_query_context.avrcp_browsing_l2cap_psm); - sdp_query_context.connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; - l2cap_create_channel(sdp_query_context.avrcp_context->packet_handler, sdp_query_context.connection->remote_addr, sdp_query_context.avrcp_l2cap_psm, l2cap_max_mtu(), NULL); + log_info("AVRCP Control PSM 0x%02x, Browsing PSM 0x%02x", sdp_query_context->avrcp_l2cap_psm, sdp_query_context->avrcp_browsing_l2cap_psm); + connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; + l2cap_create_channel(sdp_query_context->packet_handler, connection->remote_addr, sdp_query_context->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); break; } } -static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){ - uint8_t operands[20]; - uint8_t opcode; - int pos = 3; - // uint8_t transport_header = packet[0]; - // uint8_t transaction_label = transport_header >> 4; - // uint8_t packet_type = (transport_header & 0x0F) >> 2; - // uint8_t frame_type = (transport_header & 0x03) >> 1; - // uint8_t ipid = transport_header & 0x01; - // uint8_t byte_value = packet[2]; - // uint16_t pid = (byte_value << 8) | packet[2]; - - avrcp_command_type_t ctype = (avrcp_command_type_t) packet[pos++]; - uint8_t byte_value = packet[pos++]; - avrcp_subunit_type_t subunit_type = (avrcp_subunit_type_t) (byte_value >> 3); - avrcp_subunit_type_t subunit_id = (avrcp_subunit_type_t) (byte_value & 0x07); - opcode = packet[pos++]; - - // printf(" Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n", - // transport_header, transaction_label, packet_type, frame_type, ipid, pid); - // // printf_hexdump(packet+pos, size-pos); - - uint8_t pdu_id; - uint16_t param_length; - switch (avrcp_cmd_opcode(packet,size)){ - case AVRCP_CMD_OPCODE_UNIT_INFO:{ - if (connection->state != AVCTP_W2_RECEIVE_RESPONSE) return; - connection->state = AVCTP_CONNECTION_OPENED; - - // operands: - memcpy(operands, packet+pos, 5); - uint8_t unit_type = operands[1] >> 3; - uint8_t unit = operands[1] & 0x07; - uint32_t company_id = operands[2] << 16 | operands[3] << 8 | operands[4]; - 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", - ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id ); - break; - } - case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: - if (size - pos < 7) { - log_error("avrcp: wrong packet size"); - return; - }; - // operands: - memcpy(operands, packet+pos, 7); - pos += 7; - // uint32_t company_id = operands[0] << 16 | operands[1] << 8 | operands[2]; - pdu_id = operands[3]; - - if (connection->state != AVCTP_W2_RECEIVE_RESPONSE && pdu_id != AVRCP_PDU_ID_REGISTER_NOTIFICATION){ - log_info("AVRCP_CMD_OPCODE_VENDOR_DEPENDENT state %d", connection->state); - return; - } - connection->state = AVCTP_CONNECTION_OPENED; - - - // uint8_t unit_type = operands[4] >> 3; - // uint8_t unit = operands[4] & 0x07; - param_length = big_endian_read_16(operands, 5); - - // 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", - // ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id ); - - // if (ctype == AVRCP_CTYPE_RESPONSE_INTERIM) return; - log_info(" VENDOR DEPENDENT response: pdu id 0x%02x, param_length %d, status %s", pdu_id, param_length, avrcp_ctype2str(ctype)); - switch (pdu_id){ - case AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue:{ - uint8_t num_attributes = packet[pos++]; - int i; - avrcp_repeat_mode_t repeat_mode = AVRCP_REPEAT_MODE_INVALID; - avrcp_shuffle_mode_t shuffle_mode = AVRCP_SHUFFLE_MODE_INVALID; - for (i = 0; i < num_attributes; i++){ - uint8_t attribute_id = packet[pos++]; - uint8_t value = packet[pos++]; - switch (attribute_id){ - case 0x02: - repeat_mode = (avrcp_repeat_mode_t) value; - break; - case 0x03: - shuffle_mode = (avrcp_shuffle_mode_t) value; - break; - default: - break; - } - } - avrcp_emit_repeat_and_shuffle_mode(avrcp_callback, connection->avrcp_cid, ctype, repeat_mode, shuffle_mode); - break; - } - case AVRCP_PDU_ID_SetPlayerApplicationSettingValue:{ - uint8_t event[6]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - case AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME:{ - uint8_t event[7]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - event[offset++] = packet[pos++]; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - case AVRCP_PDU_ID_GET_CAPABILITIES:{ - avrcp_capability_id_t capability_id = (avrcp_capability_id_t) packet[pos++]; - uint8_t capability_count = packet[pos++]; - int i; - switch (capability_id){ - case AVRCP_CAPABILITY_ID_COMPANY: - // log_info("Supported companies %d: ", capability_count); - for (i = 0; i < capability_count; i++){ - uint32_t company_id = big_endian_read_24(packet, pos); - pos += 3; - log_info(" 0x%06x, ", company_id); - } - break; - case AVRCP_CAPABILITY_ID_EVENT: - // log_info("Supported events %d: ", capability_count); - for (i = 0; i < capability_count; i++){ - uint8_t event_id = packet[pos++]; - log_info(" 0x%02x %s", event_id, avrcp_event2str(event_id)); - } - break; - } - break; - } - case AVRCP_PDU_ID_GET_PLAY_STATUS:{ - uint32_t song_length = big_endian_read_32(packet, pos); - pos += 4; - uint32_t song_position = big_endian_read_32(packet, pos); - pos += 4; - uint8_t play_status = packet[pos]; - // log_info(" GET_PLAY_STATUS length 0x%04X, position 0x%04X, status %s", song_length, song_position, avrcp_play_status2str(play_status)); - - uint8_t event[15]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_PLAY_STATUS; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - little_endian_store_32(event, offset, song_length); - offset += 4; - little_endian_store_32(event, offset, song_position); - offset += 4; - event[offset++] = play_status; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - case AVRCP_PDU_ID_REGISTER_NOTIFICATION:{ - avrcp_notification_event_id_t event_id = (avrcp_notification_event_id_t) packet[pos++]; - uint16_t event_mask = (1 << event_id); - uint16_t reset_event_mask = ~event_mask; - switch (ctype){ - case AVRCP_CTYPE_RESPONSE_INTERIM: - // register as enabled - connection->notifications_enabled |= 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: - // 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_to_deregister &= reset_event_mask; - } - break; - default: - connection->notifications_to_register &= reset_event_mask; - connection->notifications_enabled &= reset_event_mask; - connection->notifications_to_deregister &= reset_event_mask; - break; - } - - switch (event_id){ - case AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED:{ - uint8_t event[7]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_PLAYBACK_STATUS_CHANGED; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - event[offset++] = packet[pos]; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - case AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED:{ - uint8_t event[6]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - case AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED:{ - uint8_t event[6]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_NOW_PLAYING_CONTENT_CHANGED; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - case AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED:{ - uint8_t event[6]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_AVAILABLE_PLAYERS_CHANGED; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - case AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED:{ - uint8_t event[7]; - int offset = 0; - event[offset++] = HCI_EVENT_AVRCP_META; - event[offset++] = sizeof(event) - 2; - event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED; - little_endian_store_16(event, offset, connection->avrcp_cid); - offset += 2; - event[offset++] = ctype; - event[offset++] = packet[pos++] & 0x7F; - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); - break; - } - // case AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:{ - // uint8_t num_PlayerApplicationSettingAttributes = packet[pos++]; - // int i; - // for (i = 0; i < num_PlayerApplicationSettingAttributes; i++){ - // uint8_t PlayerApplicationSetting_AttributeID = packet[pos++]; - // uint8_t PlayerApplicationSettingValueID = packet[pos++]; - // } - // break; - // } - // case AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED: - // uint16_t player_id = big_endian_read_16(packet, pos); - // pos += 2; - // uint16_t uid_counter = big_endian_read_16(packet, pos); - // pos += 2; - // break; - // case AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED: - // uint16_t uid_counter = big_endian_read_16(packet, pos); - // pos += 2; - // break; - default: - log_info("avrcp: not implemented"); - 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:{ - uint8_t num_attributes = packet[pos++]; - int i; - struct item { - uint16_t len; - uint8_t * value; - } items[AVRCP_MEDIA_ATTR_COUNT]; - memset(items, 0, sizeof(items)); - - uint16_t string_attributes_len = 0; - uint8_t num_string_attributes = 0; - uint16_t total_event_payload_for_string_attributes = HCI_EVENT_PAYLOAD_SIZE-2; - uint16_t max_string_attribute_value_len = 0; - if (ctype == AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE || ctype == AVRCP_CTYPE_RESPONSE_CHANGED_STABLE){ - for (i = 0; i < num_attributes; i++){ - avrcp_media_attribute_id_t attr_id = (avrcp_media_attribute_id_t) big_endian_read_32(packet, pos); - pos += 4; - // uint16_t character_set = big_endian_read_16(packet, pos); - pos += 2; - uint16_t attr_value_length = big_endian_read_16(packet, pos); - pos += 2; - - // debug - to remove later - uint8_t value[100]; - uint16_t value_len = sizeof(value) <= attr_value_length? sizeof(value) - 1 : attr_value_length; - memcpy(value, packet+pos, value_len); - value[value_len] = 0; - // printf("Now Playing Info %s: %s \n", attribute2str(attr_id), value); - // end debug - - if ((attr_id >= 1) || (attr_id <= AVRCP_MEDIA_ATTR_COUNT)) { - items[attr_id-1].len = attr_value_length; - items[attr_id-1].value = &packet[pos]; - switch (attr_id){ - case AVRCP_MEDIA_ATTR_TITLE: - case AVRCP_MEDIA_ATTR_ARTIST: - case AVRCP_MEDIA_ATTR_ALBUM: - case AVRCP_MEDIA_ATTR_GENRE: - num_string_attributes++; - string_attributes_len += attr_value_length; - if (max_string_attribute_value_len < attr_value_length){ - max_string_attribute_value_len = attr_value_length; - } - break; - default: - break; - } - } - pos += attr_value_length; - } - } - - // subtract space for fixed fields - total_event_payload_for_string_attributes -= 14 + 4; // 4 for '\0' - - // @TODO optimize space by repeatedly decreasing max_string_attribute_value_len until it fits into buffer instead of crude divion - 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; - // 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); - - const uint8_t attribute_order[] = { - AVRCP_MEDIA_ATTR_TRACK, - AVRCP_MEDIA_ATTR_TOTAL_TRACKS, - AVRCP_MEDIA_ATTR_SONG_LENGTH, - AVRCP_MEDIA_ATTR_TITLE, - AVRCP_MEDIA_ATTR_ARTIST, - AVRCP_MEDIA_ATTR_ALBUM, - AVRCP_MEDIA_ATTR_GENRE - }; - - uint8_t event[HCI_EVENT_BUFFER_SIZE]; - event[0] = HCI_EVENT_AVRCP_META; - pos = 2; - event[pos++] = AVRCP_SUBEVENT_NOW_PLAYING_INFO; - little_endian_store_16(event, pos, connection->avrcp_cid); - pos += 2; - event[pos++] = ctype; - for (i = 0; i < sizeof(attribute_order); i++){ - avrcp_media_attribute_id_t attr_id = (avrcp_media_attribute_id_t) attribute_order[i]; - uint16_t value_len = 0; - switch (attr_id){ - case AVRCP_MEDIA_ATTR_TITLE: - case AVRCP_MEDIA_ATTR_ARTIST: - case AVRCP_MEDIA_ATTR_ALBUM: - case AVRCP_MEDIA_ATTR_GENRE: - if (items[attr_id-1].value){ - value_len = items[attr_id-1].len <= max_value_len ? items[attr_id-1].len : max_value_len; - } - event[pos++] = value_len + 1; - if (value_len){ - memcpy(event+pos, items[attr_id-1].value, value_len); - pos += value_len; - } - event[pos++] = 0; - break; - case AVRCP_MEDIA_ATTR_SONG_LENGTH: - if (items[attr_id-1].value){ - little_endian_store_32(event, pos, btstack_atoi((char *)items[attr_id-1].value)); - } else { - little_endian_store_32(event, pos, 0); - } - pos += 4; - break; - case AVRCP_MEDIA_ATTR_TRACK: - case AVRCP_MEDIA_ATTR_TOTAL_TRACKS: - if (items[attr_id-1].value){ - event[pos++] = btstack_atoi((char *)items[attr_id-1].value); - } else { - event[pos++] = 0; - } - break; - } - } - event[1] = pos - 2; - // printf_hexdump(event, pos); - (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, pos); - break; - } - default: - break; - } - break; - case AVRCP_CMD_OPCODE_PASS_THROUGH:{ - // 0x80 | connection->cmd_operands[0] - uint8_t operation_id = packet[pos++]; - switch (connection->state){ - case AVCTP_W2_RECEIVE_PRESS_RESPONSE: - if (connection->continuous_fast_forward_cmd){ - connection->state = AVCTP_W4_STOP; - } else { - connection->state = AVCTP_W2_SEND_RELEASE_COMMAND; - } - break; - case AVCTP_W2_RECEIVE_RESPONSE: - connection->state = AVCTP_CONNECTION_OPENED; - break; - default: - // check for notifications? move state transition down - // log_info("AVRCP_CMD_OPCODE_PASS_THROUGH state %d\n", connection->state); - break; - } - if (connection->state == AVCTP_W4_STOP){ - avrcp_emit_operation_status(avrcp_callback, AVRCP_SUBEVENT_OPERATION_START, connection->avrcp_cid, ctype, operation_id); - } - if (connection->state == AVCTP_CONNECTION_OPENED) { - // RELEASE response - operation_id = operation_id & 0x7F; - avrcp_emit_operation_status(avrcp_callback, AVRCP_SUBEVENT_OPERATION_COMPLETE, connection->avrcp_cid, ctype, operation_id); - } - if (connection->state == AVCTP_W2_SEND_RELEASE_COMMAND){ - // PRESS response - request_pass_through_release_control_cmd(connection); - } - break; - } - default: - break; - } -} - -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; - avrcp_send_cmd(connection->l2cap_signaling_cid, connection); - break; - case AVCTP_W2_SEND_COMMAND: - case AVCTP_W2_SEND_RELEASE_COMMAND: - connection->state = AVCTP_W2_RECEIVE_RESPONSE; - avrcp_send_cmd(connection->l2cap_signaling_cid, connection); - break; - case AVCTP_CONNECTION_OPENED: - if (connection->notifications_to_register != 0){ - for (i = 1; i <= AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED; i++){ - if (connection->notifications_to_register & (1<notifications_to_register &= ~ (1 << i); - avrcp_prepare_notification(connection, (avrcp_notification_event_id_t) i); - connection->state = AVCTP_W2_RECEIVE_RESPONSE; - avrcp_send_cmd(connection->l2cap_signaling_cid, connection); - return; - } - } - } - return; - default: - return; - } -} - -static uint16_t avdtp_get_next_avrcp_cid(void){ - avrcp_cid_counter++; - if (avrcp_cid_counter == 0){ - avrcp_cid_counter = 1; - } - return avrcp_cid_counter; -} - -static avrcp_connection_t * avrcp_create_connection(bd_addr_t remote_addr, avrcp_context_t * context){ - avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); - memset(connection, 0, sizeof(avrcp_connection_t)); - connection->state = AVCTP_CONNECTION_IDLE; - connection->transaction_label = 0xFF; - connection->avrcp_cid = avdtp_get_next_avrcp_cid(); - memcpy(connection->remote_addr, remote_addr, 6); - btstack_linked_list_add(&context->connections, (btstack_linked_item_t *) connection); - return connection; -} - -static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context){ +void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context){ + UNUSED(channel); + UNUSED(size); bd_addr_t event_addr; uint16_t local_cid; uint8_t status; avrcp_connection_t * connection = NULL; - switch (packet_type) { - case L2CAP_DATA_PACKET: - connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, context); - if (!connection) break; - avrcp_handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); + if (packet_type != HCI_EVENT_PACKET) return; + + switch (hci_event_packet_get_type(packet)) { + case HCI_EVENT_DISCONNECTION_COMPLETE: + // connection closed -> quit test app + // status = hci_event_disconnection_complete_get_status(packet); + avrcp_emit_connection_closed(context->avrcp_callback, 0); break; - - case HCI_EVENT_PACKET: - switch (hci_event_packet_get_type(packet)) { - case HCI_EVENT_DISCONNECTION_COMPLETE: - // connection closed -> quit test app - // status = hci_event_disconnection_complete_get_status(packet); - avrcp_emit_connection_closed(avrcp_callback, 0); - break; - case L2CAP_EVENT_INCOMING_CONNECTION: - l2cap_event_incoming_connection_get_address(packet, event_addr); - local_cid = l2cap_event_incoming_connection_get_local_cid(packet); - connection = avrcp_create_connection(event_addr, context); - if (!connection) { - log_error("Failed to alloc connection structure"); - l2cap_decline_connection(local_cid); - break; - } - connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; - connection->l2cap_signaling_cid = local_cid; - log_info("L2CAP_EVENT_INCOMING_CONNECTION avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x", connection->avrcp_cid, connection->l2cap_signaling_cid); - l2cap_accept_connection(local_cid); - break; - - case L2CAP_EVENT_CHANNEL_OPENED: - l2cap_event_channel_opened_get_address(packet, event_addr); - status = l2cap_event_channel_opened_get_status(packet); - local_cid = l2cap_event_channel_opened_get_local_cid(packet); - - connection = get_avrcp_connection_for_bd_addr(event_addr, context); - if (!connection){ - log_error("Failed to alloc AVRCP connection structure"); - avrcp_emit_connection_established(avrcp_callback, connection->avrcp_cid, event_addr, BTSTACK_MEMORY_ALLOC_FAILED); - l2cap_disconnect(local_cid, 0); // reason isn't used - break; - } - if (status != ERROR_CODE_SUCCESS){ - log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); - avrcp_emit_connection_established(avrcp_callback, connection->avrcp_cid, event_addr, status); - btstack_linked_list_remove(&context->connections, (btstack_linked_item_t*) connection); - btstack_memory_avrcp_connection_free(connection); - break; - } - connection->l2cap_signaling_cid = local_cid; - log_info("L2CAP_EVENT_CHANNEL_OPENED avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x", connection->avrcp_cid, connection->l2cap_signaling_cid); - connection->state = AVCTP_CONNECTION_OPENED; - avrcp_emit_connection_established(avrcp_callback, connection->avrcp_cid, event_addr, ERROR_CODE_SUCCESS); - break; - - case L2CAP_EVENT_CAN_SEND_NOW: - connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, context); - if (!connection) break; - avrcp_handle_can_send_now(connection); - break; - - case L2CAP_EVENT_CHANNEL_CLOSED: - // data: event (8), len(8), channel (16) - local_cid = l2cap_event_channel_closed_get_local_cid(packet); - connection = get_avrcp_connection_for_l2cap_signaling_cid(local_cid, context); - if (connection){ - avrcp_emit_connection_closed(avrcp_callback, connection->avrcp_cid); - // free connection - btstack_linked_list_remove(&context->connections, (btstack_linked_item_t*) connection); - btstack_memory_avrcp_connection_free(connection); - break; - } - break; - default: - break; + case L2CAP_EVENT_INCOMING_CONNECTION: + l2cap_event_incoming_connection_get_address(packet, event_addr); + local_cid = l2cap_event_incoming_connection_get_local_cid(packet); + connection = avrcp_create_connection(event_addr, context); + if (!connection) { + log_error("Failed to alloc connection structure"); + l2cap_decline_connection(local_cid); + break; + } + connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; + connection->l2cap_signaling_cid = local_cid; + log_info("L2CAP_EVENT_INCOMING_CONNECTION avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x", connection->avrcp_cid, connection->l2cap_signaling_cid); + l2cap_accept_connection(local_cid); + break; + + case L2CAP_EVENT_CHANNEL_OPENED: + l2cap_event_channel_opened_get_address(packet, event_addr); + status = l2cap_event_channel_opened_get_status(packet); + local_cid = l2cap_event_channel_opened_get_local_cid(packet); + + connection = get_avrcp_connection_for_bd_addr(event_addr, context); + if (!connection){ + log_error("Failed to alloc AVRCP connection structure"); + avrcp_emit_connection_established(context->avrcp_callback, connection->avrcp_cid, event_addr, BTSTACK_MEMORY_ALLOC_FAILED); + l2cap_disconnect(local_cid, 0); // reason isn't used + break; + } + if (status != ERROR_CODE_SUCCESS){ + log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); + avrcp_emit_connection_established(context->avrcp_callback, connection->avrcp_cid, event_addr, status); + btstack_linked_list_remove(&context->connections, (btstack_linked_item_t*) connection); + btstack_memory_avrcp_connection_free(connection); + break; + } + connection->l2cap_signaling_cid = local_cid; + log_info("L2CAP_EVENT_CHANNEL_OPENED avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x", connection->avrcp_cid, connection->l2cap_signaling_cid); + connection->state = AVCTP_CONNECTION_OPENED; + avrcp_emit_connection_established(context->avrcp_callback, connection->avrcp_cid, event_addr, ERROR_CODE_SUCCESS); + break; + + case L2CAP_EVENT_CHANNEL_CLOSED: + // data: event (8), len(8), channel (16) + local_cid = l2cap_event_channel_closed_get_local_cid(packet); + connection = get_avrcp_connection_for_l2cap_signaling_cid(local_cid, context); + if (connection){ + avrcp_emit_connection_closed(context->avrcp_callback, connection->avrcp_cid); + // free connection + btstack_linked_list_remove(&context->connections, (btstack_linked_item_t*) connection); + btstack_memory_avrcp_connection_free(connection); + break; } break; default: @@ -1285,27 +590,6 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe } } -static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ - packet_handler(packet_type, channel, packet, size, &avrcp_controller_context); -} - -void avrcp_controller_init(void){ - avrcp_controller_context.role = AVRCP_CONTROLLER; - avrcp_controller_context.connections = NULL; - avrcp_controller_context.avrcp_callback = avrcp_callback; - avrcp_controller_context.packet_handler = avrcp_controller_packet_handler; - l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0); -} - -void avrcp_register_packet_handler(btstack_packet_handler_t callback){ - if (callback == NULL){ - log_error("avrcp_register_packet_handler called with NULL callback"); - return; - } - avrcp_callback = callback; - avrcp_controller_context.avrcp_callback = avrcp_callback; -} - uint8_t avrcp_connect(bd_addr_t bd_addr, avrcp_context_t * context, uint16_t * avrcp_cid){ avrcp_connection_t * connection = get_avrcp_connection_for_bd_addr(bd_addr, context); if (connection){ @@ -1322,330 +606,13 @@ uint8_t avrcp_connect(bd_addr_t bd_addr, avrcp_context_t * context, uint16_t * a *avrcp_cid = connection->avrcp_cid; connection->state = AVCTP_SIGNALING_W4_SDP_QUERY_COMPLETE; - sdp_query_context.avrcp_context = context; - sdp_query_context.avrcp_l2cap_psm = 0; - sdp_query_context.avrcp_version = 0; - sdp_query_context.connection = connection; + + context->avrcp_l2cap_psm = 0; + context->avrcp_version = 0; + context->avrcp_cid = connection->avrcp_cid; + + sdp_query_context = context; sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, bd_addr, BLUETOOTH_PROTOCOL_AVCTP); return ERROR_CODE_SUCCESS; } - -uint8_t avrcp_controller_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid){ - return avrcp_connect(bd_addr, &avrcp_controller_context, avrcp_cid); -} - -uint8_t avrcp_unit_info(uint16_t avrcp_cid){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_unit_info: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_COMMAND; - - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_UNIT_INFO; - connection->command_type = AVRCP_CTYPE_STATUS; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT; //vendor unique - connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; - memset(connection->cmd_operands, 0xFF, connection->cmd_operands_length); - connection->cmd_operands_length = 5; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -static uint8_t avrcp_get_capabilities(uint16_t avrcp_cid, uint8_t capability_id){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_capabilities: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_COMMAND; - - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; - connection->command_type = AVRCP_CTYPE_STATUS; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); - connection->cmd_operands[3] = AVRCP_PDU_ID_GET_CAPABILITIES; // PDU ID - connection->cmd_operands[4] = 0; - big_endian_store_16(connection->cmd_operands, 5, 1); // parameter length - connection->cmd_operands[7] = capability_id; // capability ID - connection->cmd_operands_length = 8; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -uint8_t avrcp_get_supported_company_ids(uint16_t avrcp_cid){ - return avrcp_get_capabilities(avrcp_cid, AVRCP_CAPABILITY_ID_COMPANY); -} - -uint8_t avrcp_get_supported_events(uint16_t avrcp_cid){ - return avrcp_get_capabilities(avrcp_cid, AVRCP_CAPABILITY_ID_EVENT); -} - - -uint8_t avrcp_play(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_PLAY, 0); -} - -uint8_t avrcp_stop(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_STOP, 0); -} - -uint8_t avrcp_pause(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_PAUSE, 0); -} - -uint8_t avrcp_forward(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FORWARD, 0); -} - -uint8_t avrcp_backward(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_BACKWARD, 0); -} - -uint8_t avrcp_start_rewind(uint16_t avrcp_cid){ - return request_continuous_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_REWIND, 0); -} - -uint8_t avrcp_volume_up(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_VOLUME_UP, 0); -} - -uint8_t avrcp_volume_down(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_VOLUME_DOWN, 0); -} - -uint8_t avrcp_mute(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_MUTE, 0); -} - -uint8_t avrcp_skip(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_SKIP, 0); -} - -uint8_t avrcp_stop_rewind(uint16_t avrcp_cid){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_stop_rewind: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_W4_STOP) return ERROR_CODE_COMMAND_DISALLOWED; - return request_pass_through_release_control_cmd(connection); -} - -uint8_t avrcp_start_fast_forward(uint16_t avrcp_cid){ - return request_continuous_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FAST_FORWARD, 0); -} - -uint8_t avrcp_fast_forward(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FAST_FORWARD, 0); -} - -uint8_t avrcp_rewind(uint16_t avrcp_cid){ - return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_REWIND, 0); -} - - -uint8_t avrcp_stop_fast_forward(uint16_t avrcp_cid){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_stop_fast_forward: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_W4_STOP) return ERROR_CODE_COMMAND_DISALLOWED; - return request_pass_through_release_control_cmd(connection); -} - -uint8_t avrcp_get_play_status(uint16_t avrcp_cid){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_play_status: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_COMMAND; - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; - connection->command_type = AVRCP_CTYPE_STATUS; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); - connection->cmd_operands[3] = AVRCP_PDU_ID_GET_PLAY_STATUS; - connection->cmd_operands[4] = 0; // reserved(upper 6) | packet_type -> 0 - big_endian_store_16(connection->cmd_operands, 5, 0); // parameter length - connection->cmd_operands_length = 7; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -uint8_t avrcp_enable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_play_status: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - avrcp_register_notification(connection, event_id); - return ERROR_CODE_SUCCESS; -} - -uint8_t avrcp_disable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_play_status: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - connection->notifications_to_deregister |= (1 << event_id); - return ERROR_CODE_SUCCESS; -} - -uint8_t avrcp_get_now_playing_info(uint16_t avrcp_cid){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_capabilities: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_COMMAND; - - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; - connection->command_type = AVRCP_CTYPE_STATUS; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - int pos = 0; - big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); - pos += 3; - connection->cmd_operands[pos++] = AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES; // PDU ID - connection->cmd_operands[pos++] = 0; - - // Parameter Length - big_endian_store_16(connection->cmd_operands, pos, 9); - pos += 2; - - // write 8 bytes value - memset(connection->cmd_operands + pos, 0, 8); // identifier: PLAYING - pos += 8; - - connection->cmd_operands[pos++] = 0; // attribute count, if 0 get all attributes - // every attribute is 4 bytes long - - connection->cmd_operands_length = pos; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -uint8_t avrcp_set_absolute_volume(uint16_t avrcp_cid, uint8_t volume){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_capabilities: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_COMMAND; - - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; - connection->command_type = AVRCP_CTYPE_CONTROL; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - int pos = 0; - big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); - pos += 3; - connection->cmd_operands[pos++] = AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME; // PDU ID - connection->cmd_operands[pos++] = 0; - - // Parameter Length - big_endian_store_16(connection->cmd_operands, pos, 1); - pos += 2; - connection->cmd_operands[pos++] = volume; - - connection->cmd_operands_length = pos; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -uint8_t avrcp_query_shuffle_and_repeat_modes(uint16_t avrcp_cid){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_capabilities: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_COMMAND; - - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; - connection->command_type = AVRCP_CTYPE_STATUS; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); - connection->cmd_operands[3] = AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue; // PDU ID - connection->cmd_operands[4] = 0; - big_endian_store_16(connection->cmd_operands, 5, 5); // parameter length - connection->cmd_operands[7] = 4; // NumPlayerApplicationSettingAttributeID - // PlayerApplicationSettingAttributeID1 AVRCP Spec, Appendix F, 133 - connection->cmd_operands[8] = 0x01; // equalizer (1-OFF, 2-ON) - connection->cmd_operands[9] = 0x02; // repeat (1-off, 2-single track, 3-all tracks, 4-group repeat) - connection->cmd_operands[10] = 0x03; // shuffle (1-off, 2-all tracks, 3-group shuffle) - connection->cmd_operands[11] = 0x04; // scan (1-off, 2-all tracks, 3-group scan) - connection->cmd_operands_length = 12; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -static uint8_t avrcp_set_current_player_application_setting_value(uint16_t avrcp_cid, uint8_t attr_id, uint8_t attr_value){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_capabilities: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - connection->state = AVCTP_W2_SEND_COMMAND; - - connection->transaction_label++; - connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; - connection->command_type = AVRCP_CTYPE_CONTROL; - connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; - connection->subunit_id = AVRCP_SUBUNIT_ID; - int pos = 0; - big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); - pos += 3; - connection->cmd_operands[pos++] = AVRCP_PDU_ID_SetPlayerApplicationSettingValue; // PDU ID - connection->cmd_operands[pos++] = 0; - // Parameter Length - big_endian_store_16(connection->cmd_operands, pos, 3); - pos += 2; - connection->cmd_operands[pos++] = 2; - connection->cmd_operands_length = pos; - connection->cmd_operands[pos++] = attr_id; - connection->cmd_operands[pos++] = attr_value; - connection->cmd_operands_length = pos; - avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); - return ERROR_CODE_SUCCESS; -} - -uint8_t avrcp_set_shuffle_mode(uint16_t avrcp_cid, avrcp_shuffle_mode_t mode){ - if (mode < AVRCP_SHUFFLE_MODE_OFF || mode > AVRCP_SHUFFLE_MODE_GROUP) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; - return avrcp_set_current_player_application_setting_value(avrcp_cid, 0x03, mode); -} - -uint8_t avrcp_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode){ - if (mode < AVRCP_REPEAT_MODE_OFF || mode > AVRCP_REPEAT_MODE_GROUP) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; - return avrcp_set_current_player_application_setting_value(avrcp_cid, 0x02, mode); -} - -uint8_t avrcp_disconnect(uint16_t avrcp_cid){ - avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); - if (!connection){ - log_error("avrcp_get_capabilities: could not find a connection."); - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; - l2cap_disconnect(connection->l2cap_signaling_cid, 0); - return ERROR_CODE_SUCCESS; -} \ No newline at end of file diff --git a/src/classic/avrcp.h b/src/classic/avrcp.h index 10a6fb1b5..7e63b59f1 100644 --- a/src/classic/avrcp.h +++ b/src/classic/avrcp.h @@ -54,7 +54,19 @@ extern "C" { #endif #define BT_SIG_COMPANY_ID 0x001958 -/* API_START */ + +typedef enum { + AVRCP_SINGLE_PACKET= 0, + AVRCP_START_PACKET , + AVRCP_CONTINUE_PACKET , + AVRCP_END_PACKET +} avrcp_packet_type_t; + +typedef enum { + AVRCP_COMMAND_FRAME = 0, + AVRCP_RESPONSE_FRAME +} avrcp_frame_type_t; + typedef enum { AVRCP_CAPABILITY_ID_COMPANY = 0x02, @@ -244,256 +256,15 @@ typedef struct { btstack_linked_list_t connections; btstack_packet_handler_t avrcp_callback; btstack_packet_handler_t packet_handler; -} avrcp_context_t; -typedef struct { - avrcp_connection_t * connection; - avrcp_context_t * avrcp_context; + // SDP query + uint16_t avrcp_cid; uint16_t avrcp_l2cap_psm; uint16_t avrcp_version; uint16_t avrcp_browsing_l2cap_psm; uint16_t avrcp_browsing_version; uint8_t role_supported; -} avrcp_sdp_query_context_t; - - -/** - * @brief AVDTP Sink service record. - * @param service - * @param service_record_handle - * @param browsing 1 - supported, 0 - not supported - * @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h - * @param service_name - * @param service_provider_name - */ -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); - -/** - * @brief AVDTP Sink service record. - * @param service - * @param service_record_handle - * @param browsing 1 - supported, 0 - not supported - * @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h - * @param service_name - * @param service_provider_name - */ -void avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name); - - -/** - * @brief Set up AVDTP Sink device. - */ -void avrcp_controller_init(void); - -/** - * @brief Register callback for the AVRCP Sink client. - * @param callback - */ -void avrcp_register_packet_handler(btstack_packet_handler_t callback); - -/** - * @brief Connect to device with a Bluetooth address. - * @param bd_addr - * @param avrcp_cid - * @returns status - */ - - -uint8_t avrcp_connect(bd_addr_t bd_addr, avrcp_context_t * context, uint16_t * avrcp_cid); -uint8_t avrcp_controller_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid); - -/** - * @brief Disconnect from AVRCP target - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_disconnect(uint16_t avrcp_cid); - -/** - * @brief Unit info. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_unit_info(uint16_t avrcp_cid); - -/** - * @brief Get capabilities. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_get_supported_company_ids(uint16_t avrcp_cid); - -/** - * @brief Get supported Events. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_get_supported_events(uint16_t avrcp_cid); - -/** - * @brief Play. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_play(uint16_t avrcp_cid); - -/** - * @brief Stop. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_stop(uint16_t avrcp_cid); - -/** - * @brief Pause. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_pause(uint16_t avrcp_cid); - -/** - * @brief Start Fast Forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_start_fast_forward(uint16_t avrcp_cid); - -/** - * @brief Stop Fast Forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_stop_fast_forward(uint16_t avrcp_cid); - -/** - * @brief Single step - fast forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_fast_forward(uint16_t avrcp_cid); - -/** - * @brief Stop Rewind. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_start_rewind(uint16_t avrcp_cid); - -/** - * @brief Stop Rewind. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_stop_rewind(uint16_t avrcp_cid); - -/** - * @brief Single step rewind. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_rewind(uint16_t avrcp_cid); - -/** - * @brief Forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_forward(uint16_t avrcp_cid); - -/** - * @brief Backward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_backward(uint16_t avrcp_cid); - - -/** - * @brief Get play status. Returns event of type AVRCP_SUBEVENT_PLAY_STATUS (length, position, play_status). - * If TG does not support SongLength And SongPosition on TG, then TG shall return 0xFFFFFFFF. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_get_play_status(uint16_t avrcp_cid); - -/** - * @brief Enable notification. Response via AVRCP_SUBEVENT_ENABLE_NOTIFICATION_COMPLETE. - * @param avrcp_cid - * @param event_id - * @returns status - */ -uint8_t avrcp_enable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id); - -/** - * @brief Disable notification. Response via AVRCP_SUBEVENT_ENABLE_NOTIFICATION_COMPLETE. - * @param avrcp_cid - * @param event_id - * @returns status - */ -uint8_t avrcp_disable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id); - -/** - * @brief Get info on now playing media. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_get_now_playing_info(uint16_t avrcp_cid); - -/** - * @brief Set absolute volume 0-127 (corresponds to 0-100%). Response via AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_set_absolute_volume(uint16_t avrcp_cid, uint8_t volume); - -/** - * @brief Turns the volume to high. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_volume_up(uint16_t avrcp_cid); - -/** - * @brief Turns the volume to low. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_volume_down(uint16_t avrcp_cid); - -/** - * @brief Puts the sound out. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_mute(uint16_t avrcp_cid); - -/** - * @brief Skip to next playing media. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_skip(uint16_t avrcp_cid); - -/** - * @brief Query repeat and shuffle mode. Response via AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_query_shuffle_and_repeat_modes(uint16_t avrcp_cid); - -/** - * @brief Set shuffle mode. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_set_shuffle_mode(uint16_t avrcp_cid, avrcp_shuffle_mode_t mode); - -/** - * @brief Set repeat mode. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. - * @param avrcp_cid - * @returns status - */ -uint8_t avrcp_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode); +} avrcp_context_t; const char * avrcp_subunit2str(uint16_t index); const char * avrcp_event2str(uint16_t index); @@ -504,7 +275,17 @@ const char * avrcp_ctype2str(uint8_t index); const char * avrcp_repeat2str(uint8_t index); const char * avrcp_shuffle2str(uint8_t index); -/* API_END */ +void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context); + +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 avrcp_connect(bd_addr_t bd_addr, avrcp_context_t * context, uint16_t * avrcp_cid); +void avrcp_emit_connection_established(btstack_packet_handler_t callback, uint16_t avrcp_cid, bd_addr_t addr, uint8_t status); +void avrcp_emit_connection_closed(btstack_packet_handler_t callback, uint16_t avrcp_cid); + +avrcp_connection_t * get_avrcp_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid, avrcp_context_t * context); +avrcp_connection_t * get_avrcp_connection_for_avrcp_cid(uint16_t l2cap_cid, avrcp_context_t * context); +void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid); + #if defined __cplusplus } #endif diff --git a/src/classic/avrcp_controller.c b/src/classic/avrcp_controller.c new file mode 100644 index 000000000..24aea127d --- /dev/null +++ b/src/classic/avrcp_controller.c @@ -0,0 +1,1076 @@ +/* + * Copyright (C) 2016 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +#define __BTSTACK_FILE__ "avrcp.c" + +#include +#include +#include +#include + +#include "btstack.h" +#include "classic/avrcp.h" +#include "classic/avrcp_controller.h" + + +/* +Category 1: Player/Recorder +Category 2: Monitor/Amplifier +Category 3: Tuner +Category 4: Menu +*/ + +/* controller supported features +Bit 0 = Category 1 +Bit 1 = Category 2 +Bit 2 = Category 3 +Bit 3 = Category 4 +Bit 4-5 = RFA +Bit 6 = Supports browsing +Bit 7-15 = RFA +The bits for supported categories are set to 1. Others are set to 0. +*/ + +/* target supported features +Bit 0 = Category 1 +Bit 1 = Category 2 +Bit 2 = Category 3 +Bit 3 = Category 4 +Bit 4 = Player Application Settings. Bit 0 should be set for this bit to be set. +Bit 5 = Group Navigation. Bit 0 should be set for this bit to be set. +Bit 6 = Supports browsing*4 +Bit 7 = Supports multiple media player applications +Bit 8-15 = RFA +The bits for supported categories are set to 1. Others are set to 0. +*/ + +static avrcp_context_t avrcp_controller_context; + +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){ + avrcp_create_sdp_record(1, service, service_record_handle, browsing, supported_features, service_name, service_provider_name); +} + +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){ + 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_SHUFFLE_AND_REPEAT_MODE; + little_endian_store_16(event, pos, avrcp_cid); + pos += 2; + event[pos++] = ctype; + event[pos++] = repeat_mode; + event[pos++] = shuffle_mode; + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); +} + +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){ + if (!callback) return; + uint8_t event[7]; + int pos = 0; + event[pos++] = HCI_EVENT_AVRCP_META; + event[pos++] = sizeof(event) - 2; + event[pos++] = subevent; + little_endian_store_16(event, pos, avrcp_cid); + pos += 2; + event[pos++] = ctype; + event[pos++] = operation_id; + (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); +} + +static void avrcp_press_and_hold_timeout_handler(btstack_timer_source_t * timer){ + UNUSED(timer); + avrcp_connection_t * connection = btstack_run_loop_get_timer_context(timer); + btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout + btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer); + connection->state = AVCTP_W2_SEND_PRESS_COMMAND; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); +} + +static void avrcp_press_and_hold_timer_start(avrcp_connection_t * connection){ + btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer); + btstack_run_loop_set_timer_handler(&connection->press_and_hold_cmd_timer, avrcp_press_and_hold_timeout_handler); + btstack_run_loop_set_timer_context(&connection->press_and_hold_cmd_timer, connection); + btstack_run_loop_set_timer(&connection->press_and_hold_cmd_timer, 2000); // 2 seconds timeout + btstack_run_loop_add_timer(&connection->press_and_hold_cmd_timer); +} + +static void avrcp_press_and_hold_timer_stop(avrcp_connection_t * connection){ + connection->continuous_fast_forward_cmd = 0; + btstack_run_loop_remove_timer(&connection->press_and_hold_cmd_timer); +} + +static uint8_t request_pass_through_release_control_cmd(avrcp_connection_t * connection){ + connection->state = AVCTP_W2_SEND_RELEASE_COMMAND; + if (connection->continuous_fast_forward_cmd){ + avrcp_press_and_hold_timer_stop(connection); + } + connection->cmd_operands[0] = 0x80 | connection->cmd_operands[0]; + connection->transaction_label++; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +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){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, context); + if (!connection){ + log_error("avrcp: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_PRESS_COMMAND; + connection->command_opcode = AVRCP_CMD_OPCODE_PASS_THROUGH; + connection->command_type = AVRCP_CTYPE_CONTROL; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + connection->cmd_operands_length = 0; + + connection->continuous_fast_forward_cmd = continuous_fast_forward_cmd; + connection->cmd_operands_length = 2; + connection->cmd_operands[0] = opid; + if (playback_speed > 0){ + connection->cmd_operands[2] = playback_speed; + connection->cmd_operands_length++; + } + connection->cmd_operands[1] = connection->cmd_operands_length - 2; + + if (connection->continuous_fast_forward_cmd){ + avrcp_press_and_hold_timer_start(connection); + } + + connection->transaction_label++; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +static uint8_t request_single_pass_through_press_control_cmd(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint16_t playback_speed){ + return request_pass_through_press_control_cmd(avrcp_cid, opid, playback_speed, 0, &avrcp_controller_context); +} + +static uint8_t request_continuous_pass_through_press_control_cmd(uint16_t avrcp_cid, avrcp_operation_id_t opid, uint16_t playback_speed){ + return request_pass_through_press_control_cmd(avrcp_cid, opid, playback_speed, 1, &avrcp_controller_context); +} + +static int avrcp_send_cmd(uint16_t cid, avrcp_connection_t * connection){ + uint8_t command[30]; + int pos = 0; + // transport header + // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) + command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; + // Profile IDentifier (PID) + command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; + command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; + + // command_type + command[pos++] = connection->command_type; + // subunit_type | subunit ID + command[pos++] = (connection->subunit_type << 3) | connection->subunit_id; + // opcode + command[pos++] = (uint8_t)connection->command_opcode; + // operands + memcpy(command+pos, connection->cmd_operands, connection->cmd_operands_length); + pos += connection->cmd_operands_length; + + 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){ + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_NOTIFY; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + 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_length = pos; + // AVRCP_SPEC_V14.pdf 166 + // answer page 61 +} + +static uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ + uint8_t cmd_opcode_index = 5; + if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; + return packet[cmd_opcode_index]; +} + + +static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){ + uint8_t operands[20]; + uint8_t opcode; + int pos = 3; + // uint8_t transport_header = packet[0]; + // uint8_t transaction_label = transport_header >> 4; + // uint8_t packet_type = (transport_header & 0x0F) >> 2; + // uint8_t frame_type = (transport_header & 0x03) >> 1; + // uint8_t ipid = transport_header & 0x01; + // uint8_t byte_value = packet[2]; + // uint16_t pid = (byte_value << 8) | packet[2]; + + avrcp_command_type_t ctype = (avrcp_command_type_t) packet[pos++]; + uint8_t byte_value = packet[pos++]; + avrcp_subunit_type_t subunit_type = (avrcp_subunit_type_t) (byte_value >> 3); + avrcp_subunit_type_t subunit_id = (avrcp_subunit_type_t) (byte_value & 0x07); + opcode = packet[pos++]; + + // printf(" Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n", + // transport_header, transaction_label, packet_type, frame_type, ipid, pid); + // // printf_hexdump(packet+pos, size-pos); + + uint8_t pdu_id; + uint16_t param_length; + switch (avrcp_cmd_opcode(packet,size)){ + case AVRCP_CMD_OPCODE_UNIT_INFO:{ + if (connection->state != AVCTP_W2_RECEIVE_RESPONSE) return; + connection->state = AVCTP_CONNECTION_OPENED; + + // operands: + memcpy(operands, packet+pos, 5); + uint8_t unit_type = operands[1] >> 3; + uint8_t unit = operands[1] & 0x07; + uint32_t company_id = operands[2] << 16 | operands[3] << 8 | operands[4]; + 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", + ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id ); + break; + } + case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: + if (size - pos < 7) { + log_error("avrcp: wrong packet size"); + return; + }; + // operands: + memcpy(operands, packet+pos, 7); + pos += 7; + // uint32_t company_id = operands[0] << 16 | operands[1] << 8 | operands[2]; + pdu_id = operands[3]; + + if (connection->state != AVCTP_W2_RECEIVE_RESPONSE && pdu_id != AVRCP_PDU_ID_REGISTER_NOTIFICATION){ + log_info("AVRCP_CMD_OPCODE_VENDOR_DEPENDENT state %d", connection->state); + return; + } + connection->state = AVCTP_CONNECTION_OPENED; + + + // uint8_t unit_type = operands[4] >> 3; + // uint8_t unit = operands[4] & 0x07; + param_length = big_endian_read_16(operands, 5); + + // 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", + // ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id ); + + // if (ctype == AVRCP_CTYPE_RESPONSE_INTERIM) return; + log_info(" VENDOR DEPENDENT response: pdu id 0x%02x, param_length %d, status %s", pdu_id, param_length, avrcp_ctype2str(ctype)); + switch (pdu_id){ + case AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue:{ + uint8_t num_attributes = packet[pos++]; + int i; + avrcp_repeat_mode_t repeat_mode = AVRCP_REPEAT_MODE_INVALID; + avrcp_shuffle_mode_t shuffle_mode = AVRCP_SHUFFLE_MODE_INVALID; + for (i = 0; i < num_attributes; i++){ + uint8_t attribute_id = packet[pos++]; + uint8_t value = packet[pos++]; + switch (attribute_id){ + case 0x02: + repeat_mode = (avrcp_repeat_mode_t) value; + break; + case 0x03: + shuffle_mode = (avrcp_shuffle_mode_t) value; + break; + default: + break; + } + } + avrcp_emit_repeat_and_shuffle_mode(avrcp_controller_context.avrcp_callback, connection->avrcp_cid, ctype, repeat_mode, shuffle_mode); + break; + } + case AVRCP_PDU_ID_SetPlayerApplicationSettingValue:{ + uint8_t event[6]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + case AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME:{ + uint8_t event[7]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + event[offset++] = packet[pos++]; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + case AVRCP_PDU_ID_GET_CAPABILITIES:{ + avrcp_capability_id_t capability_id = (avrcp_capability_id_t) packet[pos++]; + uint8_t capability_count = packet[pos++]; + int i; + switch (capability_id){ + case AVRCP_CAPABILITY_ID_COMPANY: + // log_info("Supported companies %d: ", capability_count); + for (i = 0; i < capability_count; i++){ + uint32_t company_id = big_endian_read_24(packet, pos); + pos += 3; + log_info(" 0x%06x, ", company_id); + } + break; + case AVRCP_CAPABILITY_ID_EVENT: + // log_info("Supported events %d: ", capability_count); + for (i = 0; i < capability_count; i++){ + uint8_t event_id = packet[pos++]; + log_info(" 0x%02x %s", event_id, avrcp_event2str(event_id)); + } + break; + } + break; + } + case AVRCP_PDU_ID_GET_PLAY_STATUS:{ + uint32_t song_length = big_endian_read_32(packet, pos); + pos += 4; + uint32_t song_position = big_endian_read_32(packet, pos); + pos += 4; + uint8_t play_status = packet[pos]; + // log_info(" GET_PLAY_STATUS length 0x%04X, position 0x%04X, status %s", song_length, song_position, avrcp_play_status2str(play_status)); + + uint8_t event[15]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_PLAY_STATUS; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + little_endian_store_32(event, offset, song_length); + offset += 4; + little_endian_store_32(event, offset, song_position); + offset += 4; + event[offset++] = play_status; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + case AVRCP_PDU_ID_REGISTER_NOTIFICATION:{ + avrcp_notification_event_id_t event_id = (avrcp_notification_event_id_t) packet[pos++]; + uint16_t event_mask = (1 << event_id); + uint16_t reset_event_mask = ~event_mask; + switch (ctype){ + case AVRCP_CTYPE_RESPONSE_INTERIM: + // register as enabled + connection->notifications_enabled |= 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: + // 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_to_deregister &= reset_event_mask; + } + break; + default: + connection->notifications_to_register &= reset_event_mask; + connection->notifications_enabled &= reset_event_mask; + connection->notifications_to_deregister &= reset_event_mask; + break; + } + + switch (event_id){ + case AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED:{ + uint8_t event[7]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_PLAYBACK_STATUS_CHANGED; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + event[offset++] = packet[pos]; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + case AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED:{ + uint8_t event[6]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + case AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED:{ + uint8_t event[6]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_NOW_PLAYING_CONTENT_CHANGED; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + case AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED:{ + uint8_t event[6]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_AVAILABLE_PLAYERS_CHANGED; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + case AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED:{ + uint8_t event[7]; + int offset = 0; + event[offset++] = HCI_EVENT_AVRCP_META; + event[offset++] = sizeof(event) - 2; + event[offset++] = AVRCP_SUBEVENT_NOTIFICATION_VOLUME_CHANGED; + little_endian_store_16(event, offset, connection->avrcp_cid); + offset += 2; + event[offset++] = ctype; + event[offset++] = packet[pos++] & 0x7F; + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + break; + } + // case AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:{ + // uint8_t num_PlayerApplicationSettingAttributes = packet[pos++]; + // int i; + // for (i = 0; i < num_PlayerApplicationSettingAttributes; i++){ + // uint8_t PlayerApplicationSetting_AttributeID = packet[pos++]; + // uint8_t PlayerApplicationSettingValueID = packet[pos++]; + // } + // break; + // } + // case AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED: + // uint16_t player_id = big_endian_read_16(packet, pos); + // pos += 2; + // uint16_t uid_counter = big_endian_read_16(packet, pos); + // pos += 2; + // break; + // case AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED: + // uint16_t uid_counter = big_endian_read_16(packet, pos); + // pos += 2; + // break; + default: + log_info("avrcp: not implemented"); + 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:{ + uint8_t num_attributes = packet[pos++]; + int i; + struct item { + uint16_t len; + uint8_t * value; + } items[AVRCP_MEDIA_ATTR_COUNT]; + memset(items, 0, sizeof(items)); + + uint16_t string_attributes_len = 0; + uint8_t num_string_attributes = 0; + uint16_t total_event_payload_for_string_attributes = HCI_EVENT_PAYLOAD_SIZE-2; + uint16_t max_string_attribute_value_len = 0; + if (ctype == AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE || ctype == AVRCP_CTYPE_RESPONSE_CHANGED_STABLE){ + for (i = 0; i < num_attributes; i++){ + avrcp_media_attribute_id_t attr_id = (avrcp_media_attribute_id_t) big_endian_read_32(packet, pos); + pos += 4; + // uint16_t character_set = big_endian_read_16(packet, pos); + pos += 2; + uint16_t attr_value_length = big_endian_read_16(packet, pos); + pos += 2; + + // debug - to remove later + uint8_t value[100]; + uint16_t value_len = sizeof(value) <= attr_value_length? sizeof(value) - 1 : attr_value_length; + memcpy(value, packet+pos, value_len); + value[value_len] = 0; + // printf("Now Playing Info %s: %s \n", attribute2str(attr_id), value); + // end debug + + if ((attr_id >= 1) || (attr_id <= AVRCP_MEDIA_ATTR_COUNT)) { + items[attr_id-1].len = attr_value_length; + items[attr_id-1].value = &packet[pos]; + switch (attr_id){ + case AVRCP_MEDIA_ATTR_TITLE: + case AVRCP_MEDIA_ATTR_ARTIST: + case AVRCP_MEDIA_ATTR_ALBUM: + case AVRCP_MEDIA_ATTR_GENRE: + num_string_attributes++; + string_attributes_len += attr_value_length; + if (max_string_attribute_value_len < attr_value_length){ + max_string_attribute_value_len = attr_value_length; + } + break; + default: + break; + } + } + pos += attr_value_length; + } + } + + // subtract space for fixed fields + total_event_payload_for_string_attributes -= 14 + 4; // 4 for '\0' + + // @TODO optimize space by repeatedly decreasing max_string_attribute_value_len until it fits into buffer instead of crude divion + 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; + // 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); + + const uint8_t attribute_order[] = { + AVRCP_MEDIA_ATTR_TRACK, + AVRCP_MEDIA_ATTR_TOTAL_TRACKS, + AVRCP_MEDIA_ATTR_SONG_LENGTH, + AVRCP_MEDIA_ATTR_TITLE, + AVRCP_MEDIA_ATTR_ARTIST, + AVRCP_MEDIA_ATTR_ALBUM, + AVRCP_MEDIA_ATTR_GENRE + }; + + uint8_t event[HCI_EVENT_BUFFER_SIZE]; + event[0] = HCI_EVENT_AVRCP_META; + pos = 2; + event[pos++] = AVRCP_SUBEVENT_NOW_PLAYING_INFO; + little_endian_store_16(event, pos, connection->avrcp_cid); + pos += 2; + event[pos++] = ctype; + for (i = 0; i < sizeof(attribute_order); i++){ + avrcp_media_attribute_id_t attr_id = (avrcp_media_attribute_id_t) attribute_order[i]; + uint16_t value_len = 0; + switch (attr_id){ + case AVRCP_MEDIA_ATTR_TITLE: + case AVRCP_MEDIA_ATTR_ARTIST: + case AVRCP_MEDIA_ATTR_ALBUM: + case AVRCP_MEDIA_ATTR_GENRE: + if (items[attr_id-1].value){ + value_len = items[attr_id-1].len <= max_value_len ? items[attr_id-1].len : max_value_len; + } + event[pos++] = value_len + 1; + if (value_len){ + memcpy(event+pos, items[attr_id-1].value, value_len); + pos += value_len; + } + event[pos++] = 0; + break; + case AVRCP_MEDIA_ATTR_SONG_LENGTH: + if (items[attr_id-1].value){ + little_endian_store_32(event, pos, btstack_atoi((char *)items[attr_id-1].value)); + } else { + little_endian_store_32(event, pos, 0); + } + pos += 4; + break; + case AVRCP_MEDIA_ATTR_TRACK: + case AVRCP_MEDIA_ATTR_TOTAL_TRACKS: + if (items[attr_id-1].value){ + event[pos++] = btstack_atoi((char *)items[attr_id-1].value); + } else { + event[pos++] = 0; + } + break; + } + } + event[1] = pos - 2; + // printf_hexdump(event, pos); + (*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, pos); + break; + } + default: + break; + } + break; + case AVRCP_CMD_OPCODE_PASS_THROUGH:{ + // 0x80 | connection->cmd_operands[0] + uint8_t operation_id = packet[pos++]; + switch (connection->state){ + case AVCTP_W2_RECEIVE_PRESS_RESPONSE: + if (connection->continuous_fast_forward_cmd){ + connection->state = AVCTP_W4_STOP; + } else { + connection->state = AVCTP_W2_SEND_RELEASE_COMMAND; + } + break; + case AVCTP_W2_RECEIVE_RESPONSE: + connection->state = AVCTP_CONNECTION_OPENED; + break; + default: + // check for notifications? move state transition down + // log_info("AVRCP_CMD_OPCODE_PASS_THROUGH state %d\n", connection->state); + break; + } + if (connection->state == AVCTP_W4_STOP){ + avrcp_emit_operation_status(avrcp_controller_context.avrcp_callback, AVRCP_SUBEVENT_OPERATION_START, connection->avrcp_cid, ctype, operation_id); + } + if (connection->state == AVCTP_CONNECTION_OPENED) { + // RELEASE response + operation_id = operation_id & 0x7F; + avrcp_emit_operation_status(avrcp_controller_context.avrcp_callback, AVRCP_SUBEVENT_OPERATION_COMPLETE, connection->avrcp_cid, ctype, operation_id); + } + if (connection->state == AVCTP_W2_SEND_RELEASE_COMMAND){ + // PRESS response + request_pass_through_release_control_cmd(connection); + } + break; + } + default: + break; + } +} + +static void avrcp_controller_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; + avrcp_send_cmd(connection->l2cap_signaling_cid, connection); + break; + case AVCTP_W2_SEND_COMMAND: + case AVCTP_W2_SEND_RELEASE_COMMAND: + connection->state = AVCTP_W2_RECEIVE_RESPONSE; + avrcp_send_cmd(connection->l2cap_signaling_cid, connection); + break; + case AVCTP_CONNECTION_OPENED: + if (connection->notifications_to_register != 0){ + for (i = 1; i <= AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED; i++){ + if (connection->notifications_to_register & (1<notifications_to_register &= ~ (1 << i); + avrcp_prepare_notification(connection, (avrcp_notification_event_id_t) i); + connection->state = AVCTP_W2_RECEIVE_RESPONSE; + avrcp_send_cmd(connection->l2cap_signaling_cid, connection); + return; + } + } + } + return; + default: + return; + } +} + +static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + avrcp_connection_t * connection; + + switch (packet_type) { + case L2CAP_DATA_PACKET: + connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_controller_context); + if (!connection) break; + avrcp_handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); + break; + case HCI_EVENT_PACKET: + switch (hci_event_packet_get_type(packet)){ + case L2CAP_EVENT_CAN_SEND_NOW: + connection = get_avrcp_connection_for_l2cap_signaling_cid(channel, &avrcp_controller_context); + if (!connection) break; + avrcp_controller_handle_can_send_now(connection); + break; + default: + avrcp_packet_handler(packet_type, channel, packet, size, &avrcp_controller_context); + break; + } + default: + break; + } +} + +void avrcp_controller_init(void){ + avrcp_controller_context.role = AVRCP_CONTROLLER; + avrcp_controller_context.connections = NULL; + avrcp_controller_context.packet_handler = avrcp_controller_packet_handler; + l2cap_register_service(&avrcp_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0); +} + +void avrcp_controller_register_packet_handler(btstack_packet_handler_t callback){ + if (callback == NULL){ + log_error("avrcp_register_packet_handler called with NULL callback"); + return; + } + avrcp_controller_context.avrcp_callback = callback; +} + +uint8_t avrcp_controller_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid){ + return avrcp_connect(bd_addr, &avrcp_controller_context, avrcp_cid); +} + +uint8_t avrcp_controller_unit_info(uint16_t avrcp_cid){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_unit_info: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_UNIT_INFO; + connection->command_type = AVRCP_CTYPE_STATUS; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT; //vendor unique + connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE; + memset(connection->cmd_operands, 0xFF, connection->cmd_operands_length); + connection->cmd_operands_length = 5; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +static uint8_t avrcp_controller_get_capabilities(uint16_t avrcp_cid, uint8_t capability_id){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_capabilities: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_STATUS; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); + connection->cmd_operands[3] = AVRCP_PDU_ID_GET_CAPABILITIES; // PDU ID + connection->cmd_operands[4] = 0; + big_endian_store_16(connection->cmd_operands, 5, 1); // parameter length + connection->cmd_operands[7] = capability_id; // capability ID + connection->cmd_operands_length = 8; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_controller_get_supported_company_ids(uint16_t avrcp_cid){ + return avrcp_controller_get_capabilities(avrcp_cid, AVRCP_CAPABILITY_ID_COMPANY); +} + +uint8_t avrcp_controller_get_supported_events(uint16_t avrcp_cid){ + return avrcp_controller_get_capabilities(avrcp_cid, AVRCP_CAPABILITY_ID_EVENT); +} + + +uint8_t avrcp_controller_play(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_PLAY, 0); +} + +uint8_t avrcp_controller_stop(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_STOP, 0); +} + +uint8_t avrcp_controller_pause(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_PAUSE, 0); +} + +uint8_t avrcp_controller_forward(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FORWARD, 0); +} + +uint8_t avrcp_controller_backward(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_BACKWARD, 0); +} + +uint8_t avrcp_controller_start_rewind(uint16_t avrcp_cid){ + return request_continuous_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_REWIND, 0); +} + +uint8_t avrcp_controller_volume_up(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_VOLUME_UP, 0); +} + +uint8_t avrcp_controller_volume_down(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_VOLUME_DOWN, 0); +} + +uint8_t avrcp_controller_mute(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_MUTE, 0); +} + +uint8_t avrcp_controller_skip(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_SKIP, 0); +} + +uint8_t avrcp_controller_stop_rewind(uint16_t avrcp_cid){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_stop_rewind: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_W4_STOP) return ERROR_CODE_COMMAND_DISALLOWED; + return request_pass_through_release_control_cmd(connection); +} + +uint8_t avrcp_controller_start_fast_forward(uint16_t avrcp_cid){ + return request_continuous_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FAST_FORWARD, 0); +} + +uint8_t avrcp_controller_fast_forward(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_FAST_FORWARD, 0); +} + +uint8_t avrcp_controller_rewind(uint16_t avrcp_cid){ + return request_single_pass_through_press_control_cmd(avrcp_cid, AVRCP_OPERATION_ID_REWIND, 0); +} + + +uint8_t avrcp_controller_stop_fast_forward(uint16_t avrcp_cid){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_stop_fast_forward: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_W4_STOP) return ERROR_CODE_COMMAND_DISALLOWED; + return request_pass_through_release_control_cmd(connection); +} + +uint8_t avrcp_controller_get_play_status(uint16_t avrcp_cid){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_play_status: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_STATUS; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); + connection->cmd_operands[3] = AVRCP_PDU_ID_GET_PLAY_STATUS; + connection->cmd_operands[4] = 0; // reserved(upper 6) | packet_type -> 0 + big_endian_store_16(connection->cmd_operands, 5, 0); // parameter length + connection->cmd_operands_length = 7; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_controller_enable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_play_status: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + avrcp_register_notification(connection, event_id); + return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_controller_disable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_play_status: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + connection->notifications_to_deregister |= (1 << event_id); + return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_controller_get_now_playing_info(uint16_t avrcp_cid){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_capabilities: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_STATUS; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + int pos = 0; + big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); + pos += 3; + connection->cmd_operands[pos++] = AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES; // PDU ID + connection->cmd_operands[pos++] = 0; + + // Parameter Length + big_endian_store_16(connection->cmd_operands, pos, 9); + pos += 2; + + // write 8 bytes value + memset(connection->cmd_operands + pos, 0, 8); // identifier: PLAYING + pos += 8; + + connection->cmd_operands[pos++] = 0; // attribute count, if 0 get all attributes + // every attribute is 4 bytes long + + connection->cmd_operands_length = pos; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_controller_set_absolute_volume(uint16_t avrcp_cid, uint8_t volume){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_capabilities: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_CONTROL; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + int pos = 0; + big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); + pos += 3; + connection->cmd_operands[pos++] = AVRCP_PDU_ID_SET_ABSOLUTE_VOLUME; // PDU ID + connection->cmd_operands[pos++] = 0; + + // Parameter Length + big_endian_store_16(connection->cmd_operands, pos, 1); + pos += 2; + connection->cmd_operands[pos++] = volume; + + connection->cmd_operands_length = pos; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_controller_query_shuffle_and_repeat_modes(uint16_t avrcp_cid){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_capabilities: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_STATUS; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID); + connection->cmd_operands[3] = AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue; // PDU ID + connection->cmd_operands[4] = 0; + big_endian_store_16(connection->cmd_operands, 5, 5); // parameter length + connection->cmd_operands[7] = 4; // NumPlayerApplicationSettingAttributeID + // PlayerApplicationSettingAttributeID1 AVRCP Spec, Appendix F, 133 + connection->cmd_operands[8] = 0x01; // equalizer (1-OFF, 2-ON) + connection->cmd_operands[9] = 0x02; // repeat (1-off, 2-single track, 3-all tracks, 4-group repeat) + connection->cmd_operands[10] = 0x03; // shuffle (1-off, 2-all tracks, 3-group shuffle) + connection->cmd_operands[11] = 0x04; // scan (1-off, 2-all tracks, 3-group scan) + connection->cmd_operands_length = 12; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +static uint8_t avrcp_controller_set_current_player_application_setting_value(uint16_t avrcp_cid, uint8_t attr_id, uint8_t attr_value){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_capabilities: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + connection->command_type = AVRCP_CTYPE_CONTROL; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + int pos = 0; + big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); + pos += 3; + connection->cmd_operands[pos++] = AVRCP_PDU_ID_SetPlayerApplicationSettingValue; // PDU ID + connection->cmd_operands[pos++] = 0; + // Parameter Length + big_endian_store_16(connection->cmd_operands, pos, 3); + pos += 2; + connection->cmd_operands[pos++] = 2; + connection->cmd_operands_length = pos; + connection->cmd_operands[pos++] = attr_id; + connection->cmd_operands[pos++] = attr_value; + connection->cmd_operands_length = pos; + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + +uint8_t avrcp_controller_set_shuffle_mode(uint16_t avrcp_cid, avrcp_shuffle_mode_t mode){ + if (mode < AVRCP_SHUFFLE_MODE_OFF || mode > AVRCP_SHUFFLE_MODE_GROUP) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; + return avrcp_controller_set_current_player_application_setting_value(avrcp_cid, 0x03, mode); +} + +uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode){ + if (mode < AVRCP_REPEAT_MODE_OFF || mode > AVRCP_REPEAT_MODE_GROUP) return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; + return avrcp_controller_set_current_player_application_setting_value(avrcp_cid, 0x02, mode); +} + +uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid){ + avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); + if (!connection){ + log_error("avrcp_get_capabilities: could not find a connection."); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + l2cap_disconnect(connection->l2cap_signaling_cid, 0); + return ERROR_CODE_SUCCESS; +} \ No newline at end of file diff --git a/src/classic/avrcp_controller.h b/src/classic/avrcp_controller.h new file mode 100644 index 000000000..6a3ad7790 --- /dev/null +++ b/src/classic/avrcp_controller.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2016 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/* + * avrcp.h + * + * Audio/Video Remote Control Profile + * + */ + +#ifndef __AVRCP_CONTROLLER_H +#define __AVRCP_CONTROLLER_H + +#include +#include "btstack_run_loop.h" +#include "btstack_linked_list.h" +#include "avrcp.h" + +#if defined __cplusplus +extern "C" { +#endif + +/* API_START */ + +/** + * @brief AVDTP Sink service record. + * @param service + * @param service_record_handle + * @param browsing 1 - supported, 0 - not supported + * @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h + * @param service_name + * @param service_provider_name + */ +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); + +/** + * @brief Set up AVDTP Sink device. + */ +void avrcp_controller_init(void); + +/** + * @brief Register callback for the AVRCP Sink client. + * @param callback + */ +void avrcp_controller_register_packet_handler(btstack_packet_handler_t callback); + +/** + * @brief Connect to device with a Bluetooth address. + * @param bd_addr + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_connect(bd_addr_t bd_addr, uint16_t * avrcp_cid); + +/** + * @brief Disconnect from AVRCP target + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid); + +/** + * @brief Unit info. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_unit_info(uint16_t avrcp_cid); + +/** + * @brief Get capabilities. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_get_supported_company_ids(uint16_t avrcp_cid); + +/** + * @brief Get supported Events. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_get_supported_events(uint16_t avrcp_cid); + +/** + * @brief Play. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_play(uint16_t avrcp_cid); + +/** + * @brief Stop. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_stop(uint16_t avrcp_cid); + +/** + * @brief Pause. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_pause(uint16_t avrcp_cid); + +/** + * @brief Start Fast Forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_start_fast_forward(uint16_t avrcp_cid); + +/** + * @brief Stop Fast Forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_stop_fast_forward(uint16_t avrcp_cid); + +/** + * @brief Single step - fast forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_fast_forward(uint16_t avrcp_cid); + +/** + * @brief Stop Rewind. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_start_rewind(uint16_t avrcp_cid); + +/** + * @brief Stop Rewind. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_stop_rewind(uint16_t avrcp_cid); + +/** + * @brief Single step rewind. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_rewind(uint16_t avrcp_cid); + +/** + * @brief Forward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_forward(uint16_t avrcp_cid); + +/** + * @brief Backward. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_backward(uint16_t avrcp_cid); + + +/** + * @brief Get play status. Returns event of type AVRCP_SUBEVENT_PLAY_STATUS (length, position, play_status). + * If TG does not support SongLength And SongPosition on TG, then TG shall return 0xFFFFFFFF. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_get_play_status(uint16_t avrcp_cid); + +/** + * @brief Enable notification. Response via AVRCP_SUBEVENT_ENABLE_NOTIFICATION_COMPLETE. + * @param avrcp_cid + * @param event_id + * @returns status + */ +uint8_t avrcp_controller_enable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id); + +/** + * @brief Disable notification. Response via AVRCP_SUBEVENT_ENABLE_NOTIFICATION_COMPLETE. + * @param avrcp_cid + * @param event_id + * @returns status + */ +uint8_t avrcp_controller_disable_notification(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id); + +/** + * @brief Get info on now playing media. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_get_now_playing_info(uint16_t avrcp_cid); + +/** + * @brief Set absolute volume 0-127 (corresponds to 0-100%). Response via AVRCP_SUBEVENT_SET_ABSOLUTE_VOLUME_RESPONSE + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_set_absolute_volume(uint16_t avrcp_cid, uint8_t volume); + +/** + * @brief Turns the volume to high. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_volume_up(uint16_t avrcp_cid); + +/** + * @brief Turns the volume to low. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_volume_down(uint16_t avrcp_cid); + +/** + * @brief Puts the sound out. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_mute(uint16_t avrcp_cid); + +/** + * @brief Skip to next playing media. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_skip(uint16_t avrcp_cid); + +/** + * @brief Query repeat and shuffle mode. Response via AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_query_shuffle_and_repeat_modes(uint16_t avrcp_cid); + +/** + * @brief Set shuffle mode. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_set_shuffle_mode(uint16_t avrcp_cid, avrcp_shuffle_mode_t mode); + +/** + * @brief Set repeat mode. Event AVRCP_SUBEVENT_OPERATION_COMPLETE returns operation id and status. + * @param avrcp_cid + * @returns status + */ +uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t mode); + +/* API_END */ +#if defined __cplusplus +} +#endif + +#endif // __AVRCP_CONTROLLER_H \ No newline at end of file diff --git a/src/classic/avrcp_target.h b/src/classic/avrcp_target.h new file mode 100644 index 000000000..d60a2ac9e --- /dev/null +++ b/src/classic/avrcp_target.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/* + * avrcp.h + * + * Audio/Video Remote Control Profile + * + */ + +#ifndef __AVRCP_H +#define __AVRCP_H + +#include +#include "avrcp.h" + +#if defined __cplusplus +extern "C" { +#endif + +/* API_START */ + + +/** + * @brief AVDTP Sink service record. + * @param service + * @param service_record_handle + * @param browsing 1 - supported, 0 - not supported + * @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h + * @param service_name + * @param service_provider_name + */ +void avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, const char * service_name, const char * service_provider_name); + +/* API_END */ +#if defined __cplusplus +} +#endif + +#endif // __AVRCP_H \ No newline at end of file diff --git a/test/avrcp/Makefile b/test/avrcp/Makefile index 92f0c221e..2b484b33b 100644 --- a/test/avrcp/Makefile +++ b/test/avrcp/Makefile @@ -66,7 +66,7 @@ SBC_ENCODER += \ AVRCP += \ avrcp.c \ -AVRCP_TESTS = avrcp_test +AVRCP_TESTS = avrcp_controller_test CORE_OBJ = $(CORE:.c=.o) COMMON_OBJ = $(COMMON:.c=.o) @@ -76,7 +76,7 @@ AVRCP_OBJ = $(AVRCP:.c=.o) all: ${AVRCP_TESTS} -avrcp_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVRCP_OBJ} avrcp_test.o +avrcp_controller_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVRCP_OBJ} avrcp_controller.o avrcp_controller_test.o ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ test: all diff --git a/test/avrcp/avrcp_controller_test b/test/avrcp/avrcp_controller_test new file mode 100755 index 0000000000000000000000000000000000000000..bfc1f0a7d6ef46f68f1317f44d13c27cc9b373c3 GIT binary patch literal 375192 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ͯZ7oT1HsB`bqm9*izCcmV#?-P_t^Jk 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 XN_4FJX)`O3I^Lq=^v1KqWr6< #include -#include "btstack_config.h" -#include "btstack_debug.h" -#include "btstack_event.h" -#include "btstack_memory.h" -#include "btstack_run_loop.h" -#include "gap.h" -#include "hci.h" -#include "hci_cmd.h" -#include "hci_dump.h" -#include "l2cap.h" -#include "btstack_stdin.h" -#include "classic/avrcp.h" +#include "btstack.h" #define AVRCP_BROWSING_ENABLED 0 static btstack_packet_callback_registration_t hci_event_callback_registration; @@ -99,8 +88,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe } printf("Channel successfully opened: %s, avrcp_cid 0x%02x\n", bd_addr_to_str(event_addr), avrcp_cid); // automatically enable notifications - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED); return; } case AVRCP_SUBEVENT_CONNECTION_RELEASED: @@ -240,95 +229,95 @@ static void stdin_process(char cmd){ break; case 'B': printf(" - Disconnect\n"); - avrcp_disconnect(avrcp_cid); + avrcp_controller_disconnect(avrcp_cid); break; case 'i': printf(" - get play status\n"); - avrcp_get_play_status(avrcp_cid); + avrcp_controller_get_play_status(avrcp_cid); break; case 'j': printf(" - get now playing info\n"); - avrcp_get_now_playing_info(avrcp_cid); + avrcp_controller_get_now_playing_info(avrcp_cid); break; case 'k': printf(" - play\n"); - avrcp_play(avrcp_cid); + avrcp_controller_play(avrcp_cid); break; case 'K': printf(" - stop\n"); - avrcp_stop(avrcp_cid); + avrcp_controller_stop(avrcp_cid); break; case 'L': printf(" - pause\n"); - avrcp_pause(avrcp_cid); + avrcp_controller_pause(avrcp_cid); break; case 'm': printf(" - start fast forward\n"); - avrcp_start_fast_forward(avrcp_cid); + avrcp_controller_start_fast_forward(avrcp_cid); break; case 'M': printf(" - stop fast forward\n"); - avrcp_stop_fast_forward(avrcp_cid); + avrcp_controller_stop_fast_forward(avrcp_cid); break; case 'n': printf(" - start rewind\n"); - avrcp_start_rewind(avrcp_cid); + avrcp_controller_start_rewind(avrcp_cid); break; case 'N': printf(" - stop rewind\n"); - avrcp_stop_rewind(avrcp_cid); + avrcp_controller_stop_rewind(avrcp_cid); break; case 'o': printf(" - forward\n"); - avrcp_forward(avrcp_cid); + avrcp_controller_forward(avrcp_cid); break; case 'O': printf(" - backward\n"); - avrcp_backward(avrcp_cid); + avrcp_controller_backward(avrcp_cid); break; case 'p': printf(" - volume up\n"); - avrcp_volume_up(avrcp_cid); + avrcp_controller_volume_up(avrcp_cid); break; case 'P': printf(" - volume down\n"); - avrcp_volume_down(avrcp_cid); + avrcp_controller_volume_down(avrcp_cid); break; case 'r': printf(" - absolute volume of 50 percent\n"); - avrcp_set_absolute_volume(avrcp_cid, 50); + avrcp_controller_set_absolute_volume(avrcp_cid, 50); break; case 's': printf(" - mute\n"); - avrcp_mute(avrcp_cid); + avrcp_controller_mute(avrcp_cid); break; case 't': printf(" - skip\n"); - avrcp_skip(avrcp_cid); + avrcp_controller_skip(avrcp_cid); break; case 'u': printf(" - query repeat and shuffle mode\n"); - avrcp_query_shuffle_and_repeat_modes(avrcp_cid); + avrcp_controller_query_shuffle_and_repeat_modes(avrcp_cid); break; case 'v': printf(" - repeat single track\n"); - avrcp_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_SINGLE_TRACK); + avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_SINGLE_TRACK); break; case 'x': printf(" - repeat all tracks\n"); - avrcp_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_ALL_TRACKS); + avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_ALL_TRACKS); break; case 'X': printf(" - disable repeat mode\n"); - avrcp_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_OFF); + avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_OFF); break; case 'z': printf(" - shuffle all tracks\n"); - avrcp_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_ALL_TRACKS); + avrcp_controller_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_ALL_TRACKS); break; case 'Z': printf(" - disable shuffle mode\n"); - avrcp_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_OFF); + avrcp_controller_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_OFF); break; default: show_usage(); @@ -349,7 +338,7 @@ int btstack_main(int argc, const char * argv[]){ // Initialize AVRCP COntroller avrcp_controller_init(); - avrcp_register_packet_handler(&packet_handler); + avrcp_controller_register_packet_handler(&packet_handler); // Initialize SDP sdp_init(); diff --git a/test/pts/Makefile b/test/pts/Makefile index 369084aec..f43a5b9d1 100644 --- a/test/pts/Makefile +++ b/test/pts/Makefile @@ -82,12 +82,12 @@ SBC_ENCODER_OBJ = $(SBC_ENCODER:.c=.o) AVDTP_OBJ = $(AVDTP:.c=.o) EXAMPLES = iopt ble_peripheral_test ble_central_test l2cap_test classic_test bnep_test hsp_ag_test hsp_hs_test sco_loopback le_data_channel -EXAMPLES = avdtp_source_test avdtp_sink_test le_data_channel avrcp_test +EXAMPLES = avdtp_source_test avdtp_sink_test le_data_channel avrcp_controller_test all: ${EXAMPLES} # compile .gatt descriptions -avrcp_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SM_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} sdp_client.o avrcp.o avrcp_test.o +avrcp_controller_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SM_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} sdp_client.o avrcp.o avrcp_controller.o avrcp_controller_test.o ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ avdtp_sink_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SM_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} avdtp_sink_test.o diff --git a/test/pts/avrcp_test.c b/test/pts/avrcp_test.c index 77ffe9fdb..060564ee2 100644 --- a/test/pts/avrcp_test.c +++ b/test/pts/avrcp_test.c @@ -42,7 +42,6 @@ #include #include "btstack.h" -// #include "wav_util.h" #define AVRCP_BROWSING_ENABLED 0 @@ -290,7 +289,7 @@ static void stdin_process(char cmd){ break; case 'C': printf("Disconnect AVRCP\n"); - avrcp_disconnect(avrcp_cid); + avrcp_controller_disconnect(avrcp_cid); break; case '\n': @@ -298,197 +297,197 @@ static void stdin_process(char cmd){ break; case 'q': printf("AVRCP: get capabilities: supported events\n"); - avrcp_get_supported_events(avrcp_cid); + avrcp_controller_get_supported_events(avrcp_cid); break; case 'w': printf("AVRCP: get unit info\n"); - avrcp_unit_info(avrcp_cid); + avrcp_controller_unit_info(avrcp_cid); break; case 'r': printf("AVRCP: get play status\n"); - avrcp_get_play_status(avrcp_cid); + avrcp_controller_get_play_status(avrcp_cid); break; case 't': printf("AVRCP: get now playing info\n"); - avrcp_get_now_playing_info(avrcp_cid); + avrcp_controller_get_now_playing_info(avrcp_cid); break; case '1': printf("AVRCP: play\n"); - avrcp_play(avrcp_cid); + avrcp_controller_play(avrcp_cid); break; case '2': printf("AVRCP: stop\n"); - avrcp_stop(avrcp_cid); + avrcp_controller_stop(avrcp_cid); break; case '3': printf("AVRCP: pause\n"); - avrcp_pause(avrcp_cid); + avrcp_controller_pause(avrcp_cid); break; case '4': printf("AVRCP: fast forward\n"); - avrcp_fast_forward(avrcp_cid); + avrcp_controller_fast_forward(avrcp_cid); break; case '5': printf("AVRCP: rewind\n"); - avrcp_rewind(avrcp_cid); + avrcp_controller_rewind(avrcp_cid); break; case '6': printf("AVRCP: forward\n"); - avrcp_forward(avrcp_cid); + avrcp_controller_forward(avrcp_cid); break; case '7': printf("AVRCP: backward\n"); - avrcp_backward(avrcp_cid); + avrcp_controller_backward(avrcp_cid); break; case '8': printf("AVRCP: volume up\n"); - avrcp_volume_up(avrcp_cid); + avrcp_controller_volume_up(avrcp_cid); break; case '9': printf("AVRCP: volume down\n"); - avrcp_volume_down(avrcp_cid); + avrcp_controller_volume_down(avrcp_cid); break; case '0': printf("AVRCP: mute\n"); - avrcp_mute(avrcp_cid); + avrcp_controller_mute(avrcp_cid); break; case 'R': printf("AVRCP: absolute volume of 50 percent\n"); - avrcp_set_absolute_volume(avrcp_cid, 50); + avrcp_controller_set_absolute_volume(avrcp_cid, 50); break; case 'u': printf("AVRCP: skip\n"); - avrcp_skip(avrcp_cid); + avrcp_controller_skip(avrcp_cid); break; case 'i': printf("AVRCP: query repeat and shuffle mode\n"); - avrcp_query_shuffle_and_repeat_modes(avrcp_cid); + avrcp_controller_query_shuffle_and_repeat_modes(avrcp_cid); break; case 'o': printf("AVRCP: repeat single track\n"); - avrcp_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_SINGLE_TRACK); + avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_SINGLE_TRACK); break; case 'x': printf("AVRCP: repeat all tracks\n"); - avrcp_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_ALL_TRACKS); + avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_ALL_TRACKS); break; case 'X': printf("AVRCP: disable repeat mode\n"); - avrcp_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_OFF); + avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_OFF); break; case 'z': printf("AVRCP: shuffle all tracks\n"); - avrcp_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_ALL_TRACKS); + avrcp_controller_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_ALL_TRACKS); break; case 'Z': printf("AVRCP: disable shuffle mode\n"); - avrcp_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_OFF); + avrcp_controller_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_OFF); break; case 'a': printf("AVRCP: enable notification PLAYBACK_STATUS_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED); break; case 's': printf("AVRCP: enable notification TRACK_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED); break; case 'd': printf("AVRCP: enable notification TRACK_REACHED_END\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END); break; case 'f': printf("AVRCP: enable notification TRACK_REACHED_START\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START); break; case 'g': printf("AVRCP: enable notification PLAYBACK_POS_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED); break; case 'h': printf("AVRCP: enable notification BATT_STATUS_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED); break; case 'j': printf("AVRCP: enable notification SYSTEM_STATUS_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED); break; case 'k': printf("AVRCP: enable notification PLAYER_APPLICATION_SETTING_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED); break; case 'l': printf("AVRCP: enable notification NOW_PLAYING_CONTENT_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED); break; case 'm': printf("AVRCP: enable notification AVAILABLE_PLAYERS_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED); break; case 'n': printf("AVRCP: enable notification ADDRESSED_PLAYER_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED); break; case 'y': printf("AVRCP: enable notification UIDS_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED); break; case 'v': printf("AVRCP: enable notification VOLUME_CHANGED\n"); - avrcp_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED); + avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED); break; case 'A': printf("AVRCP: disable notification PLAYBACK_STATUS_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED); break; case 'S': printf("AVRCP: disable notification TRACK_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED); break; case 'D': printf("AVRCP: disable notification TRACK_REACHED_END\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_END); break; case 'F': printf("AVRCP: disable notification TRACK_REACHED_START\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_REACHED_START); break; case 'G': printf("AVRCP: disable notification PLAYBACK_POS_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED); break; case 'H': printf("AVRCP: disable notification BATT_STATUS_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED); break; case 'J': printf("AVRCP: disable notification SYSTEM_STATUS_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED); break; case 'K': printf("AVRCP: disable notification PLAYER_APPLICATION_SETTING_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED); break; case 'L': printf("AVRCP: disable notification NOW_PLAYING_CONTENT_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED); break; case 'M': printf("AVRCP: disable notification AVAILABLE_PLAYERS_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_AVAILABLE_PLAYERS_CHANGED); break; case 'N': printf("AVRCP: disable notification ADDRESSED_PLAYER_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_ADDRESSED_PLAYER_CHANGED); break; case 'Y': printf("AVRCP: disable notification UIDS_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED); break; case 'V': printf("AVRCP: disable notification VOLUME_CHANGED\n"); - avrcp_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED); + avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED); break; default: show_usage(); @@ -521,7 +520,7 @@ int btstack_main(int argc, const char * argv[]){ // Initialize AVRCP COntroller avrcp_controller_init(); - avrcp_register_packet_handler(&packet_handler); + avrcp_controller_register_packet_handler(&packet_handler); // Initialize SDP sdp_init();