ad2p: fix disconnect

This commit is contained in:
Milanka Ringwald 2017-08-30 11:05:20 +02:00
parent 88132161fe
commit a466d50862
8 changed files with 104 additions and 124 deletions

View File

@ -428,8 +428,7 @@ static void media_processing_close(void){
if (!media_initialized) return;
media_initialized = 0;
#ifdef STORE_SBC_TO_WAV_FILE
printf("WAV Writer: close file.\n");
#ifdef STORE_SBC_TO_WAV_FILE
wav_writer_close();
int total_frames_nr = state.good_frames_nr + state.bad_frames_nr + state.zero_frames_nr;
@ -750,7 +749,10 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
case A2DP_SUBEVENT_STREAM_RELEASED:
cid = a2dp_subevent_stream_released_get_a2dp_cid(packet);
if (cid != a2dp_cid) break;
if (cid != a2dp_cid) {
printf(" -- a2dp sink demo: unexpected cid 0x%02x instead of 0x%02x\n", cid, a2dp_cid);
break;
}
local_seid = a2dp_subevent_stream_released_get_local_seid(packet);
app_state = AVDTP_APPLICATION_IDLE;
printf(" -- a2dp sink demo: stream released, a2dp cid 0x%02X, local_seid %d\n", a2dp_cid, local_seid);
@ -758,9 +760,17 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
// paused/stopped
media_processing_close();
break;
case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
cid = a2dp_subevent_signaling_connection_released_get_a2dp_cid(packet);
if (cid != a2dp_cid) {
printf(" -- a2dp sink demo: unexpected cid 0x%02x instead of 0x%02x\n", cid, a2dp_cid);
break;
}
app_state = AVDTP_APPLICATION_IDLE;
printf(" -- a2dp sink demo: signaling connection released\n");
break;
default:
printf(" not implemented\n");
printf(" -- a2dp sink demo: not parsed 0x%02x\n", packet[2]);
break;
}
}
@ -823,7 +833,7 @@ static void stdin_process(char cmd){
status = a2dp_sink_establish_stream(device_addr, local_seid, &a2dp_cid);
break;
case 'B':
printf(" - Disconnect\n");
printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
status = avdtp_sink_disconnect(a2dp_cid);
break;
case 'c':
@ -831,7 +841,7 @@ static void stdin_process(char cmd){
status = avrcp_controller_connect(device_addr, &avrcp_cid);
break;
case 'C':
printf(" - Disconnect\n");
printf(" - AVRCP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
status = avrcp_controller_disconnect(avrcp_cid);
break;
@ -977,8 +987,7 @@ int btstack_main(int argc, const char * argv[]){
gap_set_local_name("A2DP Sink Demo 00:00:00:00:00:00");
gap_discoverable_control(1);
gap_set_class_of_device(0x200408);
printf("sdp, gap done\n");
printf("Starting BTstack ...\n");
// turn on!
hci_power_control(HCI_POWER_ON);

View File

@ -373,7 +373,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
printf("A2DP: Signaling released.\n");
break;
default:
printf("A2DP: event 0x%02x is not implemented\n", packet[2]);
printf("A2DP: event 0x%02x is not parsed\n", packet[2]);
break;
}
}

View File

@ -184,7 +184,7 @@ typedef uint8_t sm_key_t[16];
#define AVDTP_CONNECTION_DOES_NOT_EXIST 0xC1
#define AVDTP_CONNECTION_IN_WRONG_STATE 0xC2
#define AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE 0xC3
#define AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST 0xC4
#define AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST 0xC4
/* ENUM_END */
@ -1531,10 +1531,9 @@ typedef uint8_t sm_key_t[16];
#define A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED 0x0A
/**
* @format 121 Signaling channel is released.
* @format 12 Signaling channel is released.
* @param subevent_code
* @param a2dp_cid
* @param local_seid
*/
#define A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED 0x0B

View File

@ -4983,15 +4983,6 @@ static inline void a2dp_subevent_incoming_connection_established_get_bd_addr(con
static inline uint16_t a2dp_subevent_signaling_connection_released_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_signaling_connection_released_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field status from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED

View File

@ -219,14 +219,26 @@ static inline void a2dp_emit_stream_event(btstack_packet_handler_t callback, uin
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static inline void a2dp_emit_cmd_accepted(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
static inline void a2dp_emit_signaling_connection_released(btstack_packet_handler_t callback, uint16_t a2dp_cid){
if (!callback) return;
UNUSED(size);
packet[0] = HCI_EVENT_A2DP_META;
packet[2] = A2DP_SUBEVENT_COMMAND_ACCEPTED;
(*callback)(HCI_EVENT_PACKET, 0, packet, size);
uint8_t event[5];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED;
little_endian_store_16(event, pos, a2dp_cid);
pos += 2;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
// static inline void a2dp_emit_cmd_accepted(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
// if (!callback) return;
// UNUSED(size);
// packet[0] = HCI_EVENT_A2DP_META;
// packet[2] = A2DP_SUBEVENT_COMMAND_ACCEPTED;
// (*callback)(HCI_EVENT_PACKET, 0, packet, size);
// }
static inline void a2dp_emit_cmd_rejected(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
if (!callback) return;
UNUSED(size);
@ -305,7 +317,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_RELEASED, loc_seid);
break;
default:
a2dp_emit_cmd_accepted(a2dp_sink_context.a2dp_callback, packet, size);
// a2dp_emit_cmd_accepted(a2dp_sink_context.a2dp_callback, packet, size);
break;
}
break;
@ -324,6 +336,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
a2dp_emit_stream_event(a2dp_sink_context.a2dp_callback, cid, A2DP_SUBEVENT_STREAM_RELEASED, loc_seid);
break;
case AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
cid = avdtp_subevent_signaling_connection_released_get_avdtp_cid(packet);
a2dp_emit_signaling_connection_released(a2dp_sink_context.a2dp_callback, cid);
app_state = A2DP_IDLE;
break;
default:

View File

@ -93,6 +93,7 @@ uint8_t a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_me
* - A2DP_SUBEVENT_STREAM_STARTED: received when stream is started
* - A2DP_SUBEVENT_STREAM_SUSPENDED: received when stream is paused
* - A2DP_SUBEVENT_STREAM_RELEASED: received when stream is released
* - A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED: received when signaling channel is disconnected
*
* @param callback
*/

View File

@ -311,91 +311,6 @@ static void handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t
}
}
static void stream_endpoint_state_machine(avdtp_connection_t * connection, avdtp_stream_endpoint_t * stream_endpoint, uint8_t packet_type, uint8_t event, uint8_t *packet, uint16_t size, avdtp_context_t * context){
uint16_t local_cid;
uint8_t status;
bd_addr_t address;
if (!connection){
log_info("stream_endpoint_state_machine: connection does not exist.");
return;
}
switch (packet_type){
case L2CAP_DATA_PACKET:{
int offset = avdtp_read_signaling_header(&connection->signaling_packet, packet, size);
if (connection->signaling_packet.message_type == AVDTP_CMD_MSG){
avdtp_acceptor_stream_config_subsm(connection, packet, size, offset, context);
} else {
avdtp_initiator_stream_config_subsm(connection, packet, size, offset, context);
}
break;
}
case HCI_EVENT_PACKET:
if (!stream_endpoint){
log_error("stream_endpoint_state_machine: stream_endpoint does not exist.");
return;
}
switch (event){
case L2CAP_EVENT_CHANNEL_OPENED:
l2cap_event_channel_opened_get_address(packet, address);
if (stream_endpoint->l2cap_media_cid == 0){
status = l2cap_event_channel_opened_get_status(packet);
if (status){
log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed with status %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", status, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), status);
break;
}
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED){
log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed - stream endpoint in wrong state %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", stream_endpoint->state, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE);
break;
}
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
stream_endpoint->connection = connection;
stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet);
stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet);
log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, address, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), 0);
return;
}
break;
case L2CAP_EVENT_CHANNEL_CLOSED:
local_cid = l2cap_event_channel_closed_get_local_cid(packet);
log_info("L2CAP_EVENT_CHANNEL_CLOSED stream endpoint sm: media cid 0x%02x, local cid 0x%02x\n", stream_endpoint->l2cap_media_cid , local_cid);
if (stream_endpoint->l2cap_media_cid == local_cid){
avdtp_streaming_emit_connection_released(context->avdtp_callback, connection->avdtp_cid, avdtp_local_seid(stream_endpoint));
stream_endpoint->l2cap_media_cid = 0;
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
stream_endpoint->remote_sep_index = 0;
break;
}
if (stream_endpoint->l2cap_recovery_cid == local_cid){
log_info(" -> L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid);
stream_endpoint->l2cap_recovery_cid = 0;
break;
}
if (stream_endpoint->l2cap_reporting_cid == local_cid){
log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid);
stream_endpoint->l2cap_reporting_cid = 0;
break;
}
break;
default:
break;
}
break;
default:
break;
}
}
static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
avdtp_connection_t * connection = avdtp_connection_for_avdtp_cid(sdp_query_context->avdtp_cid, sdp_query_context);
if (!connection) {
@ -555,7 +470,12 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
if (stream_endpoint->connection){
if (channel == stream_endpoint->connection->l2cap_signaling_cid){
stream_endpoint_state_machine(stream_endpoint->connection, stream_endpoint, L2CAP_DATA_PACKET, 0, packet, size, context);
int offset = avdtp_read_signaling_header(&stream_endpoint->connection->signaling_packet, packet, size);
if (stream_endpoint->connection->signaling_packet.message_type == AVDTP_CMD_MSG){
avdtp_acceptor_stream_config_subsm(stream_endpoint->connection, packet, size, offset, context);
} else {
avdtp_initiator_stream_config_subsm(stream_endpoint->connection, packet, size, offset, context);
}
break;
}
}
@ -652,19 +572,36 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found");
return;
}
stream_endpoint_state_machine(connection, stream_endpoint, HCI_EVENT_PACKET, L2CAP_EVENT_CHANNEL_OPENED, packet, size, context);
if (stream_endpoint->l2cap_media_cid == 0){
status = l2cap_event_channel_opened_get_status(packet);
if (status){
log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed with status %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", status, context->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
avdtp_streaming_emit_connection_established(context->avdtp_callback, context->avdtp_cid, event_addr, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), status);
break;
}
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED){
log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED failed - stream endpoint in wrong state %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", stream_endpoint->state, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
avdtp_streaming_emit_connection_established(context->avdtp_callback, context->avdtp_cid, event_addr, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE);
break;
}
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
stream_endpoint->connection = connection;
stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet);
stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet);
log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", context->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
avdtp_streaming_emit_connection_established(context->avdtp_callback, context->avdtp_cid, event_addr, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint), 0);
return;
}
break;
case L2CAP_EVENT_CHANNEL_CLOSED:
local_cid = l2cap_event_channel_closed_get_local_cid(packet);
connection = avdtp_connection_for_l2cap_signaling_cid(local_cid, context);
stream_endpoint = avdtp_stream_endpoint_for_l2cap_cid(local_cid, context);
log_info("received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, %p, %p\n", local_cid, connection, stream_endpoint);
if (stream_endpoint){
stream_endpoint_state_machine(stream_endpoint->connection, stream_endpoint, HCI_EVENT_PACKET, L2CAP_EVENT_CHANNEL_CLOSED, packet, size, context);
break;
}
log_info("received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint);
if (connection){
avdtp_signaling_emit_connection_released(context->avdtp_callback, connection->avdtp_cid);
@ -681,6 +618,33 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
btstack_memory_avdtp_connection_free(connection);
break;
}
if (stream_endpoint){
if (stream_endpoint->l2cap_media_cid == local_cid){
connection = stream_endpoint->connection;
avdtp_streaming_emit_connection_released(context->avdtp_callback, context->avdtp_cid, avdtp_local_seid(stream_endpoint));
stream_endpoint->l2cap_media_cid = 0;
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
stream_endpoint->remote_sep_index = 0;
if (connection && connection->disconnect){
avdtp_request_can_send_now_self(connection, connection->l2cap_signaling_cid);
}
break;
}
if (stream_endpoint->l2cap_recovery_cid == local_cid){
log_info(" -> L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid);
stream_endpoint->l2cap_recovery_cid = 0;
break;
}
if (stream_endpoint->l2cap_reporting_cid == local_cid){
log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid);
stream_endpoint->l2cap_reporting_cid = 0;
break;
}
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
@ -710,8 +674,11 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
uint8_t avdtp_disconnect(uint16_t avdtp_cid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_avdtp_cid(avdtp_cid, context);
if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED;
if (connection->state == AVDTP_SIGNALING_CONNECTION_IDLE) return AVDTP_CONNECTION_IN_WRONG_STATE;
if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return AVDTP_CONNECTION_IN_WRONG_STATE;
if (connection->state == AVDTP_SIGNALING_CONNECTION_IDLE){
avdtp_signaling_emit_connection_released(context->avdtp_callback, connection->avdtp_cid);
return ERROR_CODE_SUCCESS;
}
if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS;
connection->disconnect = 1;
avdtp_request_can_send_now_self(connection, connection->l2cap_signaling_cid);

View File

@ -880,7 +880,6 @@ uint8_t avdtp_remote_seid(avdtp_stream_endpoint_t * stream_endpoint){
void a2dp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t cid, bd_addr_t addr, uint8_t local_seid, uint8_t remote_seid, uint8_t status){
if (!callback) return;
printf("emit A2DP_SUBEVENT_STREAM_ESTABLISHED\n");
uint8_t event[14];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;