mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-12 01:14:17 +00:00
a2dp source: cleanup api, add minimal docu, update example
This commit is contained in:
parent
fd58c90006
commit
88132161fe
@ -181,7 +181,7 @@ static void a2dp_demo_send_media_packet(void){
|
||||
int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length();
|
||||
int bytes_in_storage = media_tracker.sbc_storage_count;
|
||||
uint8_t num_frames = bytes_in_storage / num_bytes_in_frame;
|
||||
a2dp_source_stream_send_media_payload(media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0);
|
||||
a2dp_source_stream_send_media_payload(media_tracker.a2dp_cid, media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0);
|
||||
media_tracker.sbc_storage_count = 0;
|
||||
media_tracker.sbc_ready_to_send = 0;
|
||||
}
|
||||
@ -264,12 +264,12 @@ static void a2dp_demo_audio_timeout_handler(btstack_timer_source_t * timer){
|
||||
if ((context->sbc_storage_count + btstack_sbc_encoder_sbc_buffer_length()) > context->max_media_payload_size){
|
||||
// schedule sending
|
||||
context->sbc_ready_to_send = 1;
|
||||
a2dp_source_stream_endpoint_request_can_send_now(context->local_seid);
|
||||
a2dp_source_stream_endpoint_request_can_send_now(context->a2dp_cid, context->local_seid);
|
||||
}
|
||||
}
|
||||
|
||||
static void a2dp_demo_timer_start(a2dp_media_sending_context_t * context){
|
||||
context->max_media_payload_size = a2dp_max_media_payload_size(context->local_seid);
|
||||
context->max_media_payload_size = a2dp_max_media_payload_size(context->a2dp_cid, context->local_seid);
|
||||
context->sbc_storage_count = 0;
|
||||
context->sbc_ready_to_send = 0;
|
||||
context->streaming = 1;
|
||||
|
@ -77,11 +77,13 @@ void a2dp_sink_init(void);
|
||||
* @param codec_capabilities_len media codec capabilities length
|
||||
* @param codec_configuration default media codec configuration
|
||||
* @param codec_configuration_len media codec configuration length
|
||||
* @return status
|
||||
* @param out_local_seid Assigned stream endpoint ID used in further A2DP commands.
|
||||
*
|
||||
* @return status ERROR_CODE_SUCCESS if sucessful
|
||||
*/
|
||||
uint8_t a2dp_sink_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type,
|
||||
uint8_t * codec_capabilities, uint16_t codec_capabilities_len,
|
||||
uint8_t * codec_configuration, uint16_t codec_configuration_len, uint8_t * local_seid);
|
||||
uint8_t * codec_configuration, uint16_t codec_configuration_len, uint8_t * out_local_seid);
|
||||
|
||||
/**
|
||||
* @brief Register callback for the A2DP Sink client. It will receive following subevents of HCI_EVENT_A2DP_META HCI event type:
|
||||
@ -107,14 +109,14 @@ void a2dp_sink_register_media_handler(void (*callback)(uint8_t local_seid, uint8
|
||||
/**
|
||||
* @brief Establish stream.
|
||||
* @param remote
|
||||
* @param local_seid ID assigned to a local stream endpoint
|
||||
* @param a2dp_cid
|
||||
* @param local_seid ID of a local stream endpoint.
|
||||
* @param out_a2dp_cid Assigned A2DP channel identifyer used for furhter A2DP commands.
|
||||
*/
|
||||
uint8_t a2dp_sink_establish_stream(bd_addr_t remote, uint8_t local_seid, uint16_t * a2dp_cid);
|
||||
uint8_t a2dp_sink_establish_stream(bd_addr_t remote, uint8_t local_seid, uint16_t * out_a2dp_cid);
|
||||
|
||||
/**
|
||||
* @brief Release stream.
|
||||
* @param a2dp_cid
|
||||
* @brief Release stream and disconnect from remote.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
*/
|
||||
void a2dp_sink_disconnect(uint16_t a2dp_cid);
|
||||
|
||||
|
@ -440,36 +440,26 @@ avdtp_stream_endpoint_t * a2dp_source_create_stream_endpoint(avdtp_media_type_t
|
||||
return local_stream_endpoint;
|
||||
}
|
||||
|
||||
uint8_t a2dp_source_establish_stream(bd_addr_t remote_addr, uint8_t loc_seid, uint16_t * avdtp_cid){
|
||||
uint8_t a2dp_source_establish_stream(bd_addr_t remote_addr, uint8_t loc_seid, uint16_t * a2dp_cid){
|
||||
sc.local_stream_endpoint = avdtp_stream_endpoint_for_seid(loc_seid, &a2dp_source_context);
|
||||
if (!sc.local_stream_endpoint){
|
||||
log_error(" no local_stream_endpoint for seid %d", loc_seid);
|
||||
return AVDTP_SEID_DOES_NOT_EXIST;
|
||||
}
|
||||
memcpy(sc.remote_addr, remote_addr, 6);
|
||||
return avdtp_source_connect(remote_addr, avdtp_cid);
|
||||
return avdtp_source_connect(remote_addr, a2dp_cid);
|
||||
}
|
||||
|
||||
uint8_t a2dp_source_disconnect(uint16_t avdtp_cid){
|
||||
return avdtp_disconnect(avdtp_cid, &a2dp_source_context);
|
||||
uint8_t a2dp_source_disconnect(uint16_t a2dp_cid){
|
||||
return avdtp_disconnect(a2dp_cid, &a2dp_source_context);
|
||||
}
|
||||
|
||||
uint8_t a2dp_source_start_stream(uint16_t avdtp_cid, uint8_t local_seid){
|
||||
return avdtp_start_stream(avdtp_cid, local_seid, &a2dp_source_context);
|
||||
uint8_t a2dp_source_start_stream(uint16_t a2dp_cid, uint8_t local_seid){
|
||||
return avdtp_start_stream(a2dp_cid, local_seid, &a2dp_source_context);
|
||||
}
|
||||
|
||||
uint8_t a2dp_source_pause_stream(uint16_t avdtp_cid, uint8_t local_seid){
|
||||
return avdtp_suspend_stream(avdtp_cid, local_seid, &a2dp_source_context);
|
||||
}
|
||||
|
||||
uint8_t a2dp_source_stream_endpoint_ready(uint16_t avdtp_cid, uint8_t local_seid){
|
||||
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
|
||||
if (!stream_endpoint) {
|
||||
log_error("No stream_endpoint with seid %d", local_seid);
|
||||
return 0;
|
||||
}
|
||||
if (!stream_endpoint->connection || stream_endpoint->connection->avdtp_cid != avdtp_cid) return 0;
|
||||
return (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING);
|
||||
uint8_t a2dp_source_pause_stream(uint16_t a2dp_cid, uint8_t local_seid){
|
||||
return avdtp_suspend_stream(a2dp_cid, local_seid, &a2dp_source_context);
|
||||
}
|
||||
|
||||
static void a2dp_source_setup_media_header(uint8_t * media_packet, int size, int *offset, uint8_t marker, uint16_t sequence_number){
|
||||
@ -502,24 +492,33 @@ static void a2dp_source_setup_media_header(uint8_t * media_packet, int size, int
|
||||
*offset = pos;
|
||||
}
|
||||
|
||||
void a2dp_source_stream_endpoint_request_can_send_now(uint8_t local_seid){
|
||||
void a2dp_source_stream_endpoint_request_can_send_now(uint16_t a2dp_cid, uint8_t local_seid){
|
||||
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
|
||||
if (!stream_endpoint) {
|
||||
log_error("no stream_endpoint for seid %d", local_seid);
|
||||
log_error("A2DP source: no stream_endpoint with seid %d", local_seid);
|
||||
return;
|
||||
}
|
||||
if (a2dp_source_context.avdtp_cid != a2dp_cid){
|
||||
log_error("A2DP source: a2dp cid 0x%02x not known, expected 0x%02x", a2dp_cid, a2dp_source_context.avdtp_cid);
|
||||
return;
|
||||
}
|
||||
stream_endpoint->send_stream = 1;
|
||||
avdtp_request_can_send_now_initiator(stream_endpoint->connection, stream_endpoint->l2cap_media_cid);
|
||||
}
|
||||
|
||||
int a2dp_max_media_payload_size(uint8_t local_seid){
|
||||
int a2dp_max_media_payload_size(uint16_t a2dp_cid, uint8_t local_seid){
|
||||
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
|
||||
if (!stream_endpoint) {
|
||||
log_error("no stream_endpoint found for seid %d", local_seid);
|
||||
log_error("A2DP source: no stream_endpoint with seid %d", local_seid);
|
||||
return 0;
|
||||
}
|
||||
if (a2dp_source_context.avdtp_cid != a2dp_cid){
|
||||
log_error("A2DP source: a2dp cid 0x%02x not known, expected 0x%02x", a2dp_cid, a2dp_source_context.avdtp_cid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream_endpoint->l2cap_media_cid == 0){
|
||||
log_error("no media cid found for seid %d", local_seid);
|
||||
log_error("A2DP source: no media connection for seid %d", local_seid);
|
||||
return 0;
|
||||
}
|
||||
return l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid) - AVDTP_MEDIA_PAYLOAD_HEADER_SIZE;
|
||||
@ -538,17 +537,21 @@ static void a2dp_source_copy_media_payload(uint8_t * media_packet, int size, int
|
||||
*offset = pos;
|
||||
}
|
||||
|
||||
int a2dp_source_stream_send_media_payload(uint8_t local_seid, uint8_t * storage, int num_bytes_to_copy, uint8_t num_frames, uint8_t marker){
|
||||
int a2dp_source_stream_send_media_payload(uint16_t a2dp_cid, uint8_t local_seid, uint8_t * storage, int num_bytes_to_copy, uint8_t num_frames, uint8_t marker){
|
||||
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
|
||||
if (!stream_endpoint) {
|
||||
log_error("no stream_endpoint found for seid %d", local_seid);
|
||||
log_error("A2DP source: no stream_endpoint with seid %d", local_seid);
|
||||
return 0;
|
||||
}
|
||||
if (a2dp_source_context.avdtp_cid != a2dp_cid){
|
||||
log_error("A2DP source: a2dp cid 0x%02x not known, expected 0x%02x", a2dp_cid, a2dp_source_context.avdtp_cid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream_endpoint->l2cap_media_cid == 0){
|
||||
log_error("no media cid found for seid %d", local_seid);
|
||||
log_error("A2DP source: no media connection for seid %d", local_seid);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int size = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
|
||||
int offset = 0;
|
||||
|
@ -55,7 +55,7 @@ extern "C" {
|
||||
/* API_START */
|
||||
|
||||
/**
|
||||
* @brief A2DP Source service record.
|
||||
* @brief Create A2DP Source service record.
|
||||
* @param service
|
||||
* @param service_record_handle
|
||||
* @param supported_features 16-bit bitmap, see AVDTP_SOURCE_SF_* values in avdtp.h
|
||||
@ -64,51 +64,95 @@ extern "C" {
|
||||
*/
|
||||
void a2dp_source_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);
|
||||
|
||||
/**
|
||||
* @brief Initialize up A2DP Source device.
|
||||
*/
|
||||
void a2dp_source_init(void);
|
||||
|
||||
void a2dp_source_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
* @brief Create a stream endpoint of type SOURCE, and register media codec by specifying its capabilities and the default configuration.
|
||||
* @param media_type See avdtp_media_type_t values in avdtp.h (audio, video or multimedia).
|
||||
* @param media_codec_type See avdtp_media_codec_type_t values in avdtp.h
|
||||
* @param codec_capabilities Media codec capabilities as defined in A2DP spec, section 4 - Audio Codec Interoperability Requirements.
|
||||
* @param codec_capabilities_len Media codec capabilities length.
|
||||
* @param codec_configuration Default media codec configuration.
|
||||
* @param codec_configuration_len Media codec configuration length.
|
||||
* @param out_local_seid Assigned stream endpoint ID used in further A2DP commands.
|
||||
*
|
||||
* @return status ERROR_CODE_SUCCESS if sucessful.
|
||||
*/
|
||||
avdtp_stream_endpoint_t * a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type,
|
||||
uint8_t * codec_capabilities, uint16_t codec_capabilities_len,
|
||||
uint8_t * codec_configuration, uint16_t codec_configuration_len);
|
||||
|
||||
/**
|
||||
* @brief Open stream
|
||||
* @param bd_addr
|
||||
* @param local_seid
|
||||
* @param avdtp_cid
|
||||
* @brief Register callback for the A2DP Source client. It will receive following subevents of HCI_EVENT_A2DP_META HCI event type:
|
||||
* - A2DP_SUBEVENT_INCOMING_CONNECTION_ESTABLISHED: Received when signaling connection with a remote is established .
|
||||
* - A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED: Received when signaling connection with a remote is released .
|
||||
* - A2DP_SUBEVENT_STREAM_ESTABLISHED: Received when stream to a remote device is established.
|
||||
* - A2DP_SUBEVENT_STREAM_STARTED: Received when stream is started.
|
||||
* - A2DP_SUBEVENT_STREAM_SUSPENDED: Received when stream is paused.
|
||||
* - A2DP_SUBEVENT_STREAM_RELEASED: Received when stream is released.
|
||||
* - A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW: Indicates that the next media packet can be sent.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
uint8_t a2dp_source_establish_stream(bd_addr_t bd_addr, uint8_t local_seid, uint16_t * avdtp_cid);
|
||||
|
||||
void a2dp_source_register_packet_handler(btstack_packet_handler_t callback);
|
||||
|
||||
/**
|
||||
* @brief Start stream
|
||||
* @param avdtp_cid
|
||||
* @param seid
|
||||
* @brief Open stream.
|
||||
* @param remote
|
||||
* @param local_seid ID assigned to a local stream endpoint
|
||||
* @param out_a2dp_cid Assigned A2DP channel identifyer used for furhter A2DP commands.
|
||||
*/
|
||||
uint8_t a2dp_source_start_stream(uint16_t avdtp_cid, uint8_t local_seid);
|
||||
uint8_t a2dp_source_establish_stream(bd_addr_t remote, uint8_t local_seid, uint16_t * out_a2dp_cid);
|
||||
|
||||
/**
|
||||
* @brief Start stream
|
||||
* @param avdtp_cid
|
||||
* @param seid
|
||||
* @brief Start stream.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
* @param local_seid ID of a local stream endpoint.
|
||||
*/
|
||||
uint8_t a2dp_source_pause_stream(uint16_t avdtp_cid, uint8_t local_seid);
|
||||
uint8_t a2dp_source_start_stream(uint16_t a2dp_cid, uint8_t local_seid);
|
||||
|
||||
/**
|
||||
* @brief Disconnect from device with cid.
|
||||
* @param avdtp_cid
|
||||
* @brief Pause stream.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
* @param local_seid ID of a local stream endpoint.
|
||||
*/
|
||||
uint8_t a2dp_source_disconnect(uint16_t avdtp_cid);
|
||||
uint8_t a2dp_source_pause_stream(uint16_t a2dp_cid, uint8_t local_seid);
|
||||
|
||||
// size for media (does not include media header)
|
||||
int a2dp_max_media_payload_size(uint8_t local_seid);
|
||||
/**
|
||||
* @brief Release stream and disconnect from remote.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
*/
|
||||
uint8_t a2dp_source_disconnect(uint16_t a2dp_cid);
|
||||
|
||||
uint8_t a2dp_source_stream_endpoint_ready(uint16_t avdtp_cid, uint8_t local_seid);
|
||||
/**
|
||||
* @brief Request to send a media packet. Packet can be then sent on reception of A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW event.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
* @param local_seid ID of a local stream endpoint.
|
||||
*/
|
||||
void a2dp_source_stream_endpoint_request_can_send_now(uint16_t a2dp_cid, uint8_t local_seid);
|
||||
|
||||
void a2dp_source_stream_endpoint_request_can_send_now(uint8_t local_seid);
|
||||
/**
|
||||
* @brief Return maximal media payload size, does not include media header.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
* @param local_seid ID of a local stream endpoint.
|
||||
* @return max_media_payload_size_without_media_header
|
||||
*/
|
||||
int a2dp_max_media_payload_size(uint16_t a2dp_cid, uint8_t local_seid);
|
||||
|
||||
int a2dp_source_stream_send_media_payload(uint8_t local_seid, uint8_t * storage, int num_bytes_to_copy, uint8_t num_frames, uint8_t marker);
|
||||
/**
|
||||
* @brief Send media payload.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
* @param local_seid ID of a local stream endpoint.
|
||||
* @param storage
|
||||
* @param num_bytes_to_copy
|
||||
* @param num_frames
|
||||
* @param marker
|
||||
* @return max_media_payload_size_without_media_header
|
||||
*/
|
||||
int a2dp_source_stream_send_media_payload(uint16_t a2dp_cid, uint8_t local_seid, uint8_t * storage, int num_bytes_to_copy, uint8_t num_frames, uint8_t marker);
|
||||
|
||||
/* API_END */
|
||||
|
||||
|
@ -473,7 +473,7 @@ typedef struct {
|
||||
bd_addr_t remote_addr;
|
||||
|
||||
uint32_t fill_audio_ring_buffer_timeout_ms;
|
||||
uint32_t time_audio_data_sent; // ms
|
||||
uint32_t time_audio_data_sent; // msstream
|
||||
uint32_t acc_num_missed_samples;
|
||||
uint32_t samples_ready;
|
||||
btstack_timer_source_t fill_audio_ring_buffer_timer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user