mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 10:21:49 +00:00
send media codec caps to app
This commit is contained in:
parent
5df46464e3
commit
a85cbb87fc
@ -295,10 +295,6 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
AVDTP_INITIATOR_STREAM_CONFIG_IDLE,
|
||||
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,
|
||||
@ -357,7 +353,15 @@ typedef enum {
|
||||
typedef enum {
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SEPS_DISCOVERED
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SEPS_DISCOVERED,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_CAPABILITIES,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ALL_CAPABILITIES,
|
||||
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_REJECT_WITH_ERROR_CODE,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE,
|
||||
AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GENERAL_REJECT_WITH_ERROR_CODE
|
||||
} avdtp_initiator_connection_state_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -47,188 +47,6 @@
|
||||
#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, 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
|
||||
buffer[pos++] = caps.recovery.maximum_recovery_window_size;
|
||||
buffer[pos++] = caps.recovery.maximum_number_media_packets;
|
||||
break;
|
||||
case AVDTP_CONTENT_PROTECTION:
|
||||
buffer[pos++] = caps.content_protection.cp_type_value_len + 2;
|
||||
big_endian_store_16(buffer, pos, caps.content_protection.cp_type);
|
||||
pos += 2;
|
||||
memcpy(buffer+pos, caps.content_protection.cp_type_value, caps.content_protection.cp_type_value_len);
|
||||
printf("AVDTP_CONTENT_PROTECTION 0%04x\n", caps.content_protection.cp_type);
|
||||
break;
|
||||
case AVDTP_HEADER_COMPRESSION:
|
||||
buffer[pos++] = (caps.header_compression.back_ch << 7) | (caps.header_compression.media << 6) | (caps.header_compression.recovery << 5);
|
||||
break;
|
||||
case AVDTP_MULTIPLEXING:
|
||||
buffer[pos++] = caps.multiplexing_mode.fragmentation << 7;
|
||||
for (i=0; i<caps.multiplexing_mode.transport_identifiers_num; i++){
|
||||
buffer[pos++] = caps.multiplexing_mode.transport_session_identifiers[i] << 7;
|
||||
buffer[pos++] = caps.multiplexing_mode.tcid[i] << 7;
|
||||
// media, reporting. recovery
|
||||
}
|
||||
break;
|
||||
case AVDTP_MEDIA_CODEC:
|
||||
buffer[pos++] = ((uint8_t)caps.media_codec.media_type) << 4;
|
||||
buffer[pos++] = (uint8_t)caps.media_codec.media_codec_type;
|
||||
for (i = 0; i<caps.media_codec.media_codec_information_len; i++){
|
||||
buffer[pos++] = caps.media_codec.media_codec_information[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
buffer[0] = pos - 1; // length
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * connection, avdtp_service_category_t category, uint8_t cap_len){
|
||||
connection->error_code = 0;
|
||||
|
||||
if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_DELAY_REPORTING){
|
||||
printf(" ACP: BAD SERVICE CATEGORY %d\n", category);
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_SERV_CATEGORY;
|
||||
return 1;
|
||||
}
|
||||
if (connection->signaling_packet.signal_identifier == AVDTP_SI_RECONFIGURE){
|
||||
if (category != AVDTP_CONTENT_PROTECTION && category != AVDTP_MEDIA_CODEC){
|
||||
printf(" ACP: REJECT CATEGORY, INVALID_CAPABILITIES\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = INVALID_CAPABILITIES;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
switch(category){
|
||||
case AVDTP_MEDIA_TRANSPORT:
|
||||
if (cap_len != 0){
|
||||
printf(" ACP: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_MEDIA_TRANSPORT_FORMAT;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_REPORTING:
|
||||
case AVDTP_DELAY_REPORTING:
|
||||
if (cap_len != 0){
|
||||
printf(" ACP: REJECT CATEGORY, BAD_LENGTH\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_LENGTH;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_RECOVERY:
|
||||
if (cap_len < 3){
|
||||
printf(" ACP: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_RECOVERY_FORMAT;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_CONTENT_PROTECTION:
|
||||
if (cap_len < 2){
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_CP_FORMAT;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_HEADER_COMPRESSION:
|
||||
break;
|
||||
case AVDTP_MULTIPLEXING:
|
||||
break;
|
||||
case AVDTP_MEDIA_CODEC:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdtp_capabilities_t * caps, uint8_t * packet, uint16_t size){
|
||||
uint16_t registered_service_categories = 0;
|
||||
int pos = 0;
|
||||
int i;
|
||||
avdtp_service_category_t category = (avdtp_service_category_t)packet[pos++];
|
||||
uint8_t cap_len = packet[pos++];
|
||||
if (avdtp_unpack_service_capabilities_has_errors(connection, category, cap_len)) return 0;
|
||||
printf(" avdtp_unpack_service_capabilities category %d, len %d\n", category, cap_len);
|
||||
|
||||
int processed_cap_len = 0;
|
||||
while (pos < size){
|
||||
processed_cap_len = pos;
|
||||
switch(category){
|
||||
case AVDTP_MEDIA_TRANSPORT:
|
||||
break;
|
||||
case AVDTP_REPORTING:
|
||||
break;
|
||||
case AVDTP_DELAY_REPORTING:
|
||||
break;
|
||||
case AVDTP_RECOVERY:
|
||||
caps->recovery.recovery_type = packet[pos++];
|
||||
caps->recovery.maximum_recovery_window_size = packet[pos++];
|
||||
caps->recovery.maximum_number_media_packets = packet[pos++];
|
||||
break;
|
||||
case AVDTP_CONTENT_PROTECTION:
|
||||
caps->content_protection.cp_type = big_endian_read_16(packet, pos);
|
||||
pos+=2;
|
||||
|
||||
caps->content_protection.cp_type_value_len = cap_len - 2;
|
||||
pos += caps->content_protection.cp_type_value_len;
|
||||
|
||||
// connection->reject_service_category = category;
|
||||
// connection->error_code = UNSUPPORTED_CONFIGURATION;
|
||||
// support for content protection goes here
|
||||
return 0;
|
||||
|
||||
case AVDTP_HEADER_COMPRESSION:
|
||||
caps->header_compression.back_ch = packet[pos] >> 7;
|
||||
caps->header_compression.media = packet[pos] >> 6;
|
||||
caps->header_compression.recovery = packet[pos] >> 5;
|
||||
pos++;
|
||||
break;
|
||||
case AVDTP_MULTIPLEXING:
|
||||
caps->multiplexing_mode.fragmentation = packet[pos++] >> 7;
|
||||
// read [tsid, tcid] for media, reporting. recovery respectively
|
||||
caps->multiplexing_mode.transport_identifiers_num = 3;
|
||||
for (i=0; i<caps->multiplexing_mode.transport_identifiers_num; i++){
|
||||
caps->multiplexing_mode.transport_session_identifiers[i] = packet[pos++] >> 7;
|
||||
caps->multiplexing_mode.tcid[i] = packet[pos++] >> 7;
|
||||
}
|
||||
break;
|
||||
case AVDTP_MEDIA_CODEC:
|
||||
caps->media_codec.media_type = packet[pos++] >> 4;
|
||||
caps->media_codec.media_codec_type = packet[pos++];
|
||||
caps->media_codec.media_codec_information_len = cap_len - 2;
|
||||
// printf_hexdump(packet+pos, caps->media_codec.media_codec_information_len);
|
||||
pos += caps->media_codec.media_codec_information_len;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
registered_service_categories = store_bit16(registered_service_categories, category, 1);
|
||||
processed_cap_len = pos - processed_cap_len;
|
||||
if (cap_len <= processed_cap_len && pos < size-2){
|
||||
category = (avdtp_service_category_t)packet[pos++];
|
||||
cap_len = packet[pos++];
|
||||
if (avdtp_unpack_service_capabilities_has_errors(connection, category, cap_len)) return 0;
|
||||
}
|
||||
}
|
||||
return registered_service_categories;
|
||||
}
|
||||
|
||||
static inline void avdtp_acceptor_prepare_capabilities_response(avdtp_signaling_packet_t * signaling_packet, uint8_t transaction_label, avdtp_sep_t sep, uint8_t identifier){
|
||||
if (signaling_packet->offset) return;
|
||||
uint8_t pack_all_capabilities = 1;
|
||||
|
@ -47,21 +47,21 @@
|
||||
#include "avdtp_util.h"
|
||||
#include "avdtp_initiator.h"
|
||||
|
||||
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_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));
|
||||
}
|
||||
// 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));
|
||||
// }
|
||||
|
||||
|
||||
int avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, avdtp_stream_endpoint_t * stream_endpoint, uint8_t *packet, uint16_t size){
|
||||
@ -69,14 +69,8 @@ int avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, avdtp_s
|
||||
if (avdtp_initiator_stream_config_subsm_run(connection, stream_endpoint)) return 1;
|
||||
|
||||
int responded = 1;
|
||||
|
||||
printf(" avdtp_initiator_stream_config_subsm got response\n");
|
||||
switch (stream_endpoint->initiator_config_state){
|
||||
case AVDTP_INITIATOR_W4_CAPABILITIES:
|
||||
printf(" INT : AVDTP_INITIATOR_W4_CAPABILITIES, Received basic capabilities -> NOT IMPLEMENTED\n");
|
||||
return 0;
|
||||
case AVDTP_INITIATOR_W4_ALL_CAPABILITIES:
|
||||
printf(" INT : AVDTP_INITIATOR_W4_ALL_CAPABILITIES -> NOT IMPLEMENTED\n");
|
||||
return 0;
|
||||
default:
|
||||
printf(" INT : NOT IMPLEMENTED sig. ID %02x\n", connection->signaling_packet.signal_identifier);
|
||||
//printf_hexdump( packet, size );
|
||||
@ -88,16 +82,16 @@ int avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, avdtp_s
|
||||
int avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, avdtp_stream_endpoint_t * stream_endpoint){
|
||||
int sent = 1;
|
||||
switch (stream_endpoint->initiator_config_state){
|
||||
case AVDTP_INITIATOR_W2_GET_CAPABILITIES:
|
||||
printf(" INT: AVDTP_INITIATOR_W2_GET_CAPABILITIES -> AVDTP_INITIATOR_W4_CAPABILITIES\n");
|
||||
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W4_CAPABILITIES;
|
||||
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(" INT: AVDTP_INITIATOR_W2_GET_ALL_CAPABILITIES -> AVDTP_INITIATOR_W4_ALL_CAPABILITIES\n");
|
||||
stream_endpoint->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;
|
||||
// case AVDTP_INITIATOR_W2_GET_CAPABILITIES:
|
||||
// printf(" INT: AVDTP_INITIATOR_W2_GET_CAPABILITIES -> AVDTP_INITIATOR_W4_CAPABILITIES\n");
|
||||
// stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W4_CAPABILITIES;
|
||||
// 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(" INT: AVDTP_INITIATOR_W2_GET_ALL_CAPABILITIES -> AVDTP_INITIATOR_W4_ALL_CAPABILITIES\n");
|
||||
// stream_endpoint->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;
|
||||
break;
|
||||
|
@ -186,6 +186,45 @@ static void avdtp_signaling_emit_done(btstack_packet_handler_t callback, uint16_
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void avdtp_signaling_emit_media_codec_sbc(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
|
||||
if (!callback) return;
|
||||
uint8_t event[13];
|
||||
int pos = 0;
|
||||
event[pos++] = HCI_EVENT_AVDTP_META;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC;
|
||||
little_endian_store_16(event, pos, con_handle);
|
||||
pos += 2;
|
||||
event[pos++] = media_codec.media_type;
|
||||
event[pos++] = media_codec.media_codec_information[0] >> 4;
|
||||
event[pos++] = media_codec.media_codec_information[0] & 0x0F;
|
||||
event[pos++] = media_codec.media_codec_information[1] >> 4;
|
||||
event[pos++] = (media_codec.media_codec_information[1] & 0x0F) >> 2;
|
||||
event[pos++] = media_codec.media_codec_information[1] & 0x03;
|
||||
event[pos++] = media_codec.media_codec_information[2];
|
||||
event[pos++] = media_codec.media_codec_information[3];
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void avdtp_signaling_emit_media_codec_other(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
|
||||
if (!callback) return;
|
||||
uint8_t event[109];
|
||||
int pos = 0;
|
||||
event[pos++] = HCI_EVENT_AVDTP_META;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER;
|
||||
little_endian_store_16(event, pos, con_handle);
|
||||
pos += 2;
|
||||
event[pos++] = media_codec.media_type;
|
||||
little_endian_store_16(event, pos, media_codec.media_codec_type);
|
||||
pos += 2;
|
||||
little_endian_store_16(event, pos, media_codec.media_codec_information_len);
|
||||
pos += 2;
|
||||
memcpy(event+pos, media_codec.media_codec_information, media_codec.media_codec_information_len);
|
||||
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static avdtp_stream_endpoint_t * get_avdtp_stream_endpoint_for_seid(uint16_t seid){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &stream_endpoints);
|
||||
@ -425,6 +464,14 @@ 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_signaling_cmd_with_seid(uint16_t cid, avdtp_signal_identifier_t identifier, 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] = (uint8_t)identifier;
|
||||
command[2] = sep_id << 2;
|
||||
return l2cap_send(cid, command, sizeof(command));
|
||||
}
|
||||
|
||||
|
||||
static void avdtp_sink_request_can_send_now_acceptor(avdtp_connection_t * connection, uint16_t l2cap_cid){
|
||||
connection->wait_to_send_acceptor = 1;
|
||||
@ -494,8 +541,15 @@ static void avdtp_sink_handle_can_send_now(avdtp_connection_t * connection, uint
|
||||
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS:
|
||||
printf(" -> AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SEPS_DISCOVERED\n");
|
||||
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SEPS_DISCOVERED;
|
||||
connection->initiator_transaction_label++;
|
||||
avdtp_initiator_send_signaling_cmd(connection->l2cap_signaling_cid, AVDTP_SI_DISCOVER, connection->initiator_transaction_label);
|
||||
return;
|
||||
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES:
|
||||
printf(" -> AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES\n");
|
||||
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_CAPABILITIES;
|
||||
connection->initiator_transaction_label++;
|
||||
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_GET_CAPABILITIES, connection->initiator_transaction_label, connection->query_seid);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -665,7 +719,7 @@ static int handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t
|
||||
printf("handle_l2cap_data_packet_for_signaling_connection AVDTP_RESPONSE_ACCEPT_MSG, identifier %d\n", connection->signaling_packet.signal_identifier);
|
||||
|
||||
switch (connection->signaling_packet.signal_identifier){
|
||||
case AVDTP_SI_DISCOVER:
|
||||
case AVDTP_SI_DISCOVER:{
|
||||
if (connection->signaling_packet.transaction_label != connection->initiator_transaction_label){
|
||||
printf("unexpected transaction label, got %d, expected %d\n", connection->signaling_packet.transaction_label, connection->initiator_transaction_label);
|
||||
return 0;
|
||||
@ -693,6 +747,25 @@ static int handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t
|
||||
connection->initiator_transaction_label++;
|
||||
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE;
|
||||
break;
|
||||
}
|
||||
case AVDTP_SI_GET_CAPABILITIES:{
|
||||
avdtp_sep_t sep;
|
||||
sep.registered_service_categories = avdtp_unpack_service_capabilities(connection, &sep.capabilities, packet+2, size-2);
|
||||
if (get_bit16(sep.registered_service_categories, AVDTP_MEDIA_CODEC)){
|
||||
switch (sep.capabilities.media_codec.media_codec_type){
|
||||
case AVDTP_CODEC_SBC:
|
||||
avdtp_signaling_emit_media_codec_sbc(avdtp_sink_callback, connection->con_handle, sep.capabilities.media_codec);
|
||||
break;
|
||||
default:
|
||||
avdtp_signaling_emit_media_codec_other(avdtp_sink_callback, connection->con_handle, sep.capabilities.media_codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
avdtp_signaling_emit_done(avdtp_sink_callback, connection->con_handle, 0);
|
||||
//avdtp_signaling_emit_done(avdtp_sink_callback, connection->con_handle, 0);
|
||||
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("AVDTP_RESPONSE_ACCEPT_MSG signal %d not implemented\n", connection->signaling_packet.signal_identifier);
|
||||
break;
|
||||
@ -977,10 +1050,10 @@ void avdtp_sink_disconnect(uint16_t con_handle){
|
||||
//avdtp_sink_run(connection);
|
||||
}
|
||||
|
||||
void avdtp_sink_stream_endpoint_discovery(uint16_t con_handle){
|
||||
void avdtp_sink_discover_stream_endpoints(uint16_t con_handle){
|
||||
avdtp_connection_t * connection = get_avdtp_connection_for_con_handle(con_handle);
|
||||
if (!connection){
|
||||
printf("avdtp_sink_stream_endpoint_discovery: no connection for handle 0x%02x found\n", con_handle);
|
||||
printf("avdtp_sink_discover_stream_endpoints: no connection for handle 0x%02x found\n", con_handle);
|
||||
return;
|
||||
}
|
||||
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
|
||||
@ -991,7 +1064,49 @@ void avdtp_sink_stream_endpoint_discovery(uint16_t con_handle){
|
||||
avdtp_sink_request_can_send_now_self(connection, connection->l2cap_signaling_cid);
|
||||
break;
|
||||
default:
|
||||
printf("avdtp_sink_stream_endpoint_discovery: wrong state\n");
|
||||
printf("avdtp_sink_discover_stream_endpoints: wrong state\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void avdtp_sink_get_capabilities(uint16_t con_handle, uint8_t seid){
|
||||
avdtp_connection_t * connection = get_avdtp_connection_for_con_handle(con_handle);
|
||||
if (!connection){
|
||||
printf("avdtp_sink_discover_stream_endpoints: no connection for handle 0x%02x found\n", con_handle);
|
||||
return;
|
||||
}
|
||||
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
|
||||
if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE) return;
|
||||
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
|
||||
connection->query_seid = seid;
|
||||
avdtp_sink_request_can_send_now_self(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
|
||||
|
||||
void avdtp_sink_get_all_capabilities(uint16_t con_handle, uint8_t seid){
|
||||
avdtp_connection_t * connection = get_avdtp_connection_for_con_handle(con_handle);
|
||||
if (!connection){
|
||||
printf("avdtp_sink_discover_stream_endpoints: no connection for handle 0x%02x found\n", con_handle);
|
||||
return;
|
||||
}
|
||||
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
|
||||
if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE) return;
|
||||
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES;
|
||||
connection->query_seid = seid;
|
||||
avdtp_sink_request_can_send_now_self(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
|
||||
|
||||
void avdtp_sink_set_capabilities(uint16_t con_handle, uint8_t seid){
|
||||
avdtp_connection_t * connection = get_avdtp_connection_for_con_handle(con_handle);
|
||||
if (!connection){
|
||||
printf("avdtp_sink_discover_stream_endpoints: no connection for handle 0x%02x found\n", con_handle);
|
||||
return;
|
||||
}
|
||||
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
|
||||
avdtp_stream_endpoint_t * stream_endpoint = get_avdtp_stream_endpoint_for_seid(seid);
|
||||
if (!stream_endpoint || stream_endpoint->initiator_config_state != AVDTP_STREAM_ENDPOINT_IDLE) return;
|
||||
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION;
|
||||
avdtp_sink_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
|
@ -106,8 +106,25 @@ void avdtp_sink_disconnect(uint16_t con_handle);
|
||||
* @brief Discover stream endpoints
|
||||
* @param con_handle
|
||||
*/
|
||||
void avdtp_sink_discover_stream_endpoints(uint16_t con_handle);
|
||||
|
||||
void avdtp_sink_stream_endpoint_discovery(uint16_t con_handle);
|
||||
/**
|
||||
* @brief Get capabilities
|
||||
* @param con_handle
|
||||
*/
|
||||
void avdtp_sink_get_capabilities(uint16_t con_handle, uint8_t seid);
|
||||
|
||||
/**
|
||||
* @brief Get all capabilities
|
||||
* @param con_handle
|
||||
*/
|
||||
void avdtp_sink_get_all_capabilities(uint16_t con_handle, uint8_t seid);
|
||||
|
||||
/**
|
||||
* @brief Set capabilities
|
||||
* @param con_handle
|
||||
*/
|
||||
void avdtp_sink_set_capabilities(uint16_t con_handle, uint8_t seid);
|
||||
|
||||
/* API_END */
|
||||
|
||||
|
@ -141,15 +141,31 @@ static char * sbc_filename = "avdtp_sink.sbc";
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
// bitmaps
|
||||
uint8_t sampling_frequency_bitmap;
|
||||
uint8_t channel_mode_bitmap;
|
||||
uint8_t block_length_bitmap;
|
||||
uint8_t subbands_bitmap;
|
||||
uint8_t allocation_method_bitmap;
|
||||
uint8_t min_bitpool_value;
|
||||
uint8_t max_bitpool_value;
|
||||
} adtvp_media_codec_information_sbc_t;
|
||||
|
||||
// mac: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
|
||||
// pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
|
||||
static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
|
||||
static uint16_t con_handle = 0;
|
||||
static uint8_t sdp_avdtp_sink_service_buffer[150];
|
||||
|
||||
static avdtp_sep_t sep;
|
||||
static adtvp_media_codec_information_sbc_t sbc;
|
||||
|
||||
typedef enum {
|
||||
AVDTP_APPLICATION_IDLE,
|
||||
AVDTP_APPLICATION_W2_DISCOVER_SEPS
|
||||
AVDTP_APPLICATION_W2_DISCOVER_SEPS,
|
||||
AVDTP_APPLICATION_W2_GET_CAPABILITIES,
|
||||
AVDTP_APPLICATION_W2_GET_ALL_CAPABILITIES,
|
||||
AVDTP_APPLICATION_W2_SET_CAPABILITIES
|
||||
} avdtp_application_state_t;
|
||||
|
||||
avdtp_application_state_t app_state = AVDTP_APPLICATION_IDLE;
|
||||
@ -294,6 +310,17 @@ static void handle_l2cap_media_data_packet(avdtp_stream_endpoint_t * stream_endp
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dump_media_codec_sbc(adtvp_media_codec_information_sbc_t media_codec_sbc){
|
||||
printf("Received media codec capability:\n");
|
||||
printf(" - sampling_frequency: %02x\n", media_codec_sbc.sampling_frequency_bitmap);
|
||||
printf(" - channel_mode: %02x\n", media_codec_sbc.channel_mode_bitmap);
|
||||
printf(" - block_length: %02x\n", media_codec_sbc.block_length_bitmap);
|
||||
printf(" - subbands: %02x\n", media_codec_sbc.subbands_bitmap);
|
||||
printf(" - allocation_method: %x\n", media_codec_sbc.allocation_method_bitmap);
|
||||
printf("bitpool_value [%d, %d] \n", media_codec_sbc.min_bitpool_value, media_codec_sbc.max_bitpool_value);
|
||||
}
|
||||
|
||||
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
bd_addr_t event_addr;
|
||||
switch (packet_type) {
|
||||
@ -331,13 +358,24 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
|
||||
break;
|
||||
case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND:
|
||||
if (app_state != AVDTP_APPLICATION_W2_DISCOVER_SEPS) return;
|
||||
avdtp_sep_t sep;
|
||||
sep.seid = avdtp_subevent_signaling_sep_found_get_seid(packet);
|
||||
sep.in_use = avdtp_subevent_signaling_sep_found_get_in_use(packet);
|
||||
sep.media_type = avdtp_subevent_signaling_sep_found_get_media_type(packet);
|
||||
sep.type = avdtp_subevent_signaling_sep_found_get_sep_type(packet);
|
||||
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);
|
||||
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;
|
||||
case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC:
|
||||
sbc.sampling_frequency_bitmap = avdtp_subevent_signaling_media_codec_sbc_get_sampling_frequency(packet);
|
||||
sbc.channel_mode_bitmap = avdtp_subevent_signaling_media_codec_sbc_get_channel_mode(packet);
|
||||
sbc.block_length_bitmap = avdtp_subevent_signaling_media_codec_sbc_get_block_length(packet);
|
||||
sbc.subbands_bitmap = avdtp_subevent_signaling_media_codec_sbc_get_subbands(packet);
|
||||
sbc.allocation_method_bitmap = avdtp_subevent_signaling_media_codec_sbc_get_allocation_method(packet);
|
||||
sbc.min_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_get_min_bitpool_value(packet);
|
||||
sbc.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_get_max_bitpool_value(packet);
|
||||
dump_media_codec_sbc(sbc);
|
||||
break;
|
||||
case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER:
|
||||
printf(" received non SBC codec. not implemented\n");
|
||||
break;
|
||||
case AVDTP_SUBEVENT_SIGNALING_DONE:
|
||||
app_state = AVDTP_APPLICATION_IDLE;
|
||||
@ -364,11 +402,15 @@ static void show_usage(void){
|
||||
printf("c - create connection to addr %s\n", bd_addr_to_str(remote));
|
||||
printf("C - disconnect\n");
|
||||
printf("d - discover stream endpoints\n");
|
||||
|
||||
printf("g - get capabilities\n");
|
||||
printf("a - get all capabilities\n");
|
||||
printf("s - set capabilities\n");
|
||||
|
||||
printf("Ctrl-c - exit\n");
|
||||
printf("---\n");
|
||||
}
|
||||
|
||||
|
||||
static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
|
||||
if (app_state != AVDTP_APPLICATION_IDLE) {
|
||||
printf("Application is not idle.\n");
|
||||
@ -376,6 +418,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
}
|
||||
char buffer;
|
||||
read(ds->fd, &buffer, 1);
|
||||
sep.seid = 1;
|
||||
switch (buffer){
|
||||
case 'c':
|
||||
printf("Creating L2CAP Connection to %s, PSM_AVDTP\n", bd_addr_to_str(remote));
|
||||
@ -387,7 +430,19 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
break;
|
||||
case 'd':
|
||||
app_state = AVDTP_APPLICATION_W2_DISCOVER_SEPS;
|
||||
avdtp_sink_stream_endpoint_discovery(con_handle);
|
||||
avdtp_sink_discover_stream_endpoints(con_handle);
|
||||
break;
|
||||
case 'g':
|
||||
app_state = AVDTP_APPLICATION_W2_GET_CAPABILITIES;
|
||||
avdtp_sink_get_capabilities(con_handle, sep.seid);
|
||||
break;
|
||||
case 'a':
|
||||
app_state = AVDTP_APPLICATION_W2_GET_ALL_CAPABILITIES;
|
||||
avdtp_sink_get_all_capabilities(con_handle, sep.seid);
|
||||
break;
|
||||
case 's':
|
||||
app_state = AVDTP_APPLICATION_W2_SET_CAPABILITIES;
|
||||
avdtp_sink_set_capabilities(con_handle, sep.seid);
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
|
@ -94,3 +94,184 @@ void avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header, ui
|
||||
}
|
||||
signaling_header->signal_identifier = packet[pos] & 0x3f;
|
||||
}
|
||||
|
||||
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
|
||||
buffer[pos++] = caps.recovery.maximum_recovery_window_size;
|
||||
buffer[pos++] = caps.recovery.maximum_number_media_packets;
|
||||
break;
|
||||
case AVDTP_CONTENT_PROTECTION:
|
||||
buffer[pos++] = caps.content_protection.cp_type_value_len + 2;
|
||||
big_endian_store_16(buffer, pos, caps.content_protection.cp_type);
|
||||
pos += 2;
|
||||
memcpy(buffer+pos, caps.content_protection.cp_type_value, caps.content_protection.cp_type_value_len);
|
||||
printf("AVDTP_CONTENT_PROTECTION 0%04x\n", caps.content_protection.cp_type);
|
||||
break;
|
||||
case AVDTP_HEADER_COMPRESSION:
|
||||
buffer[pos++] = (caps.header_compression.back_ch << 7) | (caps.header_compression.media << 6) | (caps.header_compression.recovery << 5);
|
||||
break;
|
||||
case AVDTP_MULTIPLEXING:
|
||||
buffer[pos++] = caps.multiplexing_mode.fragmentation << 7;
|
||||
for (i=0; i<caps.multiplexing_mode.transport_identifiers_num; i++){
|
||||
buffer[pos++] = caps.multiplexing_mode.transport_session_identifiers[i] << 7;
|
||||
buffer[pos++] = caps.multiplexing_mode.tcid[i] << 7;
|
||||
// media, reporting. recovery
|
||||
}
|
||||
break;
|
||||
case AVDTP_MEDIA_CODEC:
|
||||
buffer[pos++] = ((uint8_t)caps.media_codec.media_type) << 4;
|
||||
buffer[pos++] = (uint8_t)caps.media_codec.media_codec_type;
|
||||
for (i = 0; i<caps.media_codec.media_codec_information_len; i++){
|
||||
buffer[pos++] = caps.media_codec.media_codec_information[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
buffer[0] = pos - 1; // length
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * connection, avdtp_service_category_t category, uint8_t cap_len){
|
||||
connection->error_code = 0;
|
||||
|
||||
if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_DELAY_REPORTING){
|
||||
printf(" ACP: BAD SERVICE CATEGORY %d\n", category);
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_SERV_CATEGORY;
|
||||
return 1;
|
||||
}
|
||||
if (connection->signaling_packet.signal_identifier == AVDTP_SI_RECONFIGURE){
|
||||
if (category != AVDTP_CONTENT_PROTECTION && category != AVDTP_MEDIA_CODEC){
|
||||
printf(" ACP: REJECT CATEGORY, INVALID_CAPABILITIES\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = INVALID_CAPABILITIES;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
switch(category){
|
||||
case AVDTP_MEDIA_TRANSPORT:
|
||||
if (cap_len != 0){
|
||||
printf(" ACP: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_MEDIA_TRANSPORT_FORMAT;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_REPORTING:
|
||||
case AVDTP_DELAY_REPORTING:
|
||||
if (cap_len != 0){
|
||||
printf(" ACP: REJECT CATEGORY, BAD_LENGTH\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_LENGTH;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_RECOVERY:
|
||||
if (cap_len < 3){
|
||||
printf(" ACP: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_RECOVERY_FORMAT;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_CONTENT_PROTECTION:
|
||||
if (cap_len < 2){
|
||||
connection->reject_service_category = category;
|
||||
connection->error_code = BAD_CP_FORMAT;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case AVDTP_HEADER_COMPRESSION:
|
||||
break;
|
||||
case AVDTP_MULTIPLEXING:
|
||||
break;
|
||||
case AVDTP_MEDIA_CODEC:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdtp_capabilities_t * caps, uint8_t * packet, uint16_t size){
|
||||
uint16_t registered_service_categories = 0;
|
||||
int pos = 0;
|
||||
int i;
|
||||
avdtp_service_category_t category = (avdtp_service_category_t)packet[pos++];
|
||||
uint8_t cap_len = packet[pos++];
|
||||
if (avdtp_unpack_service_capabilities_has_errors(connection, category, cap_len)) return 0;
|
||||
|
||||
int processed_cap_len = 0;
|
||||
while (pos < size){
|
||||
processed_cap_len = pos;
|
||||
switch(category){
|
||||
case AVDTP_MEDIA_TRANSPORT:
|
||||
break;
|
||||
case AVDTP_REPORTING:
|
||||
break;
|
||||
case AVDTP_DELAY_REPORTING:
|
||||
break;
|
||||
case AVDTP_RECOVERY:
|
||||
caps->recovery.recovery_type = packet[pos++];
|
||||
caps->recovery.maximum_recovery_window_size = packet[pos++];
|
||||
caps->recovery.maximum_number_media_packets = packet[pos++];
|
||||
break;
|
||||
case AVDTP_CONTENT_PROTECTION:
|
||||
caps->content_protection.cp_type = big_endian_read_16(packet, pos);
|
||||
pos+=2;
|
||||
|
||||
caps->content_protection.cp_type_value_len = cap_len - 2;
|
||||
pos += caps->content_protection.cp_type_value_len;
|
||||
|
||||
// connection->reject_service_category = category;
|
||||
// connection->error_code = UNSUPPORTED_CONFIGURATION;
|
||||
// support for content protection goes here
|
||||
return 0;
|
||||
|
||||
case AVDTP_HEADER_COMPRESSION:
|
||||
caps->header_compression.back_ch = packet[pos] >> 7;
|
||||
caps->header_compression.media = packet[pos] >> 6;
|
||||
caps->header_compression.recovery = packet[pos] >> 5;
|
||||
pos++;
|
||||
break;
|
||||
case AVDTP_MULTIPLEXING:
|
||||
caps->multiplexing_mode.fragmentation = packet[pos++] >> 7;
|
||||
// read [tsid, tcid] for media, reporting. recovery respectively
|
||||
caps->multiplexing_mode.transport_identifiers_num = 3;
|
||||
for (i=0; i<caps->multiplexing_mode.transport_identifiers_num; i++){
|
||||
caps->multiplexing_mode.transport_session_identifiers[i] = packet[pos++] >> 7;
|
||||
caps->multiplexing_mode.tcid[i] = packet[pos++] >> 7;
|
||||
}
|
||||
break;
|
||||
case AVDTP_MEDIA_CODEC:
|
||||
caps->media_codec.media_type = packet[pos++] >> 4;
|
||||
caps->media_codec.media_codec_type = packet[pos++];
|
||||
caps->media_codec.media_codec_information_len = cap_len - 2;
|
||||
caps->media_codec.media_codec_information = &packet[pos];
|
||||
pos += caps->media_codec.media_codec_information_len;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
registered_service_categories = store_bit16(registered_service_categories, category, 1);
|
||||
processed_cap_len = pos - processed_cap_len;
|
||||
if (cap_len <= processed_cap_len && pos < size-2){
|
||||
category = (avdtp_service_category_t)packet[pos++];
|
||||
cap_len = packet[pos++];
|
||||
if (avdtp_unpack_service_capabilities_has_errors(connection, category, cap_len)) return 0;
|
||||
}
|
||||
}
|
||||
return registered_service_categories;
|
||||
}
|
@ -57,6 +57,10 @@ void avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header,
|
||||
uint8_t store_bit16(uint16_t bitmap, int position, uint8_t value);
|
||||
int get_bit16(uint16_t bitmap, int position);
|
||||
|
||||
int avdtp_pack_service_capabilities(uint8_t * buffer, int size, avdtp_capabilities_t caps, avdtp_service_category_t category, uint8_t pack_all_capabilities);
|
||||
uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdtp_capabilities_t * caps, uint8_t * packet, uint16_t size);
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user