avdtp: get all capabilities, acceptor role

This commit is contained in:
Milanka Ringwald 2016-11-10 12:33:34 +01:00
parent 960a7f70ae
commit ec2c446c4d
6 changed files with 109 additions and 27 deletions

View File

@ -111,14 +111,14 @@ typedef enum {
AVDTP_SI_GET_CAPABILITIES,
AVDTP_SI_SET_CONFIGURATION,
AVDTP_SI_GET_CONFIGURATION,
AVDTP_SI_RECONFIGURE,
AVDTP_SI_RECONFIGURE, //5
AVDTP_SI_OPEN,
AVDTP_SI_START,
AVDTP_SI_CLOSE,
AVDTP_SI_SUSPEND,
AVDTP_SI_ABORT,
AVDTP_SI_ABORT, //10
AVDTP_SI_SECURITY_CONTROL,
AVDTP_SI_GET_ALL_CAPABILITIES,
AVDTP_SI_GET_ALL_CAPABILITIES, //12
AVDTP_SI_DELAYREPORT
} avdtp_signal_identifier_t;

View File

@ -47,14 +47,16 @@
#include "avdtp_util.h"
#include "avdtp_acceptor.h"
static int avdtp_pack_service_capabilities(uint8_t * buffer, int size, avdtp_capabilities_t caps, avdtp_service_category_t category){
static int avdtp_pack_service_capabilities(uint8_t * buffer, int size, avdtp_capabilities_t caps, avdtp_service_category_t category, uint8_t pack_all_capabilities){
int i;
// pos = 0 reserved for length
int pos = 1;
switch(category){
case AVDTP_MEDIA_TRANSPORT:
case AVDTP_REPORTING:
break;
case AVDTP_DELAY_REPORTING:
if (!pack_all_capabilities) break;
break;
case AVDTP_RECOVERY:
buffer[pos++] = caps.recovery.recovery_type; // 0x01=RFC2733
@ -64,9 +66,13 @@ static int avdtp_pack_service_capabilities(uint8_t * buffer, int size, avdtp_cap
case AVDTP_CONTENT_PROTECTION:
buffer[pos++] = caps.content_protection.cp_type_lsb;
buffer[pos++] = caps.content_protection.cp_type_msb;
// if (caps.content_protection.cp_type_value_len == 0){
// buffer[pos++] = 0;
// }
for (i = 0; i<caps.content_protection.cp_type_value_len; i++){
buffer[pos++] = caps.content_protection.cp_type_value[i];
}
printf("AVDTP_CONTENT_PROTECTION %d, %d \n", caps.content_protection.cp_type_lsb, caps.content_protection.cp_type_msb);
break;
case AVDTP_HEADER_COMPRESSION:
buffer[pos++] = (caps.header_compression.back_ch << 7) | (caps.header_compression.media << 6) | (caps.header_compression.recovery << 5);
@ -157,22 +163,42 @@ static int avdtp_acceptor_send_seps_response(uint16_t cid, uint8_t transaction_l
return l2cap_send(cid, command, pos);
}
static int avdtp_acceptor_send_capabilities_response(uint16_t cid, uint8_t transaction_label, avdtp_sep_t sep){
static inline int avdtp_acceptor_send_capabilities(uint16_t cid, uint8_t transaction_label, avdtp_sep_t sep, uint8_t pack_all_capabilities){
uint8_t command[100];
uint8_t identifier = (uint8_t)AVDTP_SI_GET_CAPABILITIES;
if (pack_all_capabilities){
identifier = (uint8_t)AVDTP_SI_GET_ALL_CAPABILITIES;
}
int pos = 0;
command[pos++] = avdtp_header(transaction_label, AVDTP_SINGLE_PACKET, AVDTP_RESPONSE_ACCEPT_MSG);
command[pos++] = (uint8_t)AVDTP_SI_GET_CAPABILITIES;
command[pos++] = identifier;
int i = 0;
for (i = 1; i < 9; i++){
if (get_bit16(sep.registered_service_categories, i)){
// service category
command[pos++] = i;
pos += avdtp_pack_service_capabilities(command+pos, sizeof(command)-pos, sep.capabilities, (avdtp_service_category_t)i);
pos += avdtp_pack_service_capabilities(command+pos, sizeof(command)-pos, sep.capabilities, (avdtp_service_category_t)i, pack_all_capabilities);
}
}
command[pos++] = 0x04;
command[pos++] = 0x02;
command[pos++] = 0x02;
command[pos++] = 0x00;
printf(" avdtp_acceptor_send_capabilities_response: \n");
printf_hexdump(command, pos);
return l2cap_send(cid, command, pos);
}
static int avdtp_acceptor_send_capabilities_response(uint16_t cid, uint8_t transaction_label, avdtp_sep_t sep){
return avdtp_acceptor_send_capabilities(cid, transaction_label, sep, 0);
}
static int avdtp_acceptor_send_all_capabilities_response(uint16_t cid, uint8_t transaction_label, avdtp_sep_t sep){
return avdtp_acceptor_send_capabilities(cid, transaction_label, sep, 1);
}
// static int avdtp_acceptor_send_configuration_reject_response(uint16_t cid, uint8_t transaction_label){
// uint8_t command[3];
// command[0] = avdtp_header(transaction_label, AVDTP_SINGLE_PACKET, AVDTP_RESPONSE_REJECT_MSG);
@ -217,14 +243,18 @@ int avdtp_acceptor_stream_config_subsm(avdtp_sink_connection_t * connection, uin
printf(" ACP -> AVDTP_ACCEPTOR_W2_ANSWER_DISCOVER_SEPS\n");
connection->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_DISCOVER_SEPS;
break;
case AVDTP_SI_GET_ALL_CAPABILITIES:
printf(" ACP -> AVDTP_SI_GET_ALL_CAPABILITIES\n");
connection->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_GET_ALL_CAPABILITIES;
break;
case AVDTP_SI_GET_CAPABILITIES:
printf(" ACP -> AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES\n");
connection->local_seid = packet[2] >> 2;
connection->query_seid = packet[2] >> 2;
connection->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES;
break;
case AVDTP_SI_SET_CONFIGURATION:
printf(" ACP -> AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION\n");
connection->local_seid = packet[2] >> 2;
connection->query_seid = packet[2] >> 2;
sep.seid = packet[3] >> 2;
// find or add sep
for (i=0; i<connection->remote_seps_num; i++){
@ -236,9 +266,12 @@ int avdtp_acceptor_stream_config_subsm(avdtp_sink_connection_t * connection, uin
connection->remote_seps[connection->remote_sep_index] = sep;
connection->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION;
break;
default:
printf(" ACP -> NOT IMPLEMENTED\n");
request_to_send = 0;
printf(" ACP -> NOT IMPLEMENTED, Reject signal_identifier %02x\n", signaling_header.signal_identifier);
connection->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_UNKNOWN_CMD;
connection->unknown_signal_identifier = signaling_header.signal_identifier;
request_to_send = 1;
break;
}
l2cap_request_can_send_now_event(connection->l2cap_signaling_cid);
@ -254,6 +287,13 @@ int avdtp_acceptor_stream_config_subsm(avdtp_sink_connection_t * connection, uin
return request_to_send;
}
static int avdtp_acceptor_send_response_reject(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_GENERAL_REJECT_MSG);
command[1] = (uint8_t)identifier;
return l2cap_send(cid, command, sizeof(command));
}
int avdtp_acceptor_stream_config_subsm_run_for_connection(avdtp_sink_connection_t *connection, avdtp_sep_t * local_seps, uint8_t local_seps_num){
int sent = 1;
switch (connection->acceptor_config_state){
@ -265,7 +305,16 @@ int avdtp_acceptor_stream_config_subsm_run_for_connection(avdtp_sink_connection_
case AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES:
printf(" AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES -> AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE\n");
connection->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE;
avdtp_acceptor_send_capabilities_response(connection->l2cap_signaling_cid, connection->acceptor_transaction_label, local_seps[connection->local_seid]);
avdtp_acceptor_send_capabilities_response(connection->l2cap_signaling_cid, connection->acceptor_transaction_label, local_seps[connection->query_seid]);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_GET_ALL_CAPABILITIES:
printf(" AVDTP_ACCEPTOR_W2_ANSWER_GET_ALL_CAPABILITIES -> AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE\n");
connection->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE;
avdtp_acceptor_send_all_capabilities_response(connection->l2cap_signaling_cid, connection->acceptor_transaction_label, local_seps[connection->query_seid]);
break;
case AVDTP_ACCEPTOR_W2_REJECT_UNKNOWN_CMD:
connection->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE;
avdtp_acceptor_send_response_reject(connection->l2cap_signaling_cid, connection->unknown_signal_identifier, connection->acceptor_transaction_label);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION:
printf(" AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION -> AVDTP_ACCEPTOR_STREAM_CONFIG_DONE\n");

View File

@ -54,9 +54,20 @@ static int avdtp_initiator_send_signaling_cmd(uint16_t cid, avdtp_signal_identif
return l2cap_send(cid, command, sizeof(command));
}
static int avdtp_initiator_send_get_capabilities_cmd(uint16_t cid, uint8_t sep_id){
printf("TODO: avdtp_initiator_send_get_capabilities_cmd not implemented\n");
return 0;
static int avdtp_initiator_send_get_all_capabilities_cmd(uint16_t cid, uint8_t transaction_label, uint8_t sep_id){
uint8_t command[3];
command[0] = avdtp_header(transaction_label, AVDTP_SINGLE_PACKET, AVDTP_CMD_MSG);
command[1] = AVDTP_SI_GET_ALL_CAPABILITIES;
command[2] = sep_id << 2;
return l2cap_send(cid, command, sizeof(command));
}
static int avdtp_initiator_send_get_capabilities_cmd(uint16_t cid, uint8_t transaction_label, uint8_t sep_id){
uint8_t command[3];
command[0] = avdtp_header(transaction_label, AVDTP_SINGLE_PACKET, AVDTP_CMD_MSG);
command[1] = AVDTP_SI_GET_CAPABILITIES;
command[2] = sep_id << 2;
return l2cap_send(cid, command, sizeof(command));
}
void avdtp_initiator_stream_config_subsm_init(avdtp_sink_connection_t * connection){
@ -68,6 +79,7 @@ int avdtp_initiator_stream_config_subsm_is_done(avdtp_sink_connection_t * connec
}
int avdtp_initiator_stream_config_subsm(avdtp_sink_connection_t * connection, uint8_t *packet, uint16_t size){
return 0;
if (avdtp_initiator_stream_config_subsm_run_for_connection(connection)) return 1;
int i;
int responded = 1;
@ -115,8 +127,13 @@ int avdtp_initiator_stream_config_subsm(avdtp_sink_connection_t * connection, ui
responded = 1;
break;
case AVDTP_INITIATOR_W4_CAPABILITIES:
printf(" AVDTP_INITIATOR_W4_CAPABILITIES -> NOT IMPLEMENTED\n");
printf(" Received basic capabilities -> NOT IMPLEMENTED\n");
responded = 0;
break;
case AVDTP_INITIATOR_W4_ALL_CAPABILITIES:
printf(" Received all capabilities -> NOT IMPLEMENTED\n");
responded = 0;
break;
default:
printf(" INT : NOT IMPLEMENTED sig. ID %02x\n", signaling_header.signal_identifier);
//printf_hexdump( packet, size );
@ -127,6 +144,7 @@ int avdtp_initiator_stream_config_subsm(avdtp_sink_connection_t * connection, ui
}
int avdtp_initiator_stream_config_subsm_run_for_connection(avdtp_sink_connection_t *connection){
return 0;
int sent = 1;
switch (connection->initiator_config_state){
case AVDTP_INITIATOR_STREAM_CONFIG_IDLE:
@ -136,9 +154,14 @@ int avdtp_initiator_stream_config_subsm_run_for_connection(avdtp_sink_connection
avdtp_initiator_send_signaling_cmd(connection->l2cap_signaling_cid, AVDTP_SI_DISCOVER, connection->initiator_transaction_label);
break;
case AVDTP_INITIATOR_W2_GET_CAPABILITIES:
printf(" AVDTP_INitiator_W2_GET_CAPABILITIES -> AVDTP_INitiator_W4_CAPABILITIES\n");
printf(" AVDTP_INITIATOR_W2_GET_CAPABILITIES -> AVDTP_INITIATOR_W4_CAPABILITIES\n");
connection->initiator_config_state = AVDTP_INITIATOR_W4_CAPABILITIES;
avdtp_initiator_send_get_capabilities_cmd(connection->l2cap_signaling_cid, 0);
avdtp_initiator_send_get_capabilities_cmd(connection->l2cap_signaling_cid, connection->initiator_transaction_label, connection->query_seid);
break;
case AVDTP_INITIATOR_W2_GET_ALL_CAPABILITIES:
printf(" AVDTP_INITIATOR_W2_GET_ALL_CAPABILITIES -> AVDTP_INITIATOR_W4_ALL_CAPABILITIES\n");
connection->initiator_config_state = AVDTP_INITIATOR_W4_ALL_CAPABILITIES;
avdtp_initiator_send_get_all_capabilities_cmd(connection->l2cap_signaling_cid, connection->initiator_transaction_label, connection->query_seid);
break;
default:
sent = 0;

View File

@ -331,7 +331,7 @@ static void handle_l2cap_signaling_data_packet(avdtp_sink_connection_t * connect
switch (signaling_header.signal_identifier){
case AVDTP_SI_OPEN:
printf("AVDTP_CONFIGURED -> AVDTP_W2_ANSWER_OPEN_STREAM %d\n", signaling_header.transaction_label);
connection->local_seid = packet[2] >> 2;
connection->active_seid = packet[2] >> 2;
connection->avdtp_state = AVDTP_W2_ANSWER_OPEN_STREAM;
connection->acceptor_transaction_label = signaling_header.transaction_label;
l2cap_request_can_send_now_event(connection->l2cap_signaling_cid);
@ -345,7 +345,7 @@ static void handle_l2cap_signaling_data_packet(avdtp_sink_connection_t * connect
switch (signaling_header.signal_identifier){
case AVDTP_SI_START:
printf("AVDTP_OPEN -> AVDTP_W2_ANSWER_START_SINGLE_STREAM\n");
connection->local_seid = packet[2] >> 2;
connection->active_seid = packet[2] >> 2;
connection->avdtp_state = AVDTP_W2_ANSWER_START_SINGLE_STREAM;
connection->acceptor_transaction_label = signaling_header.transaction_label;
l2cap_request_can_send_now_event(connection->l2cap_signaling_cid);

View File

@ -82,6 +82,8 @@ typedef enum {
AVDTP_INITIATOR_W4_SEPS_DISCOVERED,
AVDTP_INITIATOR_W2_GET_CAPABILITIES,
AVDTP_INITIATOR_W4_CAPABILITIES,
AVDTP_INITIATOR_W2_GET_ALL_CAPABILITIES,
AVDTP_INITIATOR_W4_ALL_CAPABILITIES,
AVDTP_INITIATOR_W2_SET_CONFIGURATION,
AVDTP_INITIATOR_W4_CONFIGURATION_SET,
AVDTP_INITIATOR_W2_GET_CONFIGURATION,
@ -93,7 +95,9 @@ typedef enum {
AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE,
AVDTP_ACCEPTOR_W2_ANSWER_DISCOVER_SEPS,
AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES,
AVDTP_ACCEPTOR_W2_ANSWER_GET_ALL_CAPABILITIES,
AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION,
AVDTP_ACCEPTOR_W2_REJECT_UNKNOWN_CMD,
AVDTP_ACCEPTOR_STREAM_CONFIG_DONE
} avdtp_acceptor_stream_config_state_t;
@ -115,13 +119,16 @@ typedef struct avdtp_sink_connection {
uint8_t initiator_transaction_label;
uint8_t acceptor_transaction_label;
avdtp_signal_identifier_t unknown_signal_identifier;
// store remote seps
avdtp_sep_t remote_seps[MAX_NUM_SEPS];
uint8_t remote_seps_num;
// currently active local_seid
uint8_t local_seid;
// currently active seid - stream opened
uint8_t active_seid;
uint8_t query_seid;
// currently active remote seid
uint8_t remote_sep_index;

View File

@ -302,9 +302,9 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
}
static const uint8_t media_sbc_codec_info[] = {
(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
2, 250
0xFF, // (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
0xFF, // (AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
2, 53
};
@ -323,13 +323,16 @@ int btstack_main(int argc, const char * argv[]){
uint8_t seid = avdtp_sink_register_stream_end_point(AVDTP_SINK, AVDTP_AUDIO);
avdtp_sink_register_media_transport_category(seid);
avdtp_sink_register_media_codec_category(seid, AVDTP_AUDIO, AVDTP_CODEC_SBC, media_sbc_codec_info, sizeof(media_sbc_codec_info));
// uint8_t cp_type_lsb, uint8_t cp_type_msb, const uint8_t * cp_type_value, uint8_t cp_type_value_len
// avdtp_sink_register_content_protection_category(seid, 2, 2, NULL, 0);
avdtp_sink_register_media_handler(&handle_l2cap_media_data_packet);
// Initialize SDP
sdp_init();
memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer));
a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer, 0x10001, 0, NULL, NULL);
a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer, 0x10001, 1, NULL, NULL);
sdp_register_service(sdp_avdtp_sink_service_buffer);
gap_set_local_name("BTstack AVDTP Test");