Skip to content

Commit

Permalink
avrcp browsing: handle incoming avrcp connection
Browse files Browse the repository at this point in the history
  • Loading branch information
milamikica committed Dec 13, 2017
1 parent 3dfd0eb commit c0a054f
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 52 deletions.
44 changes: 22 additions & 22 deletions example/avrcp_browsing_client.c
Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -442,15 +442,15 @@ 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;
}
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);
Expand All @@ -470,42 +470,42 @@ static void stdin_process(char cmd){
}

switch (cmd) {
case 'a':
case 'I':
if (player_index < 0) {
printf("Get media players first\n");
break;
}
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;
}
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;
Expand Down
3 changes: 2 additions & 1 deletion src/classic/avrcp.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
115 changes: 87 additions & 28 deletions src/classic/avrcp_browsing_controller.c
Expand Up @@ -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);

Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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;
Expand Down Expand Up @@ -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){
Expand All @@ -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
Expand Down
20 changes: 19 additions & 1 deletion src/classic/avrcp_browsing_controller.h
Expand Up @@ -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.
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/classic/avrcp_controller.c
Expand Up @@ -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;
}

0 comments on commit c0a054f

Please sign in to comment.