a2dp source: handle incoming connection, send event to client on signaling connection established

This commit is contained in:
Milanka Ringwald 2017-08-16 16:06:05 +02:00
parent 2f6083d0d8
commit 5448c259b2
6 changed files with 105 additions and 33 deletions

View File

@ -306,6 +306,16 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return; if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
switch (packet[2]){ switch (packet[2]){
case A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED:
a2dp_subevent_incoming_connection_established_get_bd_addr(packet, address);
media_tracker.a2dp_cid = a2dp_subevent_incoming_connection_established_get_a2dp_cid(packet);
printf("A2DP: Incoming connection established: address %s, a2dp cid 0x%02x. Create stream on local seid %d.\n",
bd_addr_to_str(address), media_tracker.a2dp_cid, media_tracker.local_seid);
status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
if (status != ERROR_CODE_SUCCESS){
printf("Could not perform command, status 0x%2x\n", status);
}
break;
case A2DP_SUBEVENT_STREAM_ESTABLISHED: case A2DP_SUBEVENT_STREAM_ESTABLISHED:
a2dp_subevent_stream_established_get_bd_addr(packet, address); a2dp_subevent_stream_established_get_bd_addr(packet, address);
status = a2dp_subevent_stream_established_get_status(packet); status = a2dp_subevent_stream_established_get_status(packet);
@ -318,10 +328,12 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
printf("A2DP: Stream establishment failed: wrong local seid %d, expected %d.\n", local_seid, media_tracker.local_seid); printf("A2DP: Stream establishment failed: wrong local seid %d, expected %d.\n", local_seid, media_tracker.local_seid);
break; break;
} }
media_tracker.a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet); media_tracker.a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
printf("A2DP: Stream established: address %s, a2dp cid 0x%02x, local seid %d, remote seid %d.\n", bd_addr_to_str(address), printf("A2DP: Stream established: address %s, a2dp cid 0x%02x, local seid %d, remote seid %d.\n", bd_addr_to_str(address),
media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet)); media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet));
printf("Start playing mod.\n");
data_source = STREAM_MOD;
status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
break; break;
case A2DP_SUBEVENT_STREAM_STARTED: case A2DP_SUBEVENT_STREAM_STARTED:

View File

@ -1522,6 +1522,14 @@ typedef uint8_t sm_key_t[16];
*/ */
#define A2DP_SUBEVENT_COMMAND_REJECTED 0x09 #define A2DP_SUBEVENT_COMMAND_REJECTED 0x09
/**
* @format 12B Signaling channel is opened.
* @param subevent_code
* @param a2dp_cid
* @param bd_addr
*/
#define A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED 0x0A
/** AVRCP Subevent */ /** AVRCP Subevent */
/** /**

View File

@ -4964,6 +4964,25 @@ static inline uint8_t a2dp_subevent_command_rejected_get_signal_identifier(const
return event[6]; return event[6];
} }
/**
* @brief Get field a2dp_cid from event A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED
* @param event packet
* @return a2dp_cid
* @note: btstack_type 2
*/
static inline uint16_t a2dp_subevent_incoming_connection_established_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field bd_addr from event A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED
* @param event packet
* @param Pointer to storage for bd_addr
* @note: btstack_type B
*/
static inline void a2dp_subevent_incoming_connection_established_get_bd_addr(const uint8_t * event, bd_addr_t bd_addr){
reverse_bd_addr(&event[5], bd_addr);
}
/** /**
* @brief Get field status from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED * @brief Get field status from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED
* @param event packet * @param event packet

View File

@ -184,8 +184,23 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
sc.active_remote_sep = NULL; sc.active_remote_sep = NULL;
next_remote_sep_index_to_query = 0; next_remote_sep_index_to_query = 0;
if (!sc.local_stream_endpoint) {
app_state = A2DP_CONNECTED;
uint8_t event[11];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED;
little_endian_store_16(event, pos, cid);
pos += 2;
reverse_bd_addr(event+pos, sc.remote_addr);
pos += 6;
(*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
return;
}
app_state = A2DP_W2_DISCOVER_SEPS; app_state = A2DP_W2_DISCOVER_SEPS;
log_info("AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, avdtp cid 0x%02x ---", cid); // printf("AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, avdtp cid 0x%02x ---\n", cid);
avdtp_source_discover_stream_endpoints(cid); avdtp_source_discover_stream_endpoints(cid);
break; break;
@ -198,11 +213,14 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
sep.media_type = (avdtp_media_type_t) sep_media_type; sep.media_type = (avdtp_media_type_t) sep_media_type;
sep_type = avdtp_subevent_signaling_sep_found_get_sep_type(packet); sep_type = avdtp_subevent_signaling_sep_found_get_sep_type(packet);
sep.type = (avdtp_sep_type_t) sep_type; sep.type = (avdtp_sep_type_t) sep_type;
log_info("found sep: seid %u, in_use %d, media type %d, sep type %d (1-SNK)", sep.seid, sep.in_use, sep.media_type, sep.type); // printf("found sep: seid %u, in_use %d, media type %d, sep type %d (1-SNK)\n", sep.seid, sep.in_use, sep.media_type, sep.type);
break; break;
case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:{ case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:{
if (!sc.local_stream_endpoint) return; if (!sc.local_stream_endpoint) {
// printf("local seid %d \n", avdtp_subevent_signaling_media_codec_sbc_capability_get_local_seid(packet));
return;
}
uint8_t sampling_frequency = avdtp_choose_sbc_sampling_frequency(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet)); uint8_t sampling_frequency = avdtp_choose_sbc_sampling_frequency(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet));
uint8_t channel_mode = avdtp_choose_sbc_channel_mode(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet)); uint8_t channel_mode = avdtp_choose_sbc_channel_mode(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet));
uint8_t block_length = avdtp_choose_sbc_block_length(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet)); uint8_t block_length = avdtp_choose_sbc_block_length(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet));
@ -277,17 +295,17 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST); a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST);
break; break;
} }
log_info("Query get caps for seid %d", sc.active_remote_sep->seid); // printf("Query get caps for seid %d\n", sc.active_remote_sep->seid);
avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid);
break; break;
case A2DP_W2_GET_CAPABILITIES: case A2DP_W2_GET_CAPABILITIES:
case A2DP_W2_GET_ALL_CAPABILITIES: case A2DP_W2_GET_ALL_CAPABILITIES:
if (next_remote_sep_index_to_query < avdtp_source_remote_seps_num(cid)){ if (next_remote_sep_index_to_query < avdtp_source_remote_seps_num(cid)){
sc.active_remote_sep = avdtp_source_remote_sep(cid, next_remote_sep_index_to_query++); sc.active_remote_sep = avdtp_source_remote_sep(cid, next_remote_sep_index_to_query++);
log_info("Query get caps for seid %d", sc.active_remote_sep->seid); // printf("Query get caps for seid %d\n", sc.active_remote_sep->seid);
avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid); avdtp_source_get_capabilities(cid, sc.active_remote_sep->seid);
} else { } else {
log_info("No more remote seps found"); // printf("No more remote seps found\n");
app_state = A2DP_IDLE; app_state = A2DP_IDLE;
a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST); a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, cid, sc.remote_addr, 0, 0, AVDTP_SEID_DOES_NOT_EXIST);
} }

View File

@ -104,30 +104,36 @@ uint8_t avdtp_connect(bd_addr_t remote, avdtp_sep_type_t query_role, avdtp_conte
return BTSTACK_MEMORY_ALLOC_FAILED; return BTSTACK_MEMORY_ALLOC_FAILED;
} }
} }
if (connection->state != AVDTP_SIGNALING_CONNECTION_IDLE){
log_error("avdtp_connect: sink in wrong state"); *avdtp_cid = connection->avdtp_cid;
return AVDTP_CONNECTION_IN_WRONG_STATE;
}
if (!avdtp_cid) { if (!avdtp_cid) {
return L2CAP_LOCAL_CID_DOES_NOT_EXIST; return L2CAP_LOCAL_CID_DOES_NOT_EXIST;
} }
*avdtp_cid = connection->avdtp_cid;
connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE;
avdtp_context->avdtp_l2cap_psm = 0;
avdtp_context->avdtp_version = 0;
avdtp_context->avdtp_cid = connection->avdtp_cid; avdtp_context->avdtp_cid = connection->avdtp_cid;
avdtp_context->query_role = query_role;
uint8_t err;
sdp_query_context = avdtp_context; switch (connection->state){
case AVDTP_SIGNALING_CONNECTION_IDLE:
uint8_t err = sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, remote, BLUETOOTH_PROTOCOL_AVDTP); connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE;
if (err != ERROR_CODE_SUCCESS){ sdp_query_context = avdtp_context;
connection->state = AVDTP_SIGNALING_CONNECTION_IDLE; avdtp_context->avdtp_l2cap_psm = 0;
btstack_linked_list_remove(&avdtp_context->connections, (btstack_linked_item_t*) connection); avdtp_context->avdtp_version = 0;
btstack_memory_avdtp_connection_free(connection); avdtp_context->query_role = query_role;
return err; err = sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, remote, BLUETOOTH_PROTOCOL_AVDTP);
if (err != ERROR_CODE_SUCCESS){
connection->state = AVDTP_SIGNALING_CONNECTION_IDLE;
btstack_linked_list_remove(&avdtp_context->connections, (btstack_linked_item_t*) connection);
btstack_memory_avdtp_connection_free(connection);
}
return err;
case AVDTP_SIGNALING_CONNECTION_OPENED:
avdtp_signaling_emit_connection_established(avdtp_context->avdtp_callback, avdtp_context->avdtp_cid, connection->remote_addr, ERROR_CODE_SUCCESS);
break;
default:
log_error("avdtp_connect: sink in wrong state");
return AVDTP_CONNECTION_IN_WRONG_STATE;
} }
return ERROR_CODE_SUCCESS; return ERROR_CODE_SUCCESS;
} }
@ -432,7 +438,7 @@ static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c
// avdtp_remote_uuid = uuid; // avdtp_remote_uuid = uuid;
break; break;
case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK: case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK:
if (sdp_query_context->query_role != AVDTP_SINK) { if (sdp_query_context->query_role == AVDTP_SINK) {
sdp_query_context->role_supported = 1; sdp_query_context->role_supported = 1;
break; break;
} }
@ -490,7 +496,7 @@ static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c
case SDP_EVENT_QUERY_COMPLETE: case SDP_EVENT_QUERY_COMPLETE:
status = sdp_event_query_complete_get_status(packet); status = sdp_event_query_complete_get_status(packet);
if (status != ERROR_CODE_SUCCESS){ if (status != ERROR_CODE_SUCCESS){
avdtp_signaling_emit_connection_established(sdp_query_context->avdtp_callback, sdp_query_context->avdtp_cid, connection->remote_addr, L2CAP_SERVICE_DOES_NOT_EXIST); avdtp_signaling_emit_connection_established(sdp_query_context->avdtp_callback, sdp_query_context->avdtp_cid, connection->remote_addr, status);
btstack_linked_list_remove(&sdp_query_context->connections, (btstack_linked_item_t*) connection); btstack_linked_list_remove(&sdp_query_context->connections, (btstack_linked_item_t*) connection);
btstack_memory_avdtp_connection_free(connection); btstack_memory_avdtp_connection_free(connection);
log_info("AVDTP: SDP query failed with status 0x%02x.", status); log_info("AVDTP: SDP query failed with status 0x%02x.", status);

View File

@ -416,7 +416,7 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c
UNUSED(packet_type); UNUSED(packet_type);
UNUSED(channel); UNUSED(channel);
UNUSED(size); UNUSED(size);
uint8_t status;
des_iterator_t des_list_it; des_iterator_t des_list_it;
des_iterator_t prot_it; des_iterator_t prot_it;
// uint32_t avdtp_remote_uuid = 0; // uint32_t avdtp_remote_uuid = 0;
@ -544,13 +544,23 @@ static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t c
break; break;
case SDP_EVENT_QUERY_COMPLETE: 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); status = sdp_event_query_complete_get_status(packet);
if (status != ERROR_CODE_SUCCESS){
avrcp_emit_connection_established(sdp_query_context->avrcp_callback, connection->avrcp_cid, connection->remote_addr, status);
btstack_linked_list_remove(&sdp_query_context->connections, (btstack_linked_item_t*) connection);
btstack_memory_avrcp_connection_free(connection);
log_info("AVRCP: SDP query failed with status 0x%02x.", status);
break;
}
if (!sdp_query_context->role_supported || !sdp_query_context->avrcp_l2cap_psm){ if (!sdp_query_context->role_supported || !sdp_query_context->avrcp_l2cap_psm){
connection->state = AVCTP_CONNECTION_IDLE; connection->state = AVCTP_CONNECTION_IDLE;
avrcp_emit_connection_established(sdp_query_context->avrcp_callback, connection->avrcp_cid, connection->remote_addr, SDP_SERVICE_NOT_FOUND); avrcp_emit_connection_established(sdp_query_context->avrcp_callback, connection->avrcp_cid, connection->remote_addr, SDP_SERVICE_NOT_FOUND);
btstack_linked_list_remove(&sdp_query_context->connections, (btstack_linked_item_t*) connection);
btstack_memory_avrcp_connection_free(connection);
break; 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); // 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; 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); l2cap_create_channel(sdp_query_context->packet_handler, connection->remote_addr, sdp_query_context->avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
break; break;
@ -651,6 +661,5 @@ uint8_t avrcp_connect(bd_addr_t bd_addr, avrcp_context_t * context, uint16_t * a
sdp_query_context = context; sdp_query_context = context;
sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, bd_addr, BLUETOOTH_PROTOCOL_AVCTP); return sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, bd_addr, BLUETOOTH_PROTOCOL_AVCTP);
return ERROR_CODE_SUCCESS;
} }