clean up open/close stream api

This commit is contained in:
Milanka Ringwald 2017-04-21 16:34:57 +02:00
parent 0bdb280dbe
commit 46e6b06306
13 changed files with 381 additions and 251 deletions

View File

@ -932,9 +932,10 @@ typedef uint8_t sm_key_t[16];
#define HCI_EVENT_HFP_META 0xE9
#define HCI_EVENT_ANCS_META 0xEA
#define HCI_EVENT_AVDTP_META 0xEB
#define HCI_EVENT_AVRCP_META 0xEC
#define HCI_EVENT_GOEP_META 0xED
#define HCI_EVENT_PBAP_META 0xEE
#define HCI_EVENT_A2DP_META 0xEC
#define HCI_EVENT_AVRCP_META 0xED
#define HCI_EVENT_GOEP_META 0xEE
#define HCI_EVENT_PBAP_META 0xEF
// Potential other meta groups
// #define HCI_EVENT_BNEP_META 0xxx
@ -1374,24 +1375,50 @@ typedef uint8_t sm_key_t[16];
*/
#define AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW 0x0D
/** A2DP Subevent */
/**
* @format 1H111
* @param subevent_code
* @param a2dp_cid
* @param local_seid
* @param remote_seid
* @param status
*/
#define A2DP_SUBEVENT_STREAM_ESTABLISHED 0x01
/**
* @format 1H1
* @param subevent_code
* @param avdtp_cid
* @param int_seid
* @param a2dp_cid
* @param local_seid
*/
#define AVDTP_SUBEVENT_START_STREAMING 0x0E
#define A2DP_SUBEVENT_STREAM_START_ACCEPTED 0x02
/**
* @format 1H1
* @param subevent_code
* @param a2dp_cid
* @param local_seid
*/
#define A2DP_SUBEVENT_STREAM_SUSPENDED 0x03
/**
* @format 1H1
* @param subevent_code
* @param avdtp_cid
* @param int_seid
* @param local_seid
*/
#define AVDTP_SUBEVENT_STOP_STREAMING 0x0F
#define A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW 0x04
/**
* @format 1H1
* @param subevent_code
* @param avdtp_cid
* @param local_seid
*/
#define A2DP_SUBEVENT_STREAM_RELEASED 0x05
/** AVRCP Subevent */

View File

@ -85,6 +85,14 @@ static inline uint8_t hci_event_ancs_meta_get_subevent_code(const uint8_t * even
static inline uint8_t hci_event_avdtp_meta_get_subevent_code(const uint8_t * event){
return event[2];
}
/***
* @brief Get subevent code for a2dp event
* @param event packet
* @return subevent_code
*/
static inline uint8_t hci_event_a2dp_meta_get_subevent_code(const uint8_t * event){
return event[2];
}
/***
* @brief Get subevent code for avrcp event
* @param event packet
@ -4479,40 +4487,115 @@ static inline uint16_t avdtp_subevent_streaming_can_send_media_packet_now_get_se
}
/**
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_START_STREAMING
* @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return avdtp_cid
* @return a2dp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_start_streaming_get_avdtp_cid(const uint8_t * event){
static inline hci_con_handle_t a2dp_subevent_stream_established_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_START_STREAMING
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return int_seid
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_start_streaming_get_int_seid(const uint8_t * event){
static inline uint8_t a2dp_subevent_stream_established_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field remote_seid from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return remote_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_established_get_remote_seid(const uint8_t * event){
return event[6];
}
/**
* @brief Get field status from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return status
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_established_get_status(const uint8_t * event){
return event[7];
}
/**
* @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_START_ACCEPTED
* @param event packet
* @return a2dp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t a2dp_subevent_stream_start_accepted_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_START_ACCEPTED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_start_accepted_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_STOP_STREAMING
* @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_SUSPENDED
* @param event packet
* @return a2dp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t a2dp_subevent_stream_suspended_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_SUSPENDED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_suspended_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field avdtp_cid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
* @param event packet
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_stop_streaming_get_avdtp_cid(const uint8_t * event){
static inline hci_con_handle_t a2dp_subevent_streaming_can_send_media_packet_now_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_STOP_STREAMING
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
* @param event packet
* @return int_seid
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_stop_streaming_get_int_seid(const uint8_t * event){
static inline uint8_t a2dp_subevent_streaming_can_send_media_packet_now_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field avdtp_cid from event A2DP_SUBEVENT_STREAM_RELEASED
* @param event packet
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t a2dp_subevent_stream_released_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_RELEASED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_released_get_local_seid(const uint8_t * event){
return event[5];
}

View File

@ -164,6 +164,34 @@ void a2dp_source_create_sdp_record(uint8_t * service, uint32_t service_record_ha
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
}
static void a2dp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t cid, uint8_t local_seid, uint8_t remote_seid, uint8_t status){
if (!callback) return;
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAM_ESTABLISHED;
little_endian_store_16(event, pos, cid);
pos += 2;
event[pos++] = local_seid;
event[pos++] = remote_seid;
event[pos++] = status;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void a2dp_streaming_emit_can_send_media_packet_now(btstack_packet_handler_t callback, uint16_t cid, uint8_t seid){
if (!callback) return;
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW;
little_endian_store_16(event, pos, cid);
pos += 2;
event[pos++] = seid;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
@ -188,6 +216,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
case HCI_EVENT_DISCONNECTION_COMPLETE:
// connection closed -> quit test app
printf("\n --- a2dp source --- HCI_EVENT_DISCONNECTION_COMPLETE ---\n");
break;
case HCI_EVENT_AVDTP_META:
switch (packet[2]){
@ -216,7 +245,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
break;
}
app_state = A2DP_STREAMING_OPENED;
avdtp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, avdtp_cid, int_seid, acp_seid, 0);
a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, avdtp_cid, int_seid, acp_seid, 0);
printf(" --- a2dp source --- AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED --- avdtp_cid 0x%02x, local seid %d, remote seid %d\n", avdtp_cid, int_seid, acp_seid);
break;
@ -275,7 +304,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
break;
}
case AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:
avdtp_streaming_emit_can_send_media_packet_now(a2dp_source_context.a2dp_callback, avdtp_cid, 0, 0);
a2dp_streaming_emit_can_send_media_packet_now(a2dp_source_context.a2dp_callback, avdtp_cid, 0);
break;
case AVDTP_SUBEVENT_SIGNALING_ACCEPT:
@ -326,23 +355,34 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
case AVDTP_SI_START:{
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_START_STREAMING;
event[pos++] = A2DP_SUBEVENT_STREAM_START_ACCEPTED;
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint);
(*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
case AVDTP_SI_CLOSE:
case AVDTP_SI_SUSPEND:
case AVDTP_SI_ABORT:{
case AVDTP_SI_CLOSE:{
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_STOP_STREAMING;
event[pos++] = A2DP_SUBEVENT_STREAM_RELEASED;
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint);
(*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
case AVDTP_SI_SUSPEND:{
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAM_SUSPENDED;
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint);
@ -411,7 +451,7 @@ uint8_t a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_
return local_stream_endpoint->sep.seid;
}
void a2dp_source_connect(bd_addr_t bd_addr, uint8_t local_seid){
void a2dp_source_establish_stream(bd_addr_t bd_addr, uint8_t local_seid){
sc.local_stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
if (!sc.local_stream_endpoint){
printf(" no local_stream_endpoint for seid %d\n", local_seid);
@ -424,11 +464,116 @@ void a2dp_source_disconnect(uint16_t con_handle){
avdtp_disconnect(con_handle, &a2dp_source_context);
}
void a2dp_source_start_stream(uint16_t cid, uint8_t int_seid, uint8_t acp_seid){
avdtp_start_stream(cid, int_seid, acp_seid, &a2dp_source_context);
void a2dp_source_start_stream(uint8_t int_seid){
avdtp_start_stream(int_seid, &a2dp_source_context);
}
void a2dp_source_stop_stream(uint16_t cid, uint8_t int_seid, uint8_t acp_seid){
avdtp_stop_stream(cid, int_seid, acp_seid, &a2dp_source_context);
void a2dp_source_release_stream(uint8_t int_seid){
avdtp_stop_stream(int_seid, &a2dp_source_context);
}
uint8_t a2dp_source_stream_endpoint_ready(uint8_t local_seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
if (!stream_endpoint) {
printf("no stream_endpoint");
return 0;
}
return (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING || stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND);
}
static void a2dp_source_setup_media_header(uint8_t * media_packet, int size, int *offset, uint8_t marker, uint16_t sequence_number){
if (size < 12){
printf("small outgoing buffer\n");
return;
}
uint8_t rtp_version = 2;
uint8_t padding = 0;
uint8_t extension = 0;
uint8_t csrc_count = 0;
uint8_t payload_type = 0x60;
// uint16_t sequence_number = stream_endpoint->sequence_number;
uint32_t timestamp = btstack_run_loop_get_time_ms();
uint32_t ssrc = 0x11223344;
// rtp header (min size 12B)
int pos = 0;
// int mtu = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
media_packet[pos++] = (rtp_version << 6) | (padding << 5) | (extension << 4) | csrc_count;
media_packet[pos++] = (marker << 1) | payload_type;
big_endian_store_16(media_packet, pos, sequence_number);
pos += 2;
big_endian_store_32(media_packet, pos, timestamp);
pos += 4;
big_endian_store_32(media_packet, pos, ssrc); // only used for multicast
pos += 4;
*offset = pos;
}
static void a2dp_source_copy_media_payload(uint8_t * media_packet, int size, int * offset, btstack_ring_buffer_t * sbc_ring_buffer){
if (size < 18){
printf("small outgoing buffer\n");
return;
}
int pos = *offset;
// media payload
// sbc_header (size 1B)
uint8_t sbc_header_index = pos;
pos++;
uint8_t fragmentation = 0;
uint8_t starting_packet = 0; // set to 1 for the first packet of a fragmented SBC frame
uint8_t last_packet = 0; // set to 1 for the last packet of a fragmented SBC frame
uint8_t num_frames = 0;
uint32_t total_sbc_bytes_read = 0;
uint8_t sbc_frame_size = 0;
// payload
uint16_t sbc_frame_bytes = btstack_sbc_encoder_sbc_buffer_length();
while (size - 13 - total_sbc_bytes_read >= sbc_frame_bytes && btstack_ring_buffer_bytes_available(sbc_ring_buffer)){
uint32_t number_of_bytes_read = 0;
btstack_ring_buffer_read(sbc_ring_buffer, &sbc_frame_size, 1, &number_of_bytes_read);
btstack_ring_buffer_read(sbc_ring_buffer, media_packet + pos, sbc_frame_size, &number_of_bytes_read);
pos += sbc_frame_size;
total_sbc_bytes_read += sbc_frame_size;
num_frames++;
// printf("send sbc frame: timestamp %d, seq. nr %d\n", timestamp, stream_endpoint->sequence_number);
}
media_packet[sbc_header_index] = (fragmentation << 7) | (starting_packet << 6) | (last_packet << 5) | num_frames;
*offset = pos;
}
void a2dp_source_stream_endpoint_request_can_send_now(uint8_t local_seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
if (!stream_endpoint) {
printf("no stream_endpoint");
return;
}
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND;
avdtp_request_can_send_now_self(stream_endpoint->connection, stream_endpoint->l2cap_media_cid);
}
void a2dp_source_stream_send_media_payload(uint8_t int_seid, btstack_ring_buffer_t * sbc_ring_buffer, uint8_t marker){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(int_seid, &a2dp_source_context);
if (!stream_endpoint) {
printf("no stream_endpoint found for seid %d", int_seid);
return;
}
if (stream_endpoint->l2cap_media_cid == 0){
printf("no media cid found for seid %d", int_seid);
return;
}
int size = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
int offset = 0;
l2cap_reserve_packet_buffer();
uint8_t * media_packet = l2cap_get_outgoing_buffer();
//int size = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
a2dp_source_setup_media_header(media_packet, size, &offset, marker, stream_endpoint->sequence_number);
a2dp_source_copy_media_payload(media_packet, size, &offset, sbc_ring_buffer);
stream_endpoint->sequence_number++;
l2cap_send_prepared(stream_endpoint->l2cap_media_cid, offset);
}

View File

@ -72,21 +72,26 @@ uint8_t a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_
uint8_t * codec_capabilities, uint16_t codec_capabilities_len,
uint8_t * codec_configuration, uint16_t codec_configuration_len);
void a2dp_source_connect(bd_addr_t bd_addr, uint8_t local_seid);
/**
* @brief Start stream
* @param avdtp_cid
* @param seid
*/
void a2dp_source_establish_stream(bd_addr_t bd_addr, uint8_t local_seid);
/**
* @brief Start stream
* @param avdtp_cid
* @param seid
*/
void a2dp_source_start_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
void a2dp_source_start_stream(uint8_t int_seid);
/**
* @brief Start stream
* @param avdtp_cid
* @param seid
*/
void a2dp_source_stop_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
void a2dp_source_release_stream(uint8_t int_seid);
/**
* @brief Disconnect from device with connection handle.
@ -94,6 +99,10 @@ void a2dp_source_stop_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_s
*/
void a2dp_source_disconnect(uint16_t avdtp_cid);
uint8_t a2dp_source_stream_endpoint_ready(uint8_t local_seid);
void a2dp_source_stream_endpoint_request_can_send_now(uint8_t local_seid);
void a2dp_source_stream_send_media_payload(uint8_t int_seid, btstack_ring_buffer_t * sbc_ring_buffer, uint8_t marker);
/* API_END */
#if defined __cplusplus

View File

@ -485,67 +485,52 @@ void avdtp_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, a
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_start_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_start_stream: no connection for signaling cid 0x%02x found\n", avdtp_cid);
return;
}
if (avdtp_find_remote_sep(connection, acp_seid) == 0xFF){
printf("avdtp_start_stream: no remote sep for seid %d found\n", acp_seid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
printf("avdtp_start_stream: wrong connection state %d\n", connection->state);
return;
}
void avdtp_start_stream(uint8_t int_seid, avdtp_context_t * context){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(int_seid, context);
if (!stream_endpoint) {
printf("avdtp_start_stream: no stream_endpoint with seid %d found\n", int_seid);
return;
}
avdtp_connection_t * connection = stream_endpoint->connection;
if (!connection){
printf("avdtp_start_stream: no connection for seid %d found\n", int_seid);
return;
}
if (stream_endpoint->remote_sep_index == 0xFF) return;
if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_OPENED) return;
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->acp_seid = stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid;
connection->int_seid = stream_endpoint->sep.seid;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_STREAMING_START;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_stop_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_stop_stream: no connection for signaling cid 0x%02x found\n", avdtp_cid);
return;
}
if (avdtp_find_remote_sep(connection, acp_seid) == 0xFF){
printf("avdtp_stop_stream: no remote sep for seid %d found\n", acp_seid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
printf("avdtp_stop_stream: wrong connection state %d\n", connection->state);
return;
}
void avdtp_stop_stream(uint8_t int_seid, avdtp_context_t * context){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(int_seid, context);
if (!stream_endpoint) {
printf("avdtp_stop_stream: no stream_endpoint with seid %d found\n", int_seid);
return;
}
if (stream_endpoint->remote_sep_index == 0xFF) return;
switch (stream_endpoint->state){
case AVDTP_STREAM_ENDPOINT_OPENED:
case AVDTP_STREAM_ENDPOINT_STREAMING:
if (!stream_endpoint->connection){
printf("avdtp_stop_stream: no connection for seid %d found\n",stream_endpoint->sep.seid);
return;
}
printf(" AVDTP_INITIATOR_W2_STREAMING_STOP \n");
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->int_seid = stream_endpoint->sep.seid;
stream_endpoint->connection->initiator_transaction_label++;
stream_endpoint->connection->acp_seid = stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid;
stream_endpoint->connection->int_seid = stream_endpoint->sep.seid;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_STREAMING_STOP;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
avdtp_request_can_send_now_initiator(stream_endpoint->connection, stream_endpoint->connection->l2cap_signaling_cid);
break;
default:
break;

View File

@ -491,8 +491,8 @@ avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type
void avdtp_disconnect(uint16_t avdtp_cid, avdtp_context_t * context);
void avdtp_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_start_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_stop_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_start_stream(uint8_t int_seid, avdtp_context_t * context);
void avdtp_stop_stream (uint8_t int_seid, avdtp_context_t * context);
void avdtp_abort_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_discover_stream_endpoints(uint16_t avdtp_cid, avdtp_context_t * context);

View File

@ -155,12 +155,12 @@ void avdtp_sink_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_se
avdtp_open_stream(avdtp_cid, int_seid, acp_seid, &avdtp_sink_context);
}
void avdtp_sink_start_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid){
avdtp_start_stream(avdtp_cid, int_seid, acp_seid, &avdtp_sink_context);
void avdtp_sink_start_stream(uint8_t int_seid){
avdtp_start_stream(int_seid, &avdtp_sink_context);
}
void avdtp_sink_stop_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid){
avdtp_stop_stream(avdtp_cid, int_seid, acp_seid, &avdtp_sink_context);
void avdtp_sink_stop_stream(uint8_t int_seid){
avdtp_stop_stream(int_seid, &avdtp_sink_context);
}
void avdtp_sink_abort_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid){

View File

@ -150,7 +150,7 @@ void avdtp_sink_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_se
* @param avdtp_cid
* @param seid
*/
void avdtp_sink_start_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
void avdtp_sink_start_stream(uint8_t int_seid);
/**
* @brief Start stream
@ -164,7 +164,7 @@ void avdtp_sink_abort_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_s
* @param avdtp_cid
* @param seid
*/
void avdtp_sink_stop_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
void avdtp_sink_stop_stream(uint8_t int_seid);
/* API_END */

View File

@ -125,12 +125,12 @@ void avdtp_source_open_stream(uint16_t con_handle, uint8_t int_seid, uint8_t acp
avdtp_open_stream(con_handle, int_seid, acp_seid, avdtp_source_context);
}
void avdtp_source_start_stream(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid){
avdtp_start_stream(con_handle, int_seid, acp_seid, avdtp_source_context);
void avdtp_source_start_stream(uint8_t int_seid){
avdtp_start_stream(int_seid, avdtp_source_context);
}
void avdtp_source_stop_stream(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid){
avdtp_stop_stream(con_handle, int_seid, acp_seid, avdtp_source_context);
void avdtp_source_stop_stream(uint8_t int_seid){
avdtp_stop_stream(int_seid, avdtp_source_context);
}
void avdtp_source_abort_stream(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid){
@ -183,113 +183,6 @@ void avdtp_source_init(avdtp_context_t * avdtp_context){
l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0);
}
int avdtp_source_stream_endpoint_ready(uint8_t local_seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, avdtp_source_context);
if (!stream_endpoint) {
printf("no stream_endpoint");
return 0;
}
return (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING || stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND);
}
void avdtp_source_stream_endpoint_request_can_send_now(uint8_t local_seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, avdtp_source_context);
if (!stream_endpoint) {
printf("no stream_endpoint");
return;
}
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND;
avdtp_request_can_send_now_self(stream_endpoint->connection, stream_endpoint->l2cap_media_cid);
}
static void avdtp_source_setup_media_header(uint8_t * media_packet, int size, int *offset, uint8_t marker, uint16_t sequence_number){
if (size < 12){
printf("small outgoing buffer\n");
return;
}
uint8_t rtp_version = 2;
uint8_t padding = 0;
uint8_t extension = 0;
uint8_t csrc_count = 0;
uint8_t payload_type = 0x60;
// uint16_t sequence_number = stream_endpoint->sequence_number;
uint32_t timestamp = btstack_run_loop_get_time_ms();
uint32_t ssrc = 0x11223344;
// rtp header (min size 12B)
int pos = 0;
// int mtu = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
media_packet[pos++] = (rtp_version << 6) | (padding << 5) | (extension << 4) | csrc_count;
media_packet[pos++] = (marker << 1) | payload_type;
big_endian_store_16(media_packet, pos, sequence_number);
pos += 2;
big_endian_store_32(media_packet, pos, timestamp);
pos += 4;
big_endian_store_32(media_packet, pos, ssrc); // only used for multicast
pos += 4;
*offset = pos;
}
static void avdtp_source_copy_media_payload(uint8_t * media_packet, int size, int * offset, btstack_ring_buffer_t * sbc_ring_buffer){
if (size < 18){
printf("small outgoing buffer\n");
return;
}
int pos = *offset;
// media payload
// sbc_header (size 1B)
uint8_t sbc_header_index = pos;
pos++;
uint8_t fragmentation = 0;
uint8_t starting_packet = 0; // set to 1 for the first packet of a fragmented SBC frame
uint8_t last_packet = 0; // set to 1 for the last packet of a fragmented SBC frame
uint8_t num_frames = 0;
uint32_t total_sbc_bytes_read = 0;
uint8_t sbc_frame_size = 0;
// payload
uint16_t sbc_frame_bytes = btstack_sbc_encoder_sbc_buffer_length();
while (size - 13 - total_sbc_bytes_read >= sbc_frame_bytes && btstack_ring_buffer_bytes_available(sbc_ring_buffer)){
uint32_t number_of_bytes_read = 0;
btstack_ring_buffer_read(sbc_ring_buffer, &sbc_frame_size, 1, &number_of_bytes_read);
btstack_ring_buffer_read(sbc_ring_buffer, media_packet + pos, sbc_frame_size, &number_of_bytes_read);
pos += sbc_frame_size;
total_sbc_bytes_read += sbc_frame_size;
num_frames++;
// printf("send sbc frame: timestamp %d, seq. nr %d\n", timestamp, stream_endpoint->sequence_number);
}
media_packet[sbc_header_index] = (fragmentation << 7) | (starting_packet << 6) | (last_packet << 5) | num_frames;
*offset = pos;
}
void avdtp_source_stream_send_media_payload(uint8_t int_seid, btstack_ring_buffer_t * sbc_ring_buffer, uint8_t marker){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(int_seid, avdtp_source_context);
if (!stream_endpoint) {
printf("no stream_endpoint found for seid %d", int_seid);
return;
}
if (stream_endpoint->l2cap_media_cid == 0){
printf("no media cid found for seid %d", int_seid);
return;
}
int size = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
int offset = 0;
l2cap_reserve_packet_buffer();
uint8_t * media_packet = l2cap_get_outgoing_buffer();
//int size = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
avdtp_source_setup_media_header(media_packet, size, &offset, marker, stream_endpoint->sequence_number);
avdtp_source_copy_media_payload(media_packet, size, &offset, sbc_ring_buffer);
stream_endpoint->sequence_number++;
l2cap_send_prepared(stream_endpoint->l2cap_media_cid, offset);
}
uint8_t avdtp_source_remote_seps_num(uint16_t avdtp_cid){
return avdtp_remote_seps_num(avdtp_cid, avdtp_source_context);
}

View File

@ -129,14 +129,14 @@ void avdtp_source_suspend(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid
* @param avdtp_cid
* @param seid
*/
void avdtp_source_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
void avdtp_source_open_stream(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid);
/**
* @brief Start stream
* @param avdtp_cid
* @param seid
*/
void avdtp_source_start_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
void avdtp_source_start_stream(uint8_t int_seid);
/**
* @brief Start stream
@ -150,14 +150,10 @@ void avdtp_source_abort_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp
* @param avdtp_cid
* @param seid
*/
void avdtp_source_stop_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
void avdtp_source_stop_stream(uint8_t int_seid);
avdtp_stream_endpoint_t * avdtp_source_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type);
void avdtp_source_stream_endpoint_request_can_send_now(uint8_t local_seid);
int avdtp_source_stream_endpoint_ready(uint8_t local_seid);
void avdtp_source_stream_send_media_payload(uint8_t local_seid, btstack_ring_buffer_t * sbc_ring_buffer, uint8_t marker);
uint8_t avdtp_source_remote_seps_num(uint16_t avdtp_cid);
avdtp_sep_t * avdtp_source_remote_sep(uint16_t avdtp_cid, uint8_t index);
/* API_END */

View File

@ -605,7 +605,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
break;
case 'm':
app_state = AVDTP_APPLICATION_W2_START_STREAM_WITH_SEID;
avdtp_sink_start_stream(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid);
avdtp_sink_start_stream(local_stream_endpoint->sep.seid);
break;
case 'A':
app_state = AVDTP_APPLICATION_W2_ABORT_STREAM_WITH_SEID;
@ -613,7 +613,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
break;
case 'S':
app_state = AVDTP_APPLICATION_W2_STOP_STREAM_WITH_SEID;
avdtp_sink_stop_stream(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid);
avdtp_sink_stop_stream(local_stream_endpoint->sep.seid);
break;
case 'P':
app_state = AVDTP_APPLICATION_W2_SUSPEND_STREAM_WITH_SEID;

View File

@ -109,8 +109,8 @@ static uint8_t sbc_storage[44100*4];
typedef struct {
uint16_t a2dp_cid;
uint8_t int_seid;
uint8_t acp_seid;
uint8_t local_seid;
uint8_t remote_seid;
uint32_t fill_audio_ring_buffer_timeout_ms;
uint32_t time_audio_data_sent; // ms
@ -130,65 +130,56 @@ static modcontext mod_context;
static tracker_buffer_state trkbuf;
static uint8_t local_seid = 0;
a2dp_state_t app_state = A2DP_IDLE;
stream_data_source_t data_source = STREAM_SINE;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static void avdtp_fill_audio_ring_buffer_timer_start(a2dp_media_sending_context_t * context);
static void avdtp_fill_audio_ring_buffer_timer_stop(a2dp_media_sending_context_t * context);
static void a2dp_fill_audio_ring_buffer_timer_start(a2dp_media_sending_context_t * context);
static void a2dp_fill_audio_ring_buffer_timer_stop(a2dp_media_sending_context_t * context);
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
bd_addr_t event_addr;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
case HCI_EVENT_PIN_CODE_REQUEST:
// inform about pin code request
printf("Pin code request - using '0000'\n");
hci_event_pin_code_request_get_bd_addr(packet, event_addr);
hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
// connection closed -> quit test app
printf("\n --- application --- HCI_EVENT_DISCONNECTION_COMPLETE ---\n");
break;
case HCI_EVENT_AVDTP_META:
case HCI_EVENT_A2DP_META:
switch (packet[2]){
case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED:
media_tracker.int_seid = avdtp_subevent_streaming_connection_established_get_int_seid(packet);
media_tracker.acp_seid = avdtp_subevent_streaming_connection_established_get_acp_seid(packet);
media_tracker.a2dp_cid = avdtp_subevent_streaming_connection_established_get_avdtp_cid(packet);
printf(" --- application --- AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED --- a2dp_cid 0x%02x, local seid %d, remote seid %d\n",
media_tracker.a2dp_cid, media_tracker.int_seid, media_tracker.acp_seid);
case A2DP_SUBEVENT_STREAM_ESTABLISHED:
media_tracker.local_seid = a2dp_subevent_stream_established_get_local_seid(packet);
media_tracker.remote_seid = a2dp_subevent_stream_established_get_remote_seid(packet);
media_tracker.a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
printf(" --- application --- A2DP_SUBEVENT_STREAM_ESTABLISHED, a2dp_cid 0x%02x, local seid %d, remote seid %d\n",
media_tracker.a2dp_cid, media_tracker.local_seid, media_tracker.remote_seid);
break;
case AVDTP_SUBEVENT_START_STREAMING:
if (local_seid != media_tracker.int_seid) break;
if (!avdtp_source_stream_endpoint_ready(media_tracker.int_seid)) break;
printf(" --- application --- start streaming : int seid %d\n", media_tracker.int_seid);
avdtp_fill_audio_ring_buffer_timer_start(&media_tracker);
case A2DP_SUBEVENT_STREAM_START_ACCEPTED:
if (local_seid != media_tracker.local_seid) break;
if (!a2dp_source_stream_endpoint_ready(media_tracker.local_seid)) break;
printf(" --- application --- A2DP_SUBEVENT_STREAM_START_ACCEPTED, local seid %d\n", media_tracker.local_seid);
a2dp_fill_audio_ring_buffer_timer_start(&media_tracker);
break;
case AVDTP_SUBEVENT_STOP_STREAMING:
if (local_seid != media_tracker.int_seid) break;
avdtp_fill_audio_ring_buffer_timer_stop(&media_tracker);
break;
case AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:
if (local_seid != media_tracker.int_seid) break;
avdtp_source_stream_send_media_payload(media_tracker.int_seid, &media_tracker.sbc_ring_buffer, 0);
case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:
if (local_seid != media_tracker.local_seid) break;
a2dp_source_stream_send_media_payload(media_tracker.local_seid, &media_tracker.sbc_ring_buffer, 0);
if (btstack_ring_buffer_bytes_available(&media_tracker.sbc_ring_buffer)){
avdtp_source_stream_endpoint_request_can_send_now(media_tracker.int_seid);
a2dp_source_stream_endpoint_request_can_send_now(media_tracker.local_seid);
}
break;
case A2DP_SUBEVENT_STREAM_SUSPENDED:
if (local_seid != media_tracker.local_seid) break;
printf(" --- application --- A2DP_SUBEVENT_STREAM_SUSPENDED, local seid %d\n", media_tracker.local_seid);
a2dp_fill_audio_ring_buffer_timer_stop(&media_tracker);
break;
case A2DP_SUBEVENT_STREAM_RELEASED:
printf(" --- application --- A2DP_SUBEVENT_STREAM_RELEASED, local seid %d\n", media_tracker.local_seid);
break;
default:
app_state = A2DP_IDLE;
printf(" --- application --- not implemented\n");
break;
}
@ -306,11 +297,11 @@ static void avdtp_fill_audio_ring_buffer_timeout_handler(btstack_timer_source_t
int total_num_bytes_read = fill_sbc_ring_buffer(context);
// schedule sending
if (total_num_bytes_read != 0){
avdtp_source_stream_endpoint_request_can_send_now(context->int_seid);
a2dp_source_stream_endpoint_request_can_send_now(context->local_seid);
}
}
static void avdtp_fill_audio_ring_buffer_timer_start(a2dp_media_sending_context_t * context){
static void a2dp_fill_audio_ring_buffer_timer_start(a2dp_media_sending_context_t * context){
btstack_run_loop_remove_timer(&context->fill_audio_ring_buffer_timer);
btstack_run_loop_set_timer_handler(&context->fill_audio_ring_buffer_timer, avdtp_fill_audio_ring_buffer_timeout_handler);
btstack_run_loop_set_timer_context(&context->fill_audio_ring_buffer_timer, context);
@ -318,7 +309,7 @@ static void avdtp_fill_audio_ring_buffer_timer_start(a2dp_media_sending_context_
btstack_run_loop_add_timer(&context->fill_audio_ring_buffer_timer);
}
static void avdtp_fill_audio_ring_buffer_timer_stop(a2dp_media_sending_context_t * context){
static void a2dp_fill_audio_ring_buffer_timer_stop(a2dp_media_sending_context_t * context){
btstack_run_loop_remove_timer(&context->fill_audio_ring_buffer_timer);
}
@ -338,18 +329,18 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
switch (cmd){
case 'c':
printf("Creating L2CAP Connection to %s, PSM_AVDTP\n", bd_addr_to_str(remote));
a2dp_source_connect(remote, local_seid);
a2dp_source_establish_stream(remote, local_seid);
break;
case 'C':
printf("Disconnect not implemented\n");
a2dp_source_disconnect(media_tracker.a2dp_cid);
break;
case 'x':
printf(" --- application --- a2dp_source_stream_data_start --- local seid %d, remote seid %d\n", media_tracker.int_seid, media_tracker.acp_seid);
a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.int_seid, media_tracker.acp_seid);
printf(" --- application --- a2dp_source_stream_data_start --- local seid %d, remote seid %d\n", media_tracker.local_seid, media_tracker.remote_seid);
a2dp_source_start_stream(media_tracker.local_seid);
break;
case 'X':
a2dp_source_stop_stream(media_tracker.a2dp_cid, media_tracker.int_seid, media_tracker.acp_seid);
case 'X':
a2dp_source_release_stream(media_tracker.local_seid);
break;
default:
show_usage();

View File

@ -11,6 +11,7 @@ import btstack_parser as parser
meta_events = [
'ANCS',
'AVDTP',
'A2DP',
'AVRCP',
'GOEP',
'HFP',