avdtp: extend streaming end point with capabilities

This commit is contained in:
Milanka Ringwald 2016-09-28 12:07:40 +02:00
parent 3027d94f59
commit 328c17f5c5
4 changed files with 152 additions and 33 deletions

View File

@ -145,13 +145,6 @@ typedef enum{
AVDTP_SINK
} avdtp_sep_type_t;
typedef struct {
uint8_t seid; // 0x01 0x3E, 6bit
uint8_t in_use; // 1 bit, 0 - not in use, 1 - in use
avdtp_media_type_t media_type; // 4 bit
avdtp_sep_type_t type; // 1 bit, 0 - SRC, 1 - SNK
} avdtp_sep_t;
typedef enum {
AVDTP_MEDIA_TRANSPORT = 0X01,
AVDTP_REPORTING,
@ -197,15 +190,6 @@ typedef struct{
} avdtp_multiplexing_mode_capabilities_t;
typedef struct{
uint8_t media_transport_catagory;
uint8_t reporting_catagory;
uint8_t recovery_catagory;
uint8_t content_protection_catagory;
uint8_t header_compression_catagory;
uint8_t multiplexing_catagory;
uint8_t media_codec_catagory;
uint8_t delay_reportin_catagory;
avdtp_recovery_capabilities_t recovery_caps;
adtvp_media_codec_capabilities_t media_codec_caps;
adtvp_content_protection_t content_protection_caps;
@ -213,6 +197,17 @@ typedef struct{
avdtp_multiplexing_mode_capabilities_t multiplexing_mode_caps;
} avdtp_capabilities_t;
typedef struct {
uint8_t seid; // 0x01 0x3E, 6bit
uint8_t in_use; // 1 bit, 0 - not in use, 1 - in use
avdtp_media_type_t media_type; // 4 bit
avdtp_sep_type_t type; // 1 bit, 0 - SRC, 1 - SNK
uint16_t registered_service_categories;
avdtp_capabilities_t capabilities;
} avdtp_sep_t;
#if defined __cplusplus
}
#endif

View File

@ -52,7 +52,7 @@ static const char * default_avdtp_sink_service_provider_name = "BTstack AVDTP Si
static btstack_linked_list_t avdtp_sink_connections = NULL;
static avdtp_sep_t local_seps[MAX_NUM_SEPS];
static int local_seps_num = 0;
static uint8_t local_seps_num = 0;
static btstack_packet_handler_t avdtp_sink_callback;
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
@ -137,13 +137,14 @@ void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_han
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
}
void avdtp_sink_register_sep(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){
uint8_t avdtp_sink_register_stream_end_point(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){
if (local_seps_num >= MAX_NUM_SEPS){
log_error("avdtp_sink_register_sep: excedeed max sep number %d", MAX_NUM_SEPS);
return;
return 255;
}
uint8_t seid = local_seps_num;
avdtp_sep_t entry = {
local_seps_num,
seid,
0,
media_type,
sep_type
@ -151,6 +152,84 @@ void avdtp_sink_register_sep(avdtp_sep_type_t sep_type, avdtp_media_type_t media
local_seps[local_seps_num] = entry;
local_seps_num++;
return seid;
}
static int get_bit16(uint16_t bitmap, int position){
return (bitmap >> position) & 1;
}
static uint8_t store_bit16(uint16_t bitmap, int position, uint8_t value){
if (value){
bitmap |= 1 << position;
} else {
bitmap &= ~ (1 << position);
}
return bitmap;
}
void avdtp_sink_register_media_transport_category(uint8_t seid){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1);
}
void avdtp_sink_register_reporting_category(uint8_t seid){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_REPORTING, 1);
}
void avdtp_sink_register_delay_reporting_category(uint8_t seid){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_DELAY_REPORTING, 1);
}
void avdtp_sink_register_recovery_category(uint8_t seid, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_RECOVERY, 1);
}
void avdtp_sink_register_content_protection_category(uint8_t seid, uint8_t cp_type_lsb, uint8_t cp_type_msb){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_CONTENT_PROTECTION, 1);
}
void avdtp_sink_register_header_compression_category(uint8_t seid, uint8_t back_ch, uint8_t media, uint8_t recovery){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_HEADER_COMPRESSION, 1);
}
void avdtp_sink_register_media_codec_category(uint8_t seid, uint8_t media_type, uint8_t media_codec_type){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_MEDIA_CODEC, 1);
}
void avdtp_sink_register_multiplexing_category(uint8_t seid, uint8_t fragmentation, uint8_t transport_identifiers_num, uint8_t * transport_session_identifiers, uint8_t * transport_c_identifiers){
if (seid >= local_seps_num){
log_error("invalid stream end point identifier");
return;
}
store_bit16(local_seps[seid].registered_service_categories, AVDTP_MULTIPLEXING, 1);
}
static void audio_sink_generate_next_transaction_label(avdtp_sink_connection_t * connection){
@ -200,14 +279,14 @@ static inline uint8_t avdtp_header(uint8_t tr_label, avdtp_packet_type_t packet_
return (tr_label<<4) | ((uint8_t)packet_type<<2) | (uint8_t)msg_type;
}
static int avdtp_sink_send_discover_cmd(uint16_t cid, uint8_t transaction_label){
static int avdtp_sink_send_signaling_cmd(uint16_t cid, avdtp_signal_identifier_t identifier, uint8_t transaction_label){
uint8_t command[2];
command[0] = avdtp_header(transaction_label, AVDTP_SINGLE_PACKET, AVDTP_CMD_MSG);
command[1] = (uint8_t)AVDTP_DISCOVER;
command[1] = (uint8_t)identifier;
return l2cap_send(cid, command, sizeof(command));
}
static int avdtp_sink_send_seps_cmd(uint16_t cid, uint8_t transaction_label, avdtp_sep_t * seps, int seps_num){
static int avdtp_sink_send_seps_response(uint16_t cid, uint8_t transaction_label, avdtp_sep_t * seps, int seps_num){
uint8_t command[2+2*MAX_NUM_SEPS];
int pos = 0;
command[pos++] = avdtp_header(transaction_label, AVDTP_SINGLE_PACKET, AVDTP_RESPONSE_ACCEPT_MSG);
@ -220,12 +299,45 @@ static int avdtp_sink_send_seps_cmd(uint16_t cid, uint8_t transaction_label, avd
return l2cap_send(cid, command, pos);
}
static int avdtp_sink_send_capabilities_cmd(uint16_t cid, uint8_t transaction_label, avdtp_capabilities_t capabilities){
static int avdtp_sink_send_get_capabilities_cmd(uint16_t cid, uint8_t sep_id){
return 0;
}
static int avdtp_sink_send_get_capabilities_cmd(uint16_t cid, uint8_t sep_id){
return 0;
static int avdtp_pack_service_category(uint8_t * buffer, int size, avdtp_sep_t sep, avdtp_service_category_t category){
int pos = 0;
switch(category){
case AVDTP_MEDIA_TRANSPORT:
break;
case AVDTP_REPORTING:
break;
case AVDTP_RECOVERY:
break;
case AVDTP_CONTENT_PROTECTION:
break;
case AVDTP_HEADER_COMPRESSION:
break;
case AVDTP_MULTIPLEXING:
break;
case AVDTP_MEDIA_CODEC:
break;
case AVDTP_DELAY_REPORTING:
break;
}
return pos;
}
static int avdtp_sink_send_capabilities_response(uint16_t cid, uint8_t transaction_label, avdtp_sep_t sep){
uint8_t command[2+2*MAX_NUM_SEPS];
int pos = 0;
command[pos++] = avdtp_header(transaction_label, AVDTP_SINGLE_PACKET, AVDTP_RESPONSE_ACCEPT_MSG);
command[pos++] = (uint8_t)AVDTP_GET_CAPABILITIES;
int i = 0;
for (i = 1; i < 9; i++){
if (get_bit16(sep.registered_service_categories, i)){
pos += avdtp_pack_service_category(command+pos, sizeof(command)-pos, sep, (avdtp_service_category_t)i);
}
}
return l2cap_send(cid, command, pos);
}
static void handle_l2cap_data_packet(avdtp_sink_connection_t * connection, uint8_t *packet, uint16_t size){
@ -253,7 +365,9 @@ static void handle_l2cap_data_packet(avdtp_sink_connection_t * connection, uint8
l2cap_request_can_send_now_event(connection->l2cap_cid);
break;
case AVDTP_GET_CAPABILITIES:
sep.seid = packet[2] >> 2;
connection->remote_transaction_label = tr_label;
connection->requested_local_seid = sep.seid;
connection->remote_state = AVDTP_SINK_W2_GET_CAPABILITIES;
l2cap_request_can_send_now_event(connection->l2cap_cid);
break;
@ -432,11 +546,11 @@ static void avdtp_sink_run_for_connection(avdtp_sink_connection_t *connection){
switch (connection->remote_state){
case AVDTP_SINK_W2_DISCOVER_SEPS:
connection->local_state = AVDTP_SINK_W4_SEPS_DISCOVERED;
avdtp_sink_send_seps_cmd(connection->l2cap_cid, connection->remote_transaction_label, local_seps, local_seps_num);
avdtp_sink_send_seps_response(connection->l2cap_cid, connection->remote_transaction_label, local_seps, local_seps_num);
return;
case AVDTP_SINK_W2_GET_CAPABILITIES:
connection->local_state = AVDTP_SINK_W4_CAPABILITIES;
avdtp_sink_send_capabilities_cmd(connection->l2cap_cid, connection->remote_transaction_label, connection->local_capabilities);
avdtp_sink_send_capabilities_response(connection->l2cap_cid, connection->remote_transaction_label, local_seps[connection->requested_local_seid]);
break;
default:
break;
@ -445,7 +559,7 @@ static void avdtp_sink_run_for_connection(avdtp_sink_connection_t *connection){
switch (connection->local_state){
case AVDTP_SINK_W2_DISCOVER_SEPS:
connection->local_state = AVDTP_SINK_W4_SEPS_DISCOVERED;
avdtp_sink_send_discover_cmd(connection->l2cap_cid, connection->local_transaction_label);
avdtp_sink_send_signaling_cmd(connection->l2cap_cid, AVDTP_DISCOVER, connection->local_transaction_label);
return;
case AVDTP_SINK_W2_GET_CAPABILITIES:
connection->local_state = AVDTP_SINK_W4_CAPABILITIES;

View File

@ -91,8 +91,8 @@ typedef struct avdtp_sink_connection {
uint8_t release_l2cap_connection;
avdtp_capabilities_t local_capabilities;
avdtp_capabilities_t remote_capabilities;
uint8_t requested_local_seid;
} avdtp_sink_connection_t;
@ -113,7 +113,17 @@ void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_han
*/
void avdtp_sink_init(void);
void avdtp_sink_register_sep(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type);
// returns sep_id
uint8_t avdtp_sink_register_stream_end_point(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type);
void avdtp_sink_register_media_transport_category(uint8_t seid);
void avdtp_sink_register_reporting_category(uint8_t seid);
void avdtp_sink_register_delay_reporting_category(uint8_t seid);
void avdtp_sink_register_recovery_category(uint8_t seid, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets);
void avdtp_sink_register_content_protection_category(uint8_t seid, uint8_t cp_type_lsb, uint8_t cp_type_msb);
void avdtp_sink_register_header_compression_category(uint8_t seid, uint8_t back_ch, uint8_t media, uint8_t recovery);
void avdtp_sink_register_media_codec_category(uint8_t seid, uint8_t media_type, uint8_t media_codec_type);
void avdtp_sink_register_multiplexing_category(uint8_t seid, uint8_t fragmentation, uint8_t transport_identifiers_num, uint8_t * transport_session_identifiers, uint8_t * transport_c_identifiers);
/**
* @brief Register callback for the AVDTP Sink client.

View File

@ -147,8 +147,8 @@ int btstack_main(int argc, const char * argv[]){
// Initialize AVDTP Sink
avdtp_sink_init();
avdtp_sink_register_packet_handler(&packet_handler);
avdtp_sink_register_sep(AVDTP_SINK, AVDTP_AUDIO);
avdtp_sink_register_stream_end_point(AVDTP_SINK, AVDTP_AUDIO);
// Initialize SDP
sdp_init();
memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer));