avdtp: avdtp_register_media_config_validator allows to validate media codec configuration

This commit is contained in:
Matthias Ringwald 2021-03-23 15:12:52 +01:00
parent cdc66b5eb8
commit 1ef2d533ff
4 changed files with 40 additions and 3 deletions

View File

@ -25,6 +25,7 @@ GAP: add `gap_set_page_scan_activity` and `gap_set_page_scan_type`
AVRCP: new field `button_pressed` in `AVRCP_SUBEVENT_OPERATION`
AVRCP: `AVRCP_SUBEVENT_OPERATION` emitted for button release
AVRCP Controller: avrcp_controller_start_press_and_hold_cmd helps to support device buttons
AVDTP: `avdtp_register_media_config_validator` allows to validate media codec configuration
### Fixed
HCI: handle start inquiry failure

View File

@ -60,6 +60,7 @@ static bool l2cap_registered;
static btstack_packet_handler_t avdtp_source_callback;
static btstack_packet_handler_t avdtp_sink_callback;
static btstack_context_callback_registration_t avdtp_handle_sdp_client_query_request;
static uint8_t (*avdtp_media_config_validator)(const avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len);
static uint16_t sdp_query_context_avdtp_cid = 0;
@ -429,6 +430,17 @@ void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *
avdtp_sink_handle_media_data = callback;
}
void avdtp_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len)){
avdtp_media_config_validator = callback;
}
uint8_t avdtp_validate_media_configuration(const avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len){
if (avdtp_media_config_validator == NULL) {
return 0;
}
return (*avdtp_media_config_validator)(stream_endpoint, media_codec_type, media_codec_info, media_codec_info_len);
}
/* START: tracking can send now requests per l2cap cid */
static void avdtp_handle_can_send_now(uint16_t l2cap_cid) {
@ -1517,6 +1529,7 @@ void avdtp_deinit(void){
stream_endpoints = NULL;
connections = NULL;
avdtp_sink_handle_media_data = NULL;
avdtp_media_config_validator = NULL;
sdp_query_context_avdtp_cid = 0;
stream_endpoints_id_counter = 0;

View File

@ -621,6 +621,13 @@ void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpo
// sink only
void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size));
/**
* @brief Register media configuration validator. Can reject insuitable configuration or report stream endpoint as currently busy
* @note validator has to return AVDTP error codes like: SEP_IN_USE or UNSUPPORTED_CONFIGURATION
* @param callback
*/
void avdtp_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len));
void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type);
void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint);
@ -642,6 +649,7 @@ uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid);
uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid);
uint8_t avdtp_set_configuration(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
uint8_t avdtp_reconfigure(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
uint8_t avdtp_validate_media_configuration(const avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len);
// frequency will be used by avdtp_choose_sbc_sampling_frequency (if supported by both endpoints)
void avdtp_set_preferred_sampling_frequeny(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency);

View File

@ -89,20 +89,35 @@ static void
avdtp_acceptor_handle_configuration_command(avdtp_connection_t *connection, int offset, uint16_t packet_size, avdtp_stream_endpoint_t *stream_endpoint) {
log_info("W2_ANSWER_SET_CONFIGURATION cid 0x%02x", connection->avdtp_cid);
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURATION_SUBSTATEMACHINE;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION;
connection->reject_service_category = 0;
stream_endpoint->connection = connection;
// process capabilities, first rejected service category is stored in connection
connection->reject_service_category = 0;
avdtp_sep_t sep;
sep.seid = connection->acceptor_signaling_packet.command[offset++] >> 2;
sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, connection->acceptor_signaling_packet.signal_identifier, &sep.configuration, connection->acceptor_signaling_packet.command+offset, packet_size-offset);
sep.in_use = 1;
// let application validate media configuration as well
if (connection->error_code == 0){
if ((sep.configured_service_categories & (1 << AVDTP_MEDIA_CODEC)) != 0){
adtvp_media_codec_capabilities_t * media = & sep.configuration.media_codec;
uint8_t error_code = avdtp_validate_media_configuration(stream_endpoint, media->media_codec_type, media->media_codec_information, media->media_codec_information_len);
if (error_code != 0){
log_info("media codec rejected by validator, error 0x%02x", error_code);
connection->reject_service_category = AVDTP_MEDIA_CODEC;
connection->error_code = error_code;
}
}
}
if (connection->error_code){
log_info("fire configuration parsing errors ");
connection->reject_signal_identifier = connection->acceptor_signaling_packet.signal_identifier;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
return;
}
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION;
// find or add sep
log_info("local seid %d, remote seid %d", connection->acceptor_local_seid, sep.seid);