mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-03 01:20:35 +00:00
avrcp browsing: handle incoming avrcp connection
This commit is contained in:
parent
3dfd0eb6df
commit
c0a054f62c
@ -399,19 +399,19 @@ static void show_usage(void){
|
||||
bd_addr_t iut_address;
|
||||
gap_local_bd_addr(iut_address);
|
||||
printf("\n--- Bluetooth AVRCP Controller Connection Test Console %s ---\n", bd_addr_to_str(iut_address));
|
||||
printf("e - AVRCP Controller create connection to addr %s\n", bd_addr_to_str(device_addr));
|
||||
printf("c - AVRCP Browsing Controller create connection to addr %s\n", bd_addr_to_str(device_addr));
|
||||
printf("C - AVRCP Browsing Controller disconnect\n");
|
||||
printf("E - AVRCP Controller disconnect\n");
|
||||
printf("c - AVRCP Controller create connection to addr %s\n", bd_addr_to_str(device_addr));
|
||||
printf("e - AVRCP Browsing Controller create connection to addr %s\n", bd_addr_to_str(device_addr));
|
||||
printf("E - AVRCP Browsing Controller disconnect\n");
|
||||
printf("C - AVRCP Controller disconnect\n");
|
||||
|
||||
printf("a - Set first found player as addressed player\n");
|
||||
printf("b - Set first found player as browsed player\n");
|
||||
printf("I - Set first found player as addressed player\n");
|
||||
printf("O - Set first found player as browsed player\n");
|
||||
|
||||
printf("m - Get media players\n");
|
||||
printf("f - Browse folders\n");
|
||||
printf("u - Go up one level\n");
|
||||
printf("d - Go down one level\n");
|
||||
printf("i - Browse media items\n");
|
||||
printf("p - Get media players\n");
|
||||
printf("Q - Browse folders\n");
|
||||
printf("P - Go up one level\n");
|
||||
printf("W - Go down one level\n");
|
||||
printf("T - Browse media items\n");
|
||||
printf("---\n");
|
||||
}
|
||||
#endif
|
||||
@ -429,11 +429,11 @@ static void stdin_process(char cmd){
|
||||
}
|
||||
|
||||
switch (cmd){
|
||||
case 'e':
|
||||
case 'c':
|
||||
printf(" - Create AVRCP connection for control to addr %s.\n", bd_addr_to_str(device_addr));
|
||||
status = avrcp_controller_connect(device_addr, &avrcp_cid);
|
||||
break;
|
||||
case 'E':
|
||||
case 'C':
|
||||
if (avrcp_connected){
|
||||
printf(" - AVRCP Controller disconnect from addr %s.\n", bd_addr_to_str(device_addr));
|
||||
status = avrcp_controller_disconnect(avrcp_cid);
|
||||
@ -442,7 +442,7 @@ static void stdin_process(char cmd){
|
||||
printf("AVRCP Controller already disconnected\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'e':
|
||||
if (!avrcp_connected) {
|
||||
printf(" You must first create AVRCP connection for control to addr %s.\n", bd_addr_to_str(device_addr));
|
||||
break;
|
||||
@ -450,7 +450,7 @@ static void stdin_process(char cmd){
|
||||
printf(" - Create AVRCP connection for browsing to addr %s.\n", bd_addr_to_str(device_addr));
|
||||
status = avrcp_browsing_controller_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid);
|
||||
break;
|
||||
case 'C':
|
||||
case 'E':
|
||||
if (avrcp_browsing_connected){
|
||||
printf(" - AVRCP Browsing Controller disconnect from addr %s.\n", bd_addr_to_str(device_addr));
|
||||
status = avrcp_browsing_controller_disconnect(browsing_cid);
|
||||
@ -470,7 +470,7 @@ static void stdin_process(char cmd){
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case 'a':
|
||||
case 'I':
|
||||
if (player_index < 0) {
|
||||
printf("Get media players first\n");
|
||||
break;
|
||||
@ -478,7 +478,7 @@ static void stdin_process(char cmd){
|
||||
printf("Set addressed player\n");
|
||||
status = avrcp_browsing_controller_set_addressed_player(browsing_cid, players[0]);
|
||||
break;
|
||||
case 'b':
|
||||
case 'O':
|
||||
if (player_index < 0) {
|
||||
printf("Get media players first\n");
|
||||
break;
|
||||
@ -486,26 +486,26 @@ static void stdin_process(char cmd){
|
||||
printf("Set browsed player\n");
|
||||
status = avrcp_browsing_controller_set_browsed_player(browsing_cid, players[0]);
|
||||
break;
|
||||
case 'm':
|
||||
case 'p':
|
||||
printf("AVRCP Browsing: get media players\n");
|
||||
player_index = -1;
|
||||
status = avrcp_browsing_controller_get_media_players(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
|
||||
break;
|
||||
case 'f':
|
||||
case 'Q':
|
||||
printf("AVRCP Browsing: browse folders\n");
|
||||
folder_index = -1;
|
||||
status = avrcp_browsing_controller_browse_file_system(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
|
||||
break;
|
||||
case 'i':
|
||||
case 'P':
|
||||
printf("AVRCP Browsing: browse media items\n");
|
||||
avrcp_browsing_controller_browse_media(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
|
||||
break;
|
||||
case 'u':
|
||||
case 'W':
|
||||
printf("AVRCP Browsing: go up one level\n");
|
||||
status = avrcp_browsing_controller_go_up_one_level(browsing_cid);
|
||||
folder_index = -1;
|
||||
break;
|
||||
case 'd':
|
||||
case 'T':
|
||||
if (folder_index < 0 && !parent_folder_set){
|
||||
printf("AVRCP Browsing: no folders available\n");
|
||||
break;
|
||||
|
@ -244,6 +244,7 @@ typedef enum{
|
||||
typedef enum {
|
||||
AVCTP_CONNECTION_IDLE,
|
||||
AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE,
|
||||
AVCTP_CONNECTION_W4_ERTM_CONFIGURATION,
|
||||
AVCTP_CONNECTION_W4_L2CAP_CONNECTED,
|
||||
AVCTP_CONNECTION_OPENED,
|
||||
AVCTP_W2_SEND_PRESS_COMMAND,
|
||||
@ -421,7 +422,7 @@ typedef struct {
|
||||
btstack_packet_handler_t avrcp_callback;
|
||||
btstack_packet_handler_t packet_handler;
|
||||
|
||||
// btstack_packet_handler_t browsing_callback;
|
||||
btstack_packet_handler_t browsing_avrcp_callback;
|
||||
btstack_packet_handler_t browsing_packet_handler;
|
||||
|
||||
// SDP query
|
||||
|
@ -46,6 +46,8 @@
|
||||
#include "classic/avrcp.h"
|
||||
#include "classic/avrcp_browsing_controller.h"
|
||||
|
||||
#define PSM_AVCTP_BROWSING 0x001b
|
||||
|
||||
void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context);
|
||||
static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
@ -97,6 +99,21 @@ static void avrcp_emit_browsing_connection_established(btstack_packet_handler_t
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void avrcp_emit_incoming_browsing_connection(btstack_packet_handler_t callback, uint16_t browsing_cid, bd_addr_t addr){
|
||||
printf("avrcp_emit_incoming_browsing_connection browsing_cid 0x%02x \n", browsing_cid);
|
||||
if (!callback) return;
|
||||
uint8_t event[11];
|
||||
int pos = 0;
|
||||
event[pos++] = HCI_EVENT_AVRCP_META;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
event[pos++] = AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION;
|
||||
reverse_bd_addr(addr,&event[pos]);
|
||||
pos += 6;
|
||||
little_endian_store_16(event, pos, browsing_cid);
|
||||
pos += 2;
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void avrcp_emit_browsing_connection_closed(btstack_packet_handler_t callback, uint16_t browsing_cid){
|
||||
if (!callback) return;
|
||||
uint8_t event[5];
|
||||
@ -159,32 +176,29 @@ void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
bd_addr_t event_addr;
|
||||
uint16_t local_cid;
|
||||
uint8_t status;
|
||||
avrcp_browsing_connection_t * connection = NULL;
|
||||
avrcp_browsing_connection_t * browsing_connection = NULL;
|
||||
avrcp_connection_t * avrcp_connection = NULL;
|
||||
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
|
||||
switch (hci_event_packet_get_type(packet)) {
|
||||
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
||||
avrcp_emit_browsing_connection_closed(context->avrcp_callback, 0);
|
||||
avrcp_emit_browsing_connection_closed(context->browsing_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);
|
||||
avrcp_connection = get_avrcp_connection_for_bd_addr(event_addr, context);
|
||||
if (!avrcp_connection) {
|
||||
log_error("No previously created AVRCP controller connections");
|
||||
printf("No previously created AVRCP controller connections");
|
||||
l2cap_decline_connection(local_cid);
|
||||
break;
|
||||
}
|
||||
connection = avrcp_browsing_create_connection(avrcp_connection);
|
||||
avrcp_connection->browsing_connection = connection;
|
||||
connection->l2cap_browsing_cid = local_cid;
|
||||
connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
|
||||
log_info("L2CAP_EVENT_INCOMING_CONNECTION browsing_cid 0x%02x, l2cap_signaling_cid 0x%02x", avrcp_connection->avrcp_browsing_cid, connection->l2cap_browsing_cid);
|
||||
// l2cap_accept_connection(local_cid);
|
||||
log_error("L2CAP Accepting incoming connection request in ERTM.");
|
||||
l2cap_accept_ertm_connection(local_cid, &connection->ertm_config, connection->ertm_buffer, connection->ertm_buffer_size);
|
||||
browsing_connection = avrcp_browsing_create_connection(avrcp_connection);
|
||||
browsing_connection->l2cap_browsing_cid = local_cid;
|
||||
browsing_connection->state = AVCTP_CONNECTION_W4_ERTM_CONFIGURATION;
|
||||
printf("Emit AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION browsing_cid 0x%02x, l2cap_signaling_cid 0x%02x\n", avrcp_connection->avrcp_browsing_cid, browsing_connection->l2cap_browsing_cid);
|
||||
avrcp_emit_incoming_browsing_connection(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr);
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_OPENED:
|
||||
@ -195,31 +209,26 @@ void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
avrcp_connection = get_avrcp_connection_for_bd_addr(event_addr, context);
|
||||
if (!avrcp_connection){
|
||||
log_error("Failed to find AVRCP connection for bd_addr %s", bd_addr_to_str(event_addr));
|
||||
avrcp_emit_browsing_connection_established(context->avrcp_callback, local_cid, event_addr, L2CAP_LOCAL_CID_DOES_NOT_EXIST);
|
||||
l2cap_disconnect(local_cid, 0); // reason isn't used
|
||||
break;
|
||||
}
|
||||
|
||||
connection = avrcp_connection->browsing_connection;
|
||||
if (!connection){
|
||||
log_error("Failed to alloc AVRCP connection structure");
|
||||
avrcp_emit_browsing_connection_established(context->avrcp_callback, local_cid, event_addr, BTSTACK_MEMORY_ALLOC_FAILED);
|
||||
avrcp_emit_browsing_connection_established(context->browsing_avrcp_callback, local_cid, event_addr, L2CAP_LOCAL_CID_DOES_NOT_EXIST);
|
||||
l2cap_disconnect(local_cid, 0); // reason isn't used
|
||||
break;
|
||||
}
|
||||
|
||||
browsing_connection = avrcp_connection->browsing_connection;
|
||||
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_browsing_connection_established(context->avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr, status);
|
||||
btstack_memory_avrcp_browsing_connection_free(connection);
|
||||
avrcp_emit_browsing_connection_established(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr, status);
|
||||
btstack_memory_avrcp_browsing_connection_free(browsing_connection);
|
||||
avrcp_connection->browsing_connection = NULL;
|
||||
break;
|
||||
}
|
||||
connection->l2cap_browsing_cid = local_cid;
|
||||
if (browsing_connection->state != AVCTP_CONNECTION_W4_L2CAP_CONNECTED) break;
|
||||
|
||||
browsing_connection->l2cap_browsing_cid = local_cid;
|
||||
|
||||
log_info("L2CAP_EVENT_CHANNEL_OPENED browsing cid 0x%02x, l2cap cid 0x%02x", avrcp_connection->avrcp_browsing_cid, connection->l2cap_browsing_cid);
|
||||
connection->state = AVCTP_CONNECTION_OPENED;
|
||||
avrcp_emit_browsing_connection_established(context->avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr, ERROR_CODE_SUCCESS);
|
||||
log_info("L2CAP_EVENT_CHANNEL_OPENED browsing cid 0x%02x, l2cap cid 0x%02x", avrcp_connection->avrcp_browsing_cid, browsing_connection->l2cap_browsing_cid);
|
||||
browsing_connection->state = AVCTP_CONNECTION_OPENED;
|
||||
avrcp_emit_browsing_connection_established(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr, ERROR_CODE_SUCCESS);
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_CLOSED:
|
||||
@ -228,7 +237,7 @@ void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
avrcp_connection = get_avrcp_connection_for_browsing_l2cap_cid(local_cid, context);
|
||||
|
||||
if (avrcp_connection && avrcp_connection->browsing_connection){
|
||||
avrcp_emit_browsing_connection_closed(context->avrcp_callback, avrcp_connection->avrcp_browsing_cid);
|
||||
avrcp_emit_browsing_connection_closed(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid);
|
||||
// free connection
|
||||
btstack_memory_avrcp_browsing_connection_free(avrcp_connection->browsing_connection);
|
||||
avrcp_connection->browsing_connection = NULL;
|
||||
@ -480,7 +489,15 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
|
||||
|
||||
void avrcp_browsing_controller_init(void){
|
||||
avrcp_controller_context.browsing_packet_handler = avrcp_browsing_controller_packet_handler;
|
||||
l2cap_register_service(&avrcp_browsing_controller_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_0);
|
||||
l2cap_register_service(&avrcp_browsing_controller_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_0);
|
||||
}
|
||||
|
||||
void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback){
|
||||
if (callback == NULL){
|
||||
log_error("avrcp_browsing_controller_register_packet_handler called with NULL callback");
|
||||
return;
|
||||
}
|
||||
avrcp_controller_context.browsing_avrcp_callback = callback;
|
||||
}
|
||||
|
||||
uint8_t avrcp_browsing_controller_connect(bd_addr_t bd_addr, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid){
|
||||
@ -499,6 +516,48 @@ uint8_t avrcp_browsing_controller_disconnect(uint16_t avrcp_browsing_cid){
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t avrcp_avrcp_browsing_configure_incoming_connection(uint16_t avrcp_browsing_cid, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config){
|
||||
printf("avrcp_avrcp_browsing_configure_incoming_connection browsing cid 0x%02X\n", avrcp_browsing_cid);
|
||||
avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context);
|
||||
if (!avrcp_connection){
|
||||
printf("avrcp_avrcp_browsing_decline_incoming_connection: could not find a connection.\n");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (!avrcp_connection->browsing_connection){
|
||||
printf("avrcp_avrcp_browsing_decline_incoming_connection: no browsing connection.\n");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
|
||||
if (avrcp_connection->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){
|
||||
printf("avrcp_avrcp_browsing_decline_incoming_connection: browsing connection in a wrong state.\n");
|
||||
return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
}
|
||||
|
||||
avrcp_connection->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
|
||||
avrcp_connection->browsing_connection->ertm_buffer = ertm_buffer;
|
||||
avrcp_connection->browsing_connection->ertm_buffer_size = size;
|
||||
memcpy(&avrcp_connection->browsing_connection->ertm_config, ertm_config, sizeof(l2cap_ertm_config_t));
|
||||
printf("accept ertm connection\n");
|
||||
l2cap_accept_ertm_connection(avrcp_connection->browsing_connection->l2cap_browsing_cid, &avrcp_connection->browsing_connection->ertm_config, avrcp_connection->browsing_connection->ertm_buffer, avrcp_connection->browsing_connection->ertm_buffer_size);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t avrcp_avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing_cid){
|
||||
avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context);
|
||||
if (!avrcp_connection){
|
||||
log_error("avrcp_avrcp_browsing_decline_incoming_connection: could not find a connection.");
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (!avrcp_connection->browsing_connection) return ERROR_CODE_SUCCESS;
|
||||
if (avrcp_connection->browsing_connection->state > AVCTP_CONNECTION_W4_ERTM_CONFIGURATION) return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
|
||||
l2cap_decline_connection(avrcp_connection->browsing_connection->l2cap_browsing_cid);
|
||||
// free connection
|
||||
btstack_memory_avrcp_browsing_connection_free(avrcp_connection->browsing_connection);
|
||||
avrcp_connection->browsing_connection = NULL;
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve a listing of the contents of a folder.
|
||||
* @param scope 0-player list, 1-virtual file system, 2-search, 3-now playing
|
||||
|
@ -106,7 +106,7 @@ void avrcp_browsing_controller_init(void);
|
||||
* @brief Register callback for the AVRCP Browsing Controller client.
|
||||
* @param callback
|
||||
*/
|
||||
// void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback);
|
||||
void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
* @brief Connect to device with a Bluetooth address.
|
||||
@ -119,6 +119,24 @@ void avrcp_browsing_controller_init(void);
|
||||
*/
|
||||
uint8_t avrcp_browsing_controller_connect(bd_addr_t bd_addr, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid);
|
||||
|
||||
/**
|
||||
* @brief Configure incoming connection.
|
||||
* @param avrcp_browsing_cid
|
||||
* @param ertm_buffer
|
||||
* @param ertm_buffer_size
|
||||
* @param ertm_config
|
||||
* @returns status
|
||||
*/
|
||||
uint8_t avrcp_avrcp_browsing_configure_incoming_connection(uint16_t avrcp_browsing_cid, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config);
|
||||
|
||||
/**
|
||||
* @brief Decline incoming connection.
|
||||
* @param avrcp_browsing_cid
|
||||
* @returns status
|
||||
*/
|
||||
uint8_t avrcp_avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing_cid);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Disconnect from AVRCP target
|
||||
* @param avrcp_browsing_cid
|
||||
|
@ -1148,6 +1148,10 @@ uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid){
|
||||
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
|
||||
}
|
||||
if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
if (connection->browsing_connection){
|
||||
if (connection->browsing_connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED;
|
||||
l2cap_disconnect(connection->browsing_connection->l2cap_browsing_cid, 0);
|
||||
}
|
||||
l2cap_disconnect(connection->l2cap_signaling_cid, 0);
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user