From 1394c197027c0907932a814a786cc033870eb1c9 Mon Sep 17 00:00:00 2001 From: Pavlin Radoslavov Date: Sun, 2 Oct 2016 18:34:46 -0700 Subject: [PATCH] BTIF A2DP Source and Sink refactor and cleanup * Moved bta/av/bta_av_sbc.c to stack/a2dp/a2d_sbc_up_sample.c and renamed the corresponding bta_av_sbc_up_sample_* functions to a2d_sbc_up_sample_* Also, renamed bta_av_sbc_init_up_sample() to a2d_sbc_init_up_sample() * Moved A2DP SBC Encoder-related tasks, state and constants from btif_a2dp_source.cc to a2d_sbc_encoder.c * Introduced A2DP encoder callbacks interface tA2D_ENCODER_INTERFACE, and added A2D_GetEncoderInterface() to acccess the interface for a codec. * Updated a2d_sbc_encoder_init() to specify callbacks: - a2d_source_read_callback_t - a callback to read audio data for encoding - a2d_source_enqueue_callback_t - a callback to enqueue A2DP source packets for transmission * Removed BTIF_MEDIA_TRSCD_* - the encoding is always PCM * Removed conditionally defined constants and replaced them by local definitions: - BTIF_MEDIA_BITRATE_STEP -> A2D_SBC_BITRATE_STEP - BTIF_A2DP_DEFAULT_BITRATE -> A2D_SBC_DEFAULT_BITRATE - BTIF_A2DP_NON_EDR_MAX_RATE -> A2D_SBC_NON_EDR_MAX_RATE * Hard-coded the read data timeout period A2DP_DATA_READ_POLL_MS to 10ms * Merged the UNDERRUN read errors into the UNDERFLOW errors. * Removed the following statistics, because they are not very useful: - media_read_total_limited_frames - media_read_max_limited_frames - media_read_limited_count - media_read_total_expected_frames - media_read_max_expected_frames - media_read_expected_count * Updated the implementation of buffer_overruns_max_count to use the (new) counter tx_queue_max_dropped_messages instead of media_read_max_expected_frames * Replaced usage of LOG_DEBUG() in stack/a2d/ with LOG_VERBOSE(): the former is enabled by default on some of the builds. * Renamed: - btif_a2dp_sink_audio_focus_state_t -> btif_a2dp_sink_focus_state_t - btif_a2dp_sink_set_audio_focus_state_req() -> btif_a2dp_sink_set_focus_state_req() - tBTIF_A2DP_SINK_CB.RxSbcQ -> rx_audio_queue - btif_a2dp_source_start_aa_req() -> btif_a2dp_source_start_audio_req() - btif_a2dp_source_stop_aa_req() -> btif_a2dp_source_stop_audio_req() - btif_a2dp_source_aa_readbuf() -> btif_a2dp_source_audio_readbuf() - tBTIF_A2DP_SOURCE_CB.TxAaQ -> tx_audio_queue - BTIF_A2DP_SOURCE_MEDIA_TIMER_MS -> A2D_SBC_ENCODER_INTERVAL_MS - tA2D_AV_MEDIA_FEEDINGS -> tA2D_FEEDING_PARAMS - tBTIF_A2DP_SOURCE_INIT_AUDIO -> tA2D_ENCODER_INIT_PARAMS - tBTIF_A2DP_SOURCE_UPDATE_AUDIO -> tA2D_ENCODER_UPDATE_PARAMS - tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING -> tBTIF_A2DP_SOURCE_INIT_FEEDING Bug: 30958229 Test: TestTracker/65192 Change-Id: Iba0a9694bda3dba73f211f1bde25821497fa6a06 --- bta/Android.mk | 1 - bta/BUILD.gn | 1 - btif/co/bta_av_co.cc | 45 +- btif/include/btif_a2dp.h | 8 - btif/include/btif_a2dp_sink.h | 6 +- btif/include/btif_a2dp_source.h | 26 +- btif/include/btif_av_co.h | 18 +- btif/src/btif_a2dp_control.cc | 4 +- btif/src/btif_a2dp_sink.cc | 147 ++- btif/src/btif_a2dp_source.cc | 1320 ++++---------------- btif/src/btif_av.cc | 2 +- stack/Android.mk | 2 + stack/BUILD.gn | 2 + stack/a2dp/a2d_api.c | 80 +- stack/a2dp/a2d_sbc.c | 116 +- stack/a2dp/a2d_sbc_encoder.c | 880 +++++++++++++ .../bta_av_sbc.c => stack/a2dp/a2d_sbc_up_sample.c | 185 ++- stack/a2dp/a2d_vendor.c | 11 + stack/include/a2d_api.h | 102 +- stack/include/a2d_sbc.h | 18 +- stack/include/a2d_sbc_encoder.h | 72 ++ .../include/a2d_sbc_up_sample.h | 52 +- stack/include/a2d_vendor.h | 8 + stack/test/stack_a2d_test.cc | 24 +- 24 files changed, 1705 insertions(+), 1425 deletions(-) create mode 100644 stack/a2dp/a2d_sbc_encoder.c rename bta/av/bta_av_sbc.c => stack/a2dp/a2d_sbc_up_sample.c (65%) create mode 100644 stack/include/a2d_sbc_encoder.h rename bta/include/bta_av_sbc.h => stack/include/a2d_sbc_up_sample.h (79%) diff --git a/bta/Android.mk b/bta/Android.mk index 401073555..d55a9d3be 100644 --- a/bta/Android.mk +++ b/bta/Android.mk @@ -79,7 +79,6 @@ LOCAL_SRC_FILES:= \ ./av/bta_av_main.c \ ./av/bta_av_cfg.c \ ./av/bta_av_ssm.c \ - ./av/bta_av_sbc.c \ ./ar/bta_ar.c \ ./hl/bta_hl_act.c \ ./hl/bta_hl_api.c \ diff --git a/bta/BUILD.gn b/bta/BUILD.gn index bbbcec664..09fe9086e 100644 --- a/bta/BUILD.gn +++ b/bta/BUILD.gn @@ -33,7 +33,6 @@ static_library("bta") { "av/bta_av_cfg.c", "av/bta_av_ci.c", "av/bta_av_main.c", - "av/bta_av_sbc.c", "av/bta_av_ssm.c", "closure/bta_closure.cc", "dm/bta_dm_act.cc", diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc index 6b6a79ab9..30b322e7b 100644 --- a/btif/co/bta_av_co.cc +++ b/btif/co/bta_av_co.cc @@ -23,6 +23,7 @@ * ******************************************************************************/ +#include #include #include "a2d_api.h" #include "bt_target.h" @@ -765,7 +766,7 @@ void* bta_av_co_audio_src_data_path(const uint8_t *p_codec_info, APPL_TRACE_DEBUG("%s: codec: %s", __func__, A2D_CodecName(p_codec_info)); - p_buf = btif_a2dp_source_aa_readbuf(); + p_buf = btif_a2dp_source_audio_readbuf(); if (p_buf == NULL) return NULL; @@ -1069,11 +1070,11 @@ static void bta_av_co_audio_codec_reset(void) ** Returns true if successful, false otherwise ** *******************************************************************************/ -bool bta_av_co_audio_set_codec(const tA2D_AV_MEDIA_FEEDINGS *p_feeding) +bool bta_av_co_audio_set_codec(const tA2D_FEEDING_PARAMS *p_feeding_params) { uint8_t new_cfg[AVDT_CODEC_SIZE]; - if (!A2D_SetCodec(p_feeding, new_cfg)) + if (!A2D_SetCodec(p_feeding_params, new_cfg)) return false; /* The new config was correctly built */ @@ -1083,11 +1084,12 @@ bool bta_av_co_audio_set_codec(const tA2D_AV_MEDIA_FEEDINGS *p_feeding) return bta_av_co_audio_codec_supported(); } -void bta_av_co_audio_encoder_init(tBTIF_A2DP_SOURCE_INIT_AUDIO *msg) +void bta_av_co_audio_encoder_init(tA2D_ENCODER_INIT_PARAMS *p_init_params) { uint16_t min_mtu = 0xFFFF; APPL_TRACE_DEBUG("%s", __func__); + assert(p_init_params != nullptr); /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_lock(); @@ -1102,22 +1104,23 @@ void bta_av_co_audio_encoder_init(tBTIF_A2DP_SOURCE_INIT_AUDIO *msg) } const uint8_t *p_codec_info = bta_av_co_cb.codec_cfg; - msg->NumOfSubBands = A2D_GetNumberOfSubbands(p_codec_info); - msg->NumOfBlocks = A2D_GetNumberOfBlocks(p_codec_info); - msg->AllocationMethod = A2D_GetAllocationMethodCode(p_codec_info); - msg->ChannelMode = A2D_GetChannelModeCode(p_codec_info); - msg->SamplingFreq = A2D_GetSamplingFrequencyCode(p_codec_info); - msg->MtuSize = min_mtu; + p_init_params->NumOfSubBands = A2D_GetNumberOfSubbands(p_codec_info); + p_init_params->NumOfBlocks = A2D_GetNumberOfBlocks(p_codec_info); + p_init_params->AllocationMethod = A2D_GetAllocationMethodCode(p_codec_info); + p_init_params->ChannelMode = A2D_GetChannelModeCode(p_codec_info); + p_init_params->SamplingFreq = A2D_GetSamplingFrequencyCode(p_codec_info); + p_init_params->MtuSize = min_mtu; /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_unlock(); } -void bta_av_co_audio_encoder_update(tBTIF_A2DP_SOURCE_UPDATE_AUDIO *msg) +void bta_av_co_audio_encoder_update(tA2D_ENCODER_UPDATE_PARAMS *p_update_params) { uint16_t min_mtu = 0xFFFF; APPL_TRACE_DEBUG("%s", __func__); + assert(p_update_params != nullptr); /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_lock(); @@ -1186,9 +1189,23 @@ void bta_av_co_audio_encoder_update(tBTIF_A2DP_SOURCE_UPDATE_AUDIO *msg) return; } - msg->MinMtuSize = min_mtu; - msg->MinBitPool = min_bitpool; - msg->MaxBitPool = max_bitpool; + p_update_params->MinMtuSize = min_mtu; + p_update_params->MinBitPool = min_bitpool; + p_update_params->MaxBitPool = max_bitpool; +} + +const tA2D_ENCODER_INTERFACE *bta_av_co_get_encoder_interface(void) +{ + /* Protect access to bta_av_co_cb.codec_cfg */ + mutex_global_lock(); + + const tA2D_ENCODER_INTERFACE *encoder_interface = + A2D_GetEncoderInterface(bta_av_co_cb.codec_cfg); + + /* Protect access to bta_av_co_cb.codec_cfg */ + mutex_global_unlock(); + + return encoder_interface; } /******************************************************************************* diff --git a/btif/include/btif_a2dp.h b/btif/include/btif_a2dp.h index b15d5ca2c..bc87b3c7f 100644 --- a/btif/include/btif_a2dp.h +++ b/btif/include/btif_a2dp.h @@ -28,14 +28,6 @@ extern "C" { #endif -// -// |MAX_PCM_FRAME_NUM_PER_TICK| controls how many buffers we can hold in -// the A2DP buffer queues during temporary link congestion. -// -#ifndef MAX_PCM_FRAME_NUM_PER_TICK -#define MAX_PCM_FRAME_NUM_PER_TICK 14 -#endif - // Process 'idle' request from the BTIF state machine during initialization. void btif_a2dp_on_idle(void); diff --git a/btif/include/btif_a2dp_sink.h b/btif/include/btif_a2dp_sink.h index 0499a7684..95405ad15 100644 --- a/btif/include/btif_a2dp_sink.h +++ b/btif/include/btif_a2dp_sink.h @@ -40,7 +40,7 @@ extern "C" { typedef enum { BTIF_A2DP_SINK_FOCUS_NOT_GRANTED = 0, BTIF_A2DP_SINK_FOCUS_GRANTED = 1 -} btif_a2dp_sink_audio_focus_state_t; +} btif_a2dp_sink_focus_state_t; // Initialize and startup the A2DP Sink module. // This function should be called by the BTIF state machine prior to using the @@ -97,9 +97,9 @@ void btif_a2dp_sink_debug_dump(int fd); void btif_a2dp_sink_update_metrics(void); // Create a request to set the audio focus state for the audio track. -// |state| is the new state value - see |btif_a2dp_sink_audio_focus_state_t| +// |state| is the new state value - see |btif_a2dp_sink_focus_state_t| // for valid values. -void btif_a2dp_sink_set_audio_focus_state_req(btif_a2dp_sink_audio_focus_state_t state); +void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state); // Set the audio track gain for the audio track. // |gain| is the audio track gain value to use. diff --git a/btif/include/btif_a2dp_source.h b/btif/include/btif_a2dp_source.h index 1aa5b2dd7..28e8a4566 100644 --- a/btif/include/btif_a2dp_source.h +++ b/btif/include/btif_a2dp_source.h @@ -28,26 +28,6 @@ extern "C" { #endif -// A2DP Source media timer in milliseconds. -#define BTIF_A2DP_SOURCE_MEDIA_TIMER_MS 20 - -typedef struct { - BT_HDR hdr; - uint16_t SamplingFreq; /* 16k, 32k, 44.1k or 48k */ - uint8_t ChannelMode; /* mono, dual, stereo or joint stereo */ - uint8_t NumOfSubBands; /* 4 or 8 */ - uint8_t NumOfBlocks; /* 4, 8, 12 or 16 */ - uint8_t AllocationMethod; /* loudness or SNR */ - uint16_t MtuSize; /* peer mtu size */ -} tBTIF_A2DP_SOURCE_INIT_AUDIO; - -typedef struct { - BT_HDR hdr; - uint16_t MinMtuSize; /* Minimum peer mtu size */ - uint8_t MaxBitPool; /* Maximum peer bitpool */ - uint8_t MinBitPool; /* Minimum peer bitpool */ -} tBTIF_A2DP_SOURCE_UPDATE_AUDIO; - // Initialize and startup the A2DP Source module. // This function should be called by the BTIF state machine prior to using the // module. @@ -74,10 +54,10 @@ bool btif_a2dp_source_is_streaming(void); void btif_a2dp_source_setup_codec(void); // Process a request to start the A2DP audio encoding task. -void btif_a2dp_source_start_aa_req(void); +void btif_a2dp_source_start_audio_req(void); // Process a request to stop the A2DP audio encoding task. -void btif_a2dp_source_stop_aa_req(void); +void btif_a2dp_source_stop_audio_req(void); // Process 'idle' request from the BTIF state machine during initialization. void btif_a2dp_source_on_idle(void); @@ -102,7 +82,7 @@ void btif_a2dp_source_encoder_update(void); // Get the next A2DP buffer to send. // Returns the next A2DP buffer to send if available, otherwise NULL. -BT_HDR *btif_a2dp_source_aa_readbuf(void); +BT_HDR *btif_a2dp_source_audio_readbuf(void); // Dump debug-related information for the A2DP Source module. // |fd| is the file descriptor to use for writing the ASCII formatted diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h index 4ba03fd66..6ac4188db 100644 --- a/btif/include/btif_av_co.h +++ b/btif/include/btif_av_co.h @@ -46,15 +46,23 @@ extern "C" { ** Returns true if successful, false otherwise ** *******************************************************************************/ -bool bta_av_co_audio_set_codec(const tA2D_AV_MEDIA_FEEDINGS *p_feeding); +bool bta_av_co_audio_set_codec(const tA2D_FEEDING_PARAMS *p_feeding_params); // Prepares a message to initialize the encoder. The prepared message is -// stored in |msg|. -void bta_av_co_audio_encoder_init(tBTIF_A2DP_SOURCE_INIT_AUDIO *msg); +// stored in |p_init_params|. +// |p_init_params| cannot be null. +void bta_av_co_audio_encoder_init(tA2D_ENCODER_INIT_PARAMS *p_init_params); // Prepares a message to update the encoder. The prepared message is -// stored in |msg|. -void bta_av_co_audio_encoder_update(tBTIF_A2DP_SOURCE_UPDATE_AUDIO *msg); +// stored in |p_update_params|. +// |p_update_params| cannot be null. +void bta_av_co_audio_encoder_update(tA2D_ENCODER_UPDATE_PARAMS *p_update_params); + +// Gets the current A2DP encoder interface that can be used to encode and +// prepare A2DP packets for transmission - see |tA2D_ENCODER_INTERFACE|. +// Returns the A2DP encoder interface if the current codec is setup, +// otherwise NULL. +const tA2D_ENCODER_INTERFACE *bta_av_co_get_encoder_interface(void); /******************************************************************************* ** diff --git a/btif/src/btif_a2dp_control.cc b/btif/src/btif_a2dp_control.cc index 7e795cf99..5a2360121 100644 --- a/btif/src/btif_a2dp_control.cc +++ b/btif/src/btif_a2dp_control.cc @@ -33,7 +33,7 @@ #include "btif_hf.h" #include "uipc.h" -#define A2DP_DATA_READ_POLL_MS (BTIF_A2DP_SOURCE_MEDIA_TIMER_MS / 2) +#define A2DP_DATA_READ_POLL_MS 10 static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event); static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event); @@ -235,7 +235,7 @@ static void btif_a2dp_data_cb(UNUSED_ATTR tUIPC_CH_ID ch_id, tUIPC_EVENT event) if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) { /* Start the media task to encode the audio */ - btif_a2dp_source_start_aa_req(); + btif_a2dp_source_start_audio_req(); /* Make sure we update any changed encoder params */ btif_a2dp_source_encoder_update(); diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc index cc9c2e013..e3eaa2efc 100644 --- a/btif/src/btif_a2dp_sink.cc +++ b/btif/src/btif_a2dp_sink.cc @@ -56,20 +56,20 @@ enum { /* BTIF Media Sink command event definition */ enum { - BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE = 1, - BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK, - BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE, - BTIF_MEDIA_FLUSH_AA_RX + BTIF_MEDIA_SINK_DECODER_UPDATE = 1, + BTIF_MEDIA_SINK_CLEAR_TRACK, + BTIF_MEDIA_SINK_SET_FOCUS_STATE, + BTIF_MEDIA_SINK_AUDIO_RX_FLUSH }; typedef struct { BT_HDR hdr; uint8_t codec_info[AVDT_CODEC_SIZE]; -} tBTIF_MEDIA_SINK_CFG_UPDATE; +} tBTIF_MEDIA_SINK_DECODER_UPDATE; typedef struct { BT_HDR hdr; - btif_a2dp_sink_audio_focus_state_t focus_state; + btif_a2dp_sink_focus_state_t focus_state; } tBTIF_MEDIA_SINK_FOCUS_UPDATE; typedef struct { @@ -83,13 +83,13 @@ typedef struct { typedef struct { thread_t *worker_thread; fixed_queue_t *cmd_msg_queue; - fixed_queue_t *RxSbcQ; + fixed_queue_t *rx_audio_queue; bool rx_flush; /* discards any incoming data when true */ alarm_t *decode_alarm; uint8_t frames_to_process; uint32_t sample_rate; uint8_t channel_count; - btif_a2dp_sink_audio_focus_state_t rx_audio_focus_state; /* audio track state */ + btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */ void *audio_track; } tBTIF_A2DP_SINK_CB; @@ -104,28 +104,28 @@ static OI_INT16 btif_a2dp_sink_pcm_data[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX static void btif_a2dp_sink_startup_delayed(void *context); static void btif_a2dp_sink_shutdown_delayed(void *context); static void btif_a2dp_sink_command_ready(fixed_queue_t *queue, void *context); -static void btif_a2dp_sink_aa_handle_stop_decoding(void); +static void btif_a2dp_sink_audio_handle_stop_decoding(void); static void btif_decode_alarm_cb(void *context); -static void btif_a2dp_sink_aa_handle_start_decoding(void); +static void btif_a2dp_sink_audio_handle_start_decoding(void); static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void *context); -static void btif_a2dp_sink_aa_rx_flush_req(void); +static void btif_a2dp_sink_audio_rx_flush_req(void); /* Handle incoming media packets A2DP SINK streaming */ static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg); -static void btif_a2dp_sink_clear_track(void); -static void btif_a2dp_sink_aa_handle_decoder_reset( - tBTIF_MEDIA_SINK_CFG_UPDATE *p_buf); -static void btif_a2dp_sink_aa_handle_clear_track(void); -static void btif_a2dp_sink_set_audio_focus_state(btif_a2dp_sink_audio_focus_state_t state); -static void btif_a2dp_sink_aa_rx_flush(void); +static void btif_a2dp_sink_decoder_update_event( + tBTIF_MEDIA_SINK_DECODER_UPDATE *p_buf); +static void btif_a2dp_sink_clear_track_event(void); +static void btif_a2dp_sink_set_focus_state_event(btif_a2dp_sink_focus_state_t state); +static void btif_a2dp_sink_audio_rx_flush_event(void); +static void btif_a2dp_sink_clear_track_event_req(void); UNUSED_ATTR static const char *dump_media_event(uint16_t event) { switch (event) { - CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE) - CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK) - CASE_RETURN_STR(BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE) - CASE_RETURN_STR(BTIF_MEDIA_FLUSH_AA_RX) + CASE_RETURN_STR(BTIF_MEDIA_SINK_DECODER_UPDATE) + CASE_RETURN_STR(BTIF_MEDIA_SINK_CLEAR_TRACK) + CASE_RETURN_STR(BTIF_MEDIA_SINK_SET_FOCUS_STATE) + CASE_RETURN_STR(BTIF_MEDIA_SINK_AUDIO_RX_FLUSH) default: break; } @@ -152,9 +152,9 @@ bool btif_a2dp_sink_startup(void) return false; } - btif_a2dp_sink_cb.rx_audio_focus_state = BTIF_A2DP_SINK_FOCUS_NOT_GRANTED; + btif_a2dp_sink_cb.rx_focus_state = BTIF_A2DP_SINK_FOCUS_NOT_GRANTED; btif_a2dp_sink_cb.audio_track = NULL; - btif_a2dp_sink_cb.RxSbcQ = fixed_queue_new(SIZE_MAX); + btif_a2dp_sink_cb.rx_audio_queue = fixed_queue_new(SIZE_MAX); btif_a2dp_sink_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX); fixed_queue_register_dequeue(btif_a2dp_sink_cb.cmd_msg_queue, @@ -203,8 +203,8 @@ void btif_a2dp_sink_shutdown(void) static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void *context) { - fixed_queue_free(btif_a2dp_sink_cb.RxSbcQ, NULL); - btif_a2dp_sink_cb.RxSbcQ = NULL; + fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, NULL); + btif_a2dp_sink_cb.rx_audio_queue = NULL; btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF; } @@ -228,21 +228,21 @@ static void btif_a2dp_sink_command_ready(fixed_queue_t *queue, dump_media_event(p_msg->event)); switch (p_msg->event) { - case BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE: - btif_a2dp_sink_aa_handle_decoder_reset( - (tBTIF_MEDIA_SINK_CFG_UPDATE *)p_msg); + case BTIF_MEDIA_SINK_DECODER_UPDATE: + btif_a2dp_sink_decoder_update_event( + (tBTIF_MEDIA_SINK_DECODER_UPDATE *)p_msg); break; - case BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK: - btif_a2dp_sink_aa_handle_clear_track(); + case BTIF_MEDIA_SINK_CLEAR_TRACK: + btif_a2dp_sink_clear_track_event(); break; - case BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE: { - btif_a2dp_sink_audio_focus_state_t state = + case BTIF_MEDIA_SINK_SET_FOCUS_STATE: { + btif_a2dp_sink_focus_state_t state = ((tBTIF_MEDIA_SINK_FOCUS_UPDATE *)p_msg)->focus_state; - btif_a2dp_sink_set_audio_focus_state(state); + btif_a2dp_sink_set_focus_state_event(state); break; } - case BTIF_MEDIA_FLUSH_AA_RX: - btif_a2dp_sink_aa_rx_flush(); + case BTIF_MEDIA_SINK_AUDIO_RX_FLUSH: + btif_a2dp_sink_audio_rx_flush_event(); break; default: APPL_TRACE_ERROR("ERROR in %s unknown event %d", @@ -257,15 +257,15 @@ static void btif_a2dp_sink_command_ready(fixed_queue_t *queue, void btif_a2dp_sink_update_decoder(const uint8_t *p_codec_info) { - tBTIF_MEDIA_SINK_CFG_UPDATE *p_buf = - reinterpret_cast(osi_malloc(sizeof(tBTIF_MEDIA_SINK_CFG_UPDATE))); + tBTIF_MEDIA_SINK_DECODER_UPDATE *p_buf = + reinterpret_cast(osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE))); APPL_TRACE_EVENT("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, p_codec_info[1], p_codec_info[2], p_codec_info[3], p_codec_info[4], p_codec_info[5], p_codec_info[6]); memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE); - p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_CFG_UPDATE; + p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE; fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf); } @@ -275,8 +275,8 @@ void btif_a2dp_sink_on_idle(void) if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return; - btif_a2dp_sink_aa_handle_stop_decoding(); - btif_a2dp_sink_clear_track(); + btif_a2dp_sink_audio_handle_stop_decoding(); + btif_a2dp_sink_clear_track_event_req(); APPL_TRACE_DEBUG("Stopped BT track"); } @@ -286,7 +286,7 @@ void btif_a2dp_sink_on_stopped(UNUSED_ATTR tBTA_AV_SUSPEND *p_av_suspend) if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return; - btif_a2dp_sink_aa_handle_stop_decoding(); + btif_a2dp_sink_audio_handle_stop_decoding(); } void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND *p_av_suspend) @@ -294,12 +294,12 @@ void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND *p_av_suspend) if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return; - btif_a2dp_sink_aa_handle_stop_decoding(); + btif_a2dp_sink_audio_handle_stop_decoding(); } -static void btif_a2dp_sink_aa_handle_stop_decoding(void) { +static void btif_a2dp_sink_audio_handle_stop_decoding(void) { btif_a2dp_sink_cb.rx_flush = true; - btif_a2dp_sink_aa_rx_flush_req(); + btif_a2dp_sink_audio_rx_flush_req(); alarm_free(btif_a2dp_sink_cb.decode_alarm); btif_a2dp_sink_cb.decode_alarm = NULL; @@ -313,7 +313,7 @@ static void btif_decode_alarm_cb(UNUSED_ATTR void *context) { } } -static void btif_a2dp_sink_aa_handle_clear_track(void) +static void btif_a2dp_sink_clear_track_event(void) { APPL_TRACE_DEBUG("%s", __func__); @@ -322,7 +322,7 @@ static void btif_a2dp_sink_aa_handle_clear_track(void) btif_a2dp_sink_cb.audio_track = NULL; } -static void btif_a2dp_sink_aa_handle_start_decoding(void) { +static void btif_a2dp_sink_audio_handle_start_decoding(void) { if (btif_a2dp_sink_cb.decode_alarm != NULL) return; // Already started decoding @@ -385,21 +385,20 @@ static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void *context) int num_sbc_frames; int num_frames_to_process; - if (fixed_queue_is_empty(btif_a2dp_sink_cb.RxSbcQ)) { + if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) { APPL_TRACE_DEBUG("%s: empty queue", __func__); return; } /* Don't do anything in case of focus not granted */ - if (btif_a2dp_sink_cb.rx_audio_focus_state == - BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) { + if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) { APPL_TRACE_DEBUG("%s: skipping frames since focus is not present", __func__); return; } /* Play only in BTIF_A2DP_SINK_FOCUS_GRANTED case */ if (btif_a2dp_sink_cb.rx_flush) { - fixed_queue_flush(btif_a2dp_sink_cb.RxSbcQ, osi_free); + fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free); return; } @@ -407,7 +406,7 @@ static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void *context) APPL_TRACE_DEBUG(" Process Frames + "); do { - p_msg = (tBT_SBC_HDR *)fixed_queue_try_peek_first(btif_a2dp_sink_cb.RxSbcQ); + p_msg = (tBT_SBC_HDR *)fixed_queue_try_peek_first(btif_a2dp_sink_cb.rx_audio_queue); if (p_msg == NULL) return; /* Number of frames in queue packets */ @@ -416,7 +415,7 @@ static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void *context) APPL_TRACE_DEBUG("Remaining frames to process in tick %d", num_frames_to_process); APPL_TRACE_DEBUG("Number of packets in queue %d", - fixed_queue_length(btif_a2dp_sink_cb.RxSbcQ)); + fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue)); if (num_sbc_frames > num_frames_to_process) { /* Queue packet has more frames */ @@ -429,7 +428,7 @@ static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void *context) } /* Queue packet has less frames */ btif_a2dp_sink_handle_inc_media(p_msg); - p_msg = (tBT_SBC_HDR *)fixed_queue_try_dequeue(btif_a2dp_sink_cb.RxSbcQ); + p_msg = (tBT_SBC_HDR *)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue); if (p_msg == NULL) { APPL_TRACE_ERROR("Insufficient data in queue"); break; @@ -449,16 +448,16 @@ void btif_a2dp_sink_set_rx_flush(bool enable) btif_a2dp_sink_cb.rx_flush = enable; } -static void btif_a2dp_sink_aa_rx_flush(void) +static void btif_a2dp_sink_audio_rx_flush_event(void) { /* Flush all received SBC buffers (encoded) */ APPL_TRACE_DEBUG("%s", __func__); - fixed_queue_flush(btif_a2dp_sink_cb.RxSbcQ, osi_free); + fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free); } -static void btif_a2dp_sink_aa_handle_decoder_reset( - tBTIF_MEDIA_SINK_CFG_UPDATE *p_buf) +static void btif_a2dp_sink_decoder_update_event( + tBTIF_MEDIA_SINK_DECODER_UPDATE *p_buf) { OI_STATUS status; @@ -516,12 +515,12 @@ static void btif_a2dp_sink_aa_handle_decoder_reset( uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR *p_pkt) { if (btif_a2dp_sink_cb.rx_flush) /* Flush enabled, do not enqueue */ - return fixed_queue_length(btif_a2dp_sink_cb.RxSbcQ); + return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue); - if (fixed_queue_length(btif_a2dp_sink_cb.RxSbcQ) == + if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) == MAX_INPUT_A2DP_FRAME_QUEUE_SZ) { - uint8_t ret = fixed_queue_length(btif_a2dp_sink_cb.RxSbcQ); - osi_free(fixed_queue_try_dequeue(btif_a2dp_sink_cb.RxSbcQ)); + uint8_t ret = fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue); + osi_free(fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue)); return ret; } @@ -541,25 +540,25 @@ uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR *p_pkt) BTIF_TRACE_VERBOSE("%s: frames to process %d, len %d", __func__, p_msg->num_frames_to_be_processed, p_msg->len); - fixed_queue_enqueue(btif_a2dp_sink_cb.RxSbcQ, p_msg); - if (fixed_queue_length(btif_a2dp_sink_cb.RxSbcQ) == + fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg); + if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) == MAX_A2DP_DELAYED_START_FRAME_COUNT) { BTIF_TRACE_DEBUG("%s: Initiate decoding", __func__); - btif_a2dp_sink_aa_handle_start_decoding(); + btif_a2dp_sink_audio_handle_start_decoding(); } - return fixed_queue_length(btif_a2dp_sink_cb.RxSbcQ); + return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue); } -void btif_a2dp_sink_aa_rx_flush_req(void) +void btif_a2dp_sink_audio_rx_flush_req(void) { - if (fixed_queue_is_empty(btif_a2dp_sink_cb.RxSbcQ)) { + if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) { /* Queue is already empty */ return; } BT_HDR *p_buf = reinterpret_cast(osi_malloc(sizeof(BT_HDR))); - p_buf->event = BTIF_MEDIA_FLUSH_AA_RX; + p_buf->event = BTIF_MEDIA_SINK_AUDIO_RX_FLUSH; fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf); } @@ -573,7 +572,7 @@ void btif_a2dp_sink_update_metrics(void) // Nothing to do } -void btif_a2dp_sink_set_audio_focus_state_req(btif_a2dp_sink_audio_focus_state_t state) +void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state) { tBTIF_MEDIA_SINK_FOCUS_UPDATE *p_buf = reinterpret_cast(osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE))); @@ -581,16 +580,16 @@ void btif_a2dp_sink_set_audio_focus_state_req(btif_a2dp_sink_audio_focus_state_t APPL_TRACE_EVENT("%s", __func__); p_buf->focus_state = state; - p_buf->hdr.event = BTIF_MEDIA_AUDIO_SINK_SET_FOCUS_STATE; + p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE; fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf); } -static void btif_a2dp_sink_set_audio_focus_state(btif_a2dp_sink_audio_focus_state_t state) +static void btif_a2dp_sink_set_focus_state_event(btif_a2dp_sink_focus_state_t state) { if (!btif_av_is_connected()) return; APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state); - btif_a2dp_sink_cb.rx_audio_focus_state = state; + btif_a2dp_sink_cb.rx_focus_state = state; } void btif_a2dp_sink_set_audio_track_gain(float gain) @@ -599,10 +598,10 @@ void btif_a2dp_sink_set_audio_track_gain(float gain) BtifAvrcpSetAudioTrackGain(btif_a2dp_sink_cb.audio_track, gain); } -static void btif_a2dp_sink_clear_track(void) +static void btif_a2dp_sink_clear_track_event_req(void) { BT_HDR *p_buf = reinterpret_cast(osi_malloc(sizeof(BT_HDR))); - p_buf->event = BTIF_MEDIA_AUDIO_SINK_CLEAR_TRACK; + p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK; fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf); } diff --git a/btif/src/btif_a2dp_source.cc b/btif/src/btif_a2dp_source.cc index b51642ad3..4cdfd4c46 100644 --- a/btif/src/btif_a2dp_source.cc +++ b/btif/src/btif_a2dp_source.cc @@ -25,7 +25,6 @@ #include "audio_a2dp_hw.h" #include "bt_common.h" #include "bta_av_ci.h" -#include "bta_av_sbc.h" #include "btif_a2dp.h" #include "btif_a2dp_control.h" #include "btif_a2dp_source.h" @@ -40,25 +39,9 @@ #include "osi/include/osi.h" #include "osi/include/thread.h" #include "osi/include/time.h" -#include "sbc_encoder.h" -#include "stack/include/a2d_sbc.h" #include "uipc.h" -/* offset */ -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -#define BTIF_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2D_SBC_MPL_HDR_LEN + 1) -#else -#define BTIF_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2D_SBC_MPL_HDR_LEN) -#endif - -/* - * 2DH5 payload size of: - * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header) - */ -#define MAX_2MBPS_AVDTP_MTU 663 -#define MAX_PCM_ITER_NUM_PER_TICK 3 - /** * The typical runlevel of the tx queue size is ~1 buffer * but due to link flow control or thread preemption in lower @@ -66,41 +49,6 @@ */ #define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (MAX_PCM_FRAME_NUM_PER_TICK * 2) -/* Define the bitrate step when trying to match bitpool value */ -#ifndef BTIF_MEDIA_BITRATE_STEP -#define BTIF_MEDIA_BITRATE_STEP 5 -#endif - -#ifndef BTIF_A2DP_DEFAULT_BITRATE -/* High quality quality setting @ 44.1 khz */ -#define BTIF_A2DP_DEFAULT_BITRATE 328 -#endif - -#ifndef BTIF_A2DP_NON_EDR_MAX_RATE -#define BTIF_A2DP_NON_EDR_MAX_RATE 229 -#endif - -#if (BTA_AV_CO_CP_SCMS_T == TRUE) -/* A2DP header will contain a CP header of size 1 */ -#define A2DP_HDR_SIZE 2 -#else -#define A2DP_HDR_SIZE 1 -#endif -#define MAX_SBC_HQ_FRAME_SIZE_44_1 119 -#define MAX_SBC_HQ_FRAME_SIZE_48 115 - -/* Readability constants */ -#define SBC_FRAME_HEADER_SIZE_BYTES 4 // A2DP Spec v1.3, 12.4, Table 12.12 -#define SBC_SCALE_FACTOR_BITS 4 // A2DP Spec v1.3, 12.4, Table 12.13 - - -/* Transcoding definition for TxTranscoding */ -#define BTIF_MEDIA_TRSCD_OFF 0 -#define BTIF_MEDIA_TRSCD_PCM_2_SBC 1 /* Tx */ - -/* Buffer pool */ -#define BTIF_MEDIA_AA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE - enum { BTIF_A2DP_SOURCE_STATE_OFF, BTIF_A2DP_SOURCE_STATE_STARTING_UP, @@ -110,19 +58,31 @@ enum { /* BTIF Media Source event definition */ enum { - BTIF_MEDIA_START_AA_TX = 1, - BTIF_MEDIA_STOP_AA_TX, - BTIF_MEDIA_SBC_ENC_INIT, - BTIF_MEDIA_SBC_ENC_UPDATE, - BTIF_MEDIA_AUDIO_FEEDING_INIT, - BTIF_MEDIA_FLUSH_AA_TX + BTIF_MEDIA_AUDIO_TX_START = 1, + BTIF_MEDIA_AUDIO_TX_STOP, + BTIF_MEDIA_AUDIO_TX_FLUSH, + BTIF_MEDIA_SOURCE_ENCODER_INIT, + BTIF_MEDIA_SOURCE_ENCODER_UPDATE, + BTIF_MEDIA_AUDIO_FEEDING_INIT }; -/* tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING msg structure */ +/* tBTIF_A2DP_AUDIO_FEEDING_INIT msg structure */ +typedef struct { + BT_HDR hdr; + tA2D_FEEDING_PARAMS feeding_params; +} tBTIF_A2DP_AUDIO_FEEDING_INIT; + +/* tBTIF_A2DP_SOURCE_ENCODER_INIT msg structure */ +typedef struct { + BT_HDR hdr; + tA2D_ENCODER_INIT_PARAMS init_params; +} tBTIF_A2DP_SOURCE_ENCODER_INIT; + +/* tBTIF_A2DP_SOURCE_ENCODER_UPDATE msg structure */ typedef struct { BT_HDR hdr; - tA2D_AV_MEDIA_FEEDINGS feeding; -} tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING; + tA2D_ENCODER_UPDATE_PARAMS update_params; +} tBTIF_A2DP_SOURCE_ENCODER_UPDATE; typedef struct { // Counter for total updates @@ -175,101 +135,65 @@ typedef struct { uint64_t tx_queue_last_flushed_us; size_t tx_queue_total_dropped_messages; + size_t tx_queue_max_dropped_messages; size_t tx_queue_dropouts; uint64_t tx_queue_last_dropouts_us; size_t media_read_total_underflow_bytes; size_t media_read_total_underflow_count; uint64_t media_read_last_underflow_us; - - size_t media_read_total_underrun_bytes; - size_t media_read_total_underrun_count; - uint64_t media_read_last_underrun_us; - - size_t media_read_total_expected_frames; - size_t media_read_max_expected_frames; - size_t media_read_expected_count; - - size_t media_read_total_limited_frames; - size_t media_read_max_limited_frames; - size_t media_read_limited_count; } btif_media_stats_t; typedef struct { - uint32_t aa_frame_counter; - int32_t aa_feed_counter; - int32_t aa_feed_residue; - uint32_t counter; - uint32_t bytes_per_tick; /* pcm bytes read each media task tick */ -} tBTIF_AV_MEDIA_FEEDINGS_STATE; - -typedef struct { thread_t *worker_thread; fixed_queue_t *cmd_msg_queue; - fixed_queue_t *TxAaQ; - uint32_t timestamp; /* Timestamp for the A2DP frames */ - uint8_t TxTranscoding; - uint16_t TxAaMtuSize; - uint8_t tx_sbc_frames; + fixed_queue_t *tx_audio_queue; bool tx_flush; /* Discards any outgoing data when true */ - tA2D_AV_MEDIA_FEEDINGS media_feeding; - tBTIF_AV_MEDIA_FEEDINGS_STATE media_feeding_state; bool is_streaming; alarm_t *media_alarm; + const tA2D_ENCODER_INTERFACE *encoder_interface; + period_ms_t encoder_interval_ms; /* Local copy of the encoder interval */ btif_media_stats_t stats; - - SBC_ENC_PARAMS sbc_encoder_params; } tBTIF_A2DP_SOURCE_CB; static tBTIF_A2DP_SOURCE_CB btif_a2dp_source_cb; static int btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF; -static uint64_t last_frame_us = 0; static void btif_a2dp_source_command_ready(fixed_queue_t *queue, void *context); static void btif_a2dp_source_startup_delayed(void *context); static void btif_a2dp_source_shutdown_delayed(void *context); -static void btif_a2dp_source_aa_start_tx(void); -static void btif_a2dp_source_aa_stop_tx(void); -static void btif_a2dp_source_enc_init(BT_HDR *p_msg); -static void btif_a2dp_source_enc_update(BT_HDR *p_msg); -static void btif_a2dp_source_audio_feeding_init(BT_HDR *p_msg); -static void btif_a2dp_source_aa_tx_flush(BT_HDR *p_msg); +static void btif_a2dp_source_audio_tx_start_event(void); +static void btif_a2dp_source_audio_tx_stop_event(void); +static void btif_a2dp_source_audio_tx_flush_event(BT_HDR *p_msg); +static void btif_a2dp_source_encoder_init_event(BT_HDR *p_msg); +static void btif_a2dp_source_encoder_update_event(BT_HDR *p_msg); +static void btif_a2dp_source_audio_feeding_init_event(BT_HDR *p_msg); static void btif_a2dp_source_encoder_init(void); -static void btif_a2dp_source_feeding_init_req(tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *p_msg); -static void btif_a2dp_source_enc_init_req(tBTIF_A2DP_SOURCE_INIT_AUDIO *p_msg); -static void btif_a2dp_source_enc_update_req(tBTIF_A2DP_SOURCE_UPDATE_AUDIO *p_msg); -static uint16_t btif_a2dp_source_get_sbc_rate(void); -static uint8_t calculate_max_frames_per_packet(void); -static bool btif_a2dp_source_aa_tx_flush_req(void); -static void btif_a2dp_source_pcm2sbc_init(tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *p_feeding); +static void btif_a2dp_source_feeding_init_req(tBTIF_A2DP_AUDIO_FEEDING_INIT *p_msg); +static void btif_a2dp_source_encoder_init_req(tBTIF_A2DP_SOURCE_ENCODER_INIT *p_msg); +static void btif_a2dp_source_encoder_update_req(tBTIF_A2DP_SOURCE_ENCODER_UPDATE *p_msg); +static bool btif_a2dp_source_audio_tx_flush_req(void); static void btif_a2dp_source_alarm_cb(void *context); -static void btif_a2dp_source_aa_handle_timer(void *context); +static void btif_a2dp_source_audio_handle_timer(void *context); +static uint32_t btif_a2dp_source_read_callback(uint8_t *p_buf, uint32_t len); +static bool btif_a2dp_source_enqueue_callback(BT_HDR *p_buf, size_t frames_n); static void log_tstamps_us(const char *comment, uint64_t timestamp_us); -static void btif_a2dp_source_send_aa_frame(uint64_t timestamp_us); -static void btif_get_num_aa_frame_iteration(uint8_t *num_of_iterations, - uint8_t *num_of_frames); -static void btif_a2dp_source_aa_prep_2_send(uint8_t nb_frame, - uint64_t timestamp_us); -static void btm_read_rssi_cb(void *data); -static void btif_a2dp_source_aa_prep_sbc_2_send(uint8_t nb_frame, - uint64_t timestamp_us); -static bool btif_a2dp_source_aa_read_feeding(void); static void update_scheduling_stats(scheduling_stats_t *stats, uint64_t now_us, uint64_t expected_delta); -static uint32_t get_frame_length(void); +static void btm_read_rssi_cb(void *data); UNUSED_ATTR static const char *dump_media_event(uint16_t event) { switch (event) { - CASE_RETURN_STR(BTIF_MEDIA_START_AA_TX) - CASE_RETURN_STR(BTIF_MEDIA_STOP_AA_TX) - CASE_RETURN_STR(BTIF_MEDIA_SBC_ENC_INIT) - CASE_RETURN_STR(BTIF_MEDIA_SBC_ENC_UPDATE) + CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_START) + CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_STOP) + CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_FLUSH) + CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_INIT) + CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_UPDATE) CASE_RETURN_STR(BTIF_MEDIA_AUDIO_FEEDING_INIT) - CASE_RETURN_STR(BTIF_MEDIA_FLUSH_AA_TX) default: break; } @@ -298,7 +222,7 @@ bool btif_a2dp_source_startup(void) } btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us(); - btif_a2dp_source_cb.TxAaQ = fixed_queue_new(SIZE_MAX); + btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX); btif_a2dp_source_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX); fixed_queue_register_dequeue(btif_a2dp_source_cb.cmd_msg_queue, @@ -345,8 +269,8 @@ void btif_a2dp_source_shutdown(void) static void btif_a2dp_source_shutdown_delayed(UNUSED_ATTR void *context) { btif_a2dp_control_cleanup(); - fixed_queue_free(btif_a2dp_source_cb.TxAaQ, NULL); - btif_a2dp_source_cb.TxAaQ = NULL; + fixed_queue_free(btif_a2dp_source_cb.tx_audio_queue, NULL); + btif_a2dp_source_cb.tx_audio_queue = NULL; btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF; } @@ -375,23 +299,23 @@ static void btif_a2dp_source_command_ready(fixed_queue_t *queue, dump_media_event(p_msg->event)); switch (p_msg->event) { - case BTIF_MEDIA_START_AA_TX: - btif_a2dp_source_aa_start_tx(); + case BTIF_MEDIA_AUDIO_TX_START: + btif_a2dp_source_audio_tx_start_event(); break; - case BTIF_MEDIA_STOP_AA_TX: - btif_a2dp_source_aa_stop_tx(); + case BTIF_MEDIA_AUDIO_TX_STOP: + btif_a2dp_source_audio_tx_stop_event(); break; - case BTIF_MEDIA_SBC_ENC_INIT: - btif_a2dp_source_enc_init(p_msg); + case BTIF_MEDIA_AUDIO_TX_FLUSH: + btif_a2dp_source_audio_tx_flush_event(p_msg); break; - case BTIF_MEDIA_SBC_ENC_UPDATE: - btif_a2dp_source_enc_update(p_msg); + case BTIF_MEDIA_SOURCE_ENCODER_INIT: + btif_a2dp_source_encoder_init_event(p_msg); break; - case BTIF_MEDIA_AUDIO_FEEDING_INIT: - btif_a2dp_source_audio_feeding_init(p_msg); + case BTIF_MEDIA_SOURCE_ENCODER_UPDATE: + btif_a2dp_source_encoder_update_event(p_msg); break; - case BTIF_MEDIA_FLUSH_AA_TX: - btif_a2dp_source_aa_tx_flush(p_msg); + case BTIF_MEDIA_AUDIO_FEEDING_INIT: + btif_a2dp_source_audio_feeding_init_event(p_msg); break; default: APPL_TRACE_ERROR("ERROR in %s unknown event %d", @@ -406,25 +330,25 @@ static void btif_a2dp_source_command_ready(fixed_queue_t *queue, void btif_a2dp_source_setup_codec(void) { - tA2D_AV_MEDIA_FEEDINGS media_feeding; + tA2D_FEEDING_PARAMS feeding_params; APPL_TRACE_EVENT("## A2DP SOURCE SETUP CODEC ##"); mutex_global_lock(); /* for now hardcode 44.1 khz 16 bit stereo PCM format */ - media_feeding.sampling_freq = BTIF_A2DP_SRC_SAMPLING_RATE; - media_feeding.bit_per_sample = BTIF_A2DP_SRC_BIT_DEPTH; - media_feeding.num_channel = BTIF_A2DP_SRC_NUM_CHANNELS; + feeding_params.sampling_freq = BTIF_A2DP_SRC_SAMPLING_RATE; + feeding_params.bit_per_sample = BTIF_A2DP_SRC_BIT_DEPTH; + feeding_params.num_channel = BTIF_A2DP_SRC_NUM_CHANNELS; - if (bta_av_co_audio_set_codec(&media_feeding)) { - tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING mfeed; + if (bta_av_co_audio_set_codec(&feeding_params)) { + tBTIF_A2DP_AUDIO_FEEDING_INIT mfeed; /* Init the encoding task */ btif_a2dp_source_encoder_init(); /* Build the media task configuration */ - mfeed.feeding = media_feeding; + mfeed.feeding_params = feeding_params; /* Send message to Media task to configure transcoding */ btif_a2dp_source_feeding_init_req(&mfeed); } @@ -432,26 +356,26 @@ void btif_a2dp_source_setup_codec(void) mutex_global_unlock(); } -void btif_a2dp_source_start_aa_req(void) +void btif_a2dp_source_start_audio_req(void) { BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR)); - p_buf->event = BTIF_MEDIA_START_AA_TX; + p_buf->event = BTIF_MEDIA_AUDIO_TX_START; fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf); } -void btif_a2dp_source_stop_aa_req(void) +void btif_a2dp_source_stop_audio_req(void) { BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR)); - p_buf->event = BTIF_MEDIA_STOP_AA_TX; + p_buf->event = BTIF_MEDIA_AUDIO_TX_STOP; /* * Explicitly check whether btif_a2dp_source_cb.cmd_msg_queue is not NULL * to avoid a race condition during shutdown of the Bluetooth stack. * This race condition is triggered when A2DP audio is streaming on * shutdown: - * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_stop_aa_req()" + * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_stop_audio_req()" * is called to stop the particular audio stream, and this happens right * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()" * processing during the shutdown of the Bluetooth stack. @@ -462,7 +386,7 @@ void btif_a2dp_source_stop_aa_req(void) static void btif_a2dp_source_encoder_init(void) { - tBTIF_A2DP_SOURCE_INIT_AUDIO msg; + tBTIF_A2DP_SOURCE_ENCODER_INIT msg; // Check to make sure the platform has 8 bits/byte since // we're using that in frame size calculations now. @@ -470,242 +394,83 @@ static void btif_a2dp_source_encoder_init(void) APPL_TRACE_DEBUG("%s", __func__); - bta_av_co_audio_encoder_init(&msg); - btif_a2dp_source_enc_init_req(&msg); + bta_av_co_audio_encoder_init(&msg.init_params); + btif_a2dp_source_encoder_init_req(&msg); } void btif_a2dp_source_encoder_update(void) { - tBTIF_A2DP_SOURCE_UPDATE_AUDIO msg; + tBTIF_A2DP_SOURCE_ENCODER_UPDATE msg; APPL_TRACE_DEBUG("%s", __func__); - bta_av_co_audio_encoder_update(&msg); - - /* Update the audio encoding */ - btif_a2dp_source_enc_update_req(&msg); + bta_av_co_audio_encoder_update(&msg.update_params); + btif_a2dp_source_encoder_update_req(&msg); } -static void btif_a2dp_source_enc_init_req(tBTIF_A2DP_SOURCE_INIT_AUDIO *p_msg) +static void btif_a2dp_source_encoder_init_req(tBTIF_A2DP_SOURCE_ENCODER_INIT *p_msg) { - tBTIF_A2DP_SOURCE_INIT_AUDIO *p_buf = - (tBTIF_A2DP_SOURCE_INIT_AUDIO *)osi_malloc(sizeof(tBTIF_A2DP_SOURCE_INIT_AUDIO)); + tBTIF_A2DP_SOURCE_ENCODER_INIT *p_buf = + (tBTIF_A2DP_SOURCE_ENCODER_INIT *)osi_malloc(sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT)); - memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_INIT_AUDIO)); - p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_INIT; + memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT)); + p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_INIT; fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf); } -static void btif_a2dp_source_enc_update_req(tBTIF_A2DP_SOURCE_UPDATE_AUDIO *p_msg) +static void btif_a2dp_source_encoder_update_req(tBTIF_A2DP_SOURCE_ENCODER_UPDATE *p_msg) { - tBTIF_A2DP_SOURCE_UPDATE_AUDIO *p_buf = (tBTIF_A2DP_SOURCE_UPDATE_AUDIO *) - osi_malloc(sizeof(tBTIF_A2DP_SOURCE_UPDATE_AUDIO)); + tBTIF_A2DP_SOURCE_ENCODER_UPDATE *p_buf = + (tBTIF_A2DP_SOURCE_ENCODER_UPDATE *)osi_malloc(sizeof(tBTIF_A2DP_SOURCE_ENCODER_UPDATE)); - memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_UPDATE_AUDIO)); - p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_UPDATE; + memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_ENCODER_UPDATE)); + p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_UPDATE; fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf); } -static void btif_a2dp_source_enc_init(BT_HDR *p_msg) +static void btif_a2dp_source_encoder_init_event(BT_HDR *p_msg) { - tBTIF_A2DP_SOURCE_INIT_AUDIO *pInitAudio = (tBTIF_A2DP_SOURCE_INIT_AUDIO *) p_msg; + tBTIF_A2DP_SOURCE_ENCODER_INIT *p_encoder_init = + (tBTIF_A2DP_SOURCE_ENCODER_INIT *)p_msg; APPL_TRACE_DEBUG("%s", __func__); - btif_a2dp_source_cb.timestamp = 0; - - /* SBC encoder config (enforced even if not used) */ - btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode = pInitAudio->ChannelMode; - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands = pInitAudio->NumOfSubBands; - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks = pInitAudio->NumOfBlocks; - btif_a2dp_source_cb.sbc_encoder_params.s16AllocationMethod = pInitAudio->AllocationMethod; - btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq = pInitAudio->SamplingFreq; - - btif_a2dp_source_cb.sbc_encoder_params.u16BitRate = btif_a2dp_source_get_sbc_rate(); - - /* Default transcoding is PCM to SBC, modified by feeding configuration */ - btif_a2dp_source_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_SBC; - btif_a2dp_source_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE-BTIF_MEDIA_AA_SBC_OFFSET-sizeof(BT_HDR)) - < pInitAudio->MtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET - - sizeof(BT_HDR)) : pInitAudio->MtuSize; - - APPL_TRACE_EVENT("%s: mtu %d, peer mtu %d", - __func__, - btif_a2dp_source_cb.TxAaMtuSize, pInitAudio->MtuSize); - APPL_TRACE_EVENT("%s: ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d", - __func__, - btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode, - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands, - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks, - btif_a2dp_source_cb.sbc_encoder_params.s16AllocationMethod, - btif_a2dp_source_cb.sbc_encoder_params.u16BitRate, - btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq); - - /* Reset entirely the SBC encoder */ - SBC_Encoder_Init(&(btif_a2dp_source_cb.sbc_encoder_params)); - - btif_a2dp_source_cb.tx_sbc_frames = calculate_max_frames_per_packet(); - - APPL_TRACE_DEBUG("%s: bit pool %d", __func__, - btif_a2dp_source_cb.sbc_encoder_params.s16BitPool); -} - -static void btif_a2dp_source_enc_update(BT_HDR *p_msg) -{ - tBTIF_A2DP_SOURCE_UPDATE_AUDIO * pUpdateAudio = (tBTIF_A2DP_SOURCE_UPDATE_AUDIO *) p_msg; - SBC_ENC_PARAMS *pstrEncParams = &btif_a2dp_source_cb.sbc_encoder_params; - uint16_t s16SamplingFreq; - SINT16 s16BitPool = 0; - SINT16 s16BitRate; - SINT16 s16FrameLen; - uint8_t protect = 0; - - APPL_TRACE_DEBUG("%s: minmtu %d, maxbp %d minbp %d", __func__, - pUpdateAudio->MinMtuSize, pUpdateAudio->MaxBitPool, - pUpdateAudio->MinBitPool); - - if (!pstrEncParams->s16NumOfSubBands) { - APPL_TRACE_WARNING("%s: SubBands are set to 0, resetting to max (%d)", - __func__, SBC_MAX_NUM_OF_SUBBANDS); - pstrEncParams->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS; - } - - if (!pstrEncParams->s16NumOfBlocks) { - APPL_TRACE_WARNING("%s: Blocks are set to 0, resetting to max (%d)", - __func__, SBC_MAX_NUM_OF_BLOCKS); - pstrEncParams->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS; - } - - if (!pstrEncParams->s16NumOfChannels) { - APPL_TRACE_WARNING("%s: Channels are set to 0, resetting to max (%d)", - __func__, SBC_MAX_NUM_OF_CHANNELS); - pstrEncParams->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS; + btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface(); + if (btif_a2dp_source_cb.encoder_interface == NULL) { + APPL_TRACE_ERROR("%s: Cannot stream audio: no source encoder interface", + __func__); + return; } - btif_a2dp_source_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE - - BTIF_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR)) - < pUpdateAudio->MinMtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET - - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize; - - /* Set the initial target bit rate */ - pstrEncParams->u16BitRate = btif_a2dp_source_get_sbc_rate(); - - if (pstrEncParams->s16SamplingFreq == SBC_sf16000) - s16SamplingFreq = 16000; - else if (pstrEncParams->s16SamplingFreq == SBC_sf32000) - s16SamplingFreq = 32000; - else if (pstrEncParams->s16SamplingFreq == SBC_sf44100) - s16SamplingFreq = 44100; - else - s16SamplingFreq = 48000; - - do { - if (pstrEncParams->s16NumOfBlocks == 0 || - pstrEncParams->s16NumOfSubBands == 0 || - pstrEncParams->s16NumOfChannels == 0) { - APPL_TRACE_ERROR("%s - Avoiding division by zero...", __func__); - APPL_TRACE_ERROR("%s - block=%d, subBands=%d, channels=%d", - __func__, - pstrEncParams->s16NumOfBlocks, - pstrEncParams->s16NumOfSubBands, - pstrEncParams->s16NumOfChannels); - break; - } + btif_a2dp_source_cb.encoder_interface->encoder_init( + btif_av_is_peer_edr(), + btif_av_peer_supports_3mbps(), + &p_encoder_init->init_params, + btif_a2dp_source_read_callback, + btif_a2dp_source_enqueue_callback); - if ((pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) || - (pstrEncParams->s16ChannelMode == SBC_STEREO)) { - s16BitPool = (SINT16)((pstrEncParams->u16BitRate * - pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq) - - ((32 + (4 * pstrEncParams->s16NumOfSubBands * - pstrEncParams->s16NumOfChannels) - + ((pstrEncParams->s16ChannelMode - 2) * - pstrEncParams->s16NumOfSubBands)) - / pstrEncParams->s16NumOfBlocks)); - - s16FrameLen = 4 + (4*pstrEncParams->s16NumOfSubBands * - pstrEncParams->s16NumOfChannels) / 8 - + (((pstrEncParams->s16ChannelMode - 2) * - pstrEncParams->s16NumOfSubBands) - + (pstrEncParams->s16NumOfBlocks * s16BitPool)) / 8; - - s16BitRate = (8 * s16FrameLen * s16SamplingFreq) - / (pstrEncParams->s16NumOfSubBands * - pstrEncParams->s16NumOfBlocks * 1000); - - if (s16BitRate > pstrEncParams->u16BitRate) - s16BitPool--; - - if (pstrEncParams->s16NumOfSubBands == 8) - s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool; - else - s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool; - } else { - s16BitPool = (SINT16)(((pstrEncParams->s16NumOfSubBands * - pstrEncParams->u16BitRate * 1000) - / (s16SamplingFreq * pstrEncParams->s16NumOfChannels)) - - (((32 / pstrEncParams->s16NumOfChannels) + - (4 * pstrEncParams->s16NumOfSubBands)) - / pstrEncParams->s16NumOfBlocks)); - - pstrEncParams->s16BitPool = - (s16BitPool > (16 * pstrEncParams->s16NumOfSubBands)) ? - (16 * pstrEncParams->s16NumOfSubBands) : s16BitPool; - } - - if (s16BitPool < 0) - s16BitPool = 0; - - APPL_TRACE_EVENT("%s: bitpool candidate: %d (%d kbps)", __func__, - s16BitPool, pstrEncParams->u16BitRate); - - if (s16BitPool > pUpdateAudio->MaxBitPool) { - APPL_TRACE_DEBUG("%s: computed bitpool too large (%d)", __func__, - s16BitPool); - /* Decrease bitrate */ - btif_a2dp_source_cb.sbc_encoder_params.u16BitRate -= BTIF_MEDIA_BITRATE_STEP; - /* Record that we have decreased the bitrate */ - protect |= 1; - } else if (s16BitPool < pUpdateAudio->MinBitPool) { - APPL_TRACE_WARNING("%s: computed bitpool too small (%d)", __func__, - s16BitPool); - - /* Increase bitrate */ - uint16_t previous_u16BitRate = btif_a2dp_source_cb.sbc_encoder_params.u16BitRate; - btif_a2dp_source_cb.sbc_encoder_params.u16BitRate += BTIF_MEDIA_BITRATE_STEP; - /* Record that we have increased the bitrate */ - protect |= 2; - /* Check over-flow */ - if (btif_a2dp_source_cb.sbc_encoder_params.u16BitRate < previous_u16BitRate) - protect |= 3; - } else { - break; - } - /* In case we have already increased and decreased the bitrate, just stop */ - if (protect == 3) { - APPL_TRACE_ERROR("%s could not find bitpool in range", __func__); - break; - } - } while (true); - - /* Finally update the bitpool in the encoder structure */ - pstrEncParams->s16BitPool = s16BitPool; - - APPL_TRACE_DEBUG("%s: final bit rate %d, final bit pool %d", __func__, - btif_a2dp_source_cb.sbc_encoder_params.u16BitRate, - btif_a2dp_source_cb.sbc_encoder_params.s16BitPool); + // Save a local copy of the encoder_interval_ms + btif_a2dp_source_cb.encoder_interval_ms = + btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(); +} - /* make sure we reinitialize encoder with new settings */ - SBC_Encoder_Init(&(btif_a2dp_source_cb.sbc_encoder_params)); +static void btif_a2dp_source_encoder_update_event(BT_HDR *p_msg) +{ + tBTIF_A2DP_SOURCE_ENCODER_UPDATE *p_encoder_update = + (tBTIF_A2DP_SOURCE_ENCODER_UPDATE *)p_msg; - btif_a2dp_source_cb.tx_sbc_frames = calculate_max_frames_per_packet(); + APPL_TRACE_DEBUG("%s", __func__); + assert(btif_a2dp_source_cb.encoder_interface != NULL); + btif_a2dp_source_cb.encoder_interface->encoder_update( + &p_encoder_update->update_params); } -static void btif_a2dp_source_feeding_init_req(tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *p_msg) +static void btif_a2dp_source_feeding_init_req(tBTIF_A2DP_AUDIO_FEEDING_INIT *p_msg) { - tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *p_buf = - (tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *)osi_malloc(sizeof(tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING)); + tBTIF_A2DP_AUDIO_FEEDING_INIT *p_buf = + (tBTIF_A2DP_AUDIO_FEEDING_INIT *)osi_malloc(sizeof(tBTIF_A2DP_AUDIO_FEEDING_INIT)); - memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING)); + memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_AUDIO_FEEDING_INIT)); p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_INIT; fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf); } @@ -716,7 +481,7 @@ void btif_a2dp_source_on_idle(void) return; /* Make sure media task is stopped */ - btif_a2dp_source_stop_aa_req(); + btif_a2dp_source_stop_audio_req(); } void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av_suspend) @@ -742,9 +507,9 @@ void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av_suspend) /* ensure tx frames are immediately suspended */ btif_a2dp_source_cb.tx_flush = true; - /* request to stop media task */ - btif_a2dp_source_aa_tx_flush_req(); - btif_a2dp_source_stop_aa_req(); + /* request to stop media task */ + btif_a2dp_source_audio_tx_flush_req(); + btif_a2dp_source_stop_audio_req(); /* once stream is fully stopped we will ack back */ } @@ -771,7 +536,7 @@ void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av_suspend) btif_a2dp_source_cb.tx_flush = true; /* stop timer tick */ - btif_a2dp_source_stop_aa_req(); + btif_a2dp_source_stop_audio_req(); } /* when true media task discards any tx frames */ @@ -781,121 +546,30 @@ void btif_a2dp_source_set_tx_flush(bool enable) btif_a2dp_source_cb.tx_flush = enable; } -static void btif_a2dp_source_feeding_state_reset(void) -{ - /* By default, just clear the entire state */ - memset(&btif_a2dp_source_cb.media_feeding_state, 0, - sizeof(btif_a2dp_source_cb.media_feeding_state)); - - if (btif_a2dp_source_cb.TxTranscoding == BTIF_MEDIA_TRSCD_PCM_2_SBC) { - btif_a2dp_source_cb.media_feeding_state.bytes_per_tick = - (btif_a2dp_source_cb.media_feeding.sampling_freq * - btif_a2dp_source_cb.media_feeding.bit_per_sample / 8 * - btif_a2dp_source_cb.media_feeding.num_channel * - BTIF_A2DP_SOURCE_MEDIA_TIMER_MS) / 1000; - - APPL_TRACE_WARNING("pcm bytes per tick %d", - (int)btif_a2dp_source_cb.media_feeding_state.bytes_per_tick); - } -} - -static void btif_a2dp_source_audio_feeding_init(BT_HDR *p_msg) +static void btif_a2dp_source_audio_feeding_init_event(BT_HDR *p_msg) { - tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *p_feeding = - (tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *)p_msg; + tBTIF_A2DP_AUDIO_FEEDING_INIT *p_feeding = + (tBTIF_A2DP_AUDIO_FEEDING_INIT *)p_msg; APPL_TRACE_DEBUG("%s", __func__); - /* Save Media Feeding information */ - btif_a2dp_source_cb.media_feeding = p_feeding->feeding; - btif_a2dp_source_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_SBC; - - btif_a2dp_source_pcm2sbc_init(p_feeding); + assert(btif_a2dp_source_cb.encoder_interface != NULL); + btif_a2dp_source_cb.encoder_interface->feeding_init( + &p_feeding->feeding_params); } -static void btif_a2dp_source_pcm2sbc_init(tBTIF_A2DP_SOURCE_INIT_AUDIO_FEEDING *p_feeding) -{ - bool reconfig_needed = false; - - APPL_TRACE_DEBUG("PCM feeding:"); - APPL_TRACE_DEBUG("sampling_freq:%d", p_feeding->feeding.sampling_freq); - APPL_TRACE_DEBUG("num_channel:%d", p_feeding->feeding.num_channel); - APPL_TRACE_DEBUG("bit_per_sample:%d", p_feeding->feeding.bit_per_sample); - - /* Check the PCM feeding sampling_freq */ - switch (p_feeding->feeding.sampling_freq) { - case 8000: - case 12000: - case 16000: - case 24000: - case 32000: - case 48000: - /* For these sampling_freq the AV connection must be 48000 */ - if (btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq != - SBC_sf48000) { - /* Reconfiguration needed at 48000 */ - APPL_TRACE_DEBUG("SBC Reconfiguration needed at 48000"); - btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq = - SBC_sf48000; - reconfig_needed = true; - } - break; - - case 11025: - case 22050: - case 44100: - /* For these sampling_freq the AV connection must be 44100 */ - if (btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq != - SBC_sf44100) { - /* Reconfiguration needed at 44100 */ - APPL_TRACE_DEBUG("SBC Reconfiguration needed at 44100"); - btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq = - SBC_sf44100; - reconfig_needed = true; - } - break; - default: - APPL_TRACE_DEBUG("Feeding PCM sampling_freq unsupported"); - break; - } - - /* Some AV Headsets do not support Mono => always ask for Stereo */ - if (btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode == SBC_MONO) { - APPL_TRACE_DEBUG("SBC Reconfiguration needed in Stereo"); - btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode = SBC_JOINT_STEREO; - reconfig_needed = true; - } - - if (reconfig_needed) { - APPL_TRACE_DEBUG("%s: mtu %d", __func__, - btif_a2dp_source_cb.TxAaMtuSize); - APPL_TRACE_DEBUG("%s: ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d", - __func__, - btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode, - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands, - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks, - btif_a2dp_source_cb.sbc_encoder_params.s16AllocationMethod, - btif_a2dp_source_cb.sbc_encoder_params.u16BitRate, - btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq); - - SBC_Encoder_Init(&(btif_a2dp_source_cb.sbc_encoder_params)); - } else { - APPL_TRACE_DEBUG("%s: no SBC reconfig needed", __func__); - } -} - -static void btif_a2dp_source_aa_start_tx(void) +static void btif_a2dp_source_audio_tx_start_event(void) { APPL_TRACE_DEBUG("%s media_alarm is %srunning, is_streaming %s", __func__, alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)? "" : "not ", (btif_a2dp_source_cb.is_streaming)? "true" : "false"); - last_frame_us = 0; - /* Reset the media feeding state */ - btif_a2dp_source_feeding_state_reset(); + assert(btif_a2dp_source_cb.encoder_interface != NULL); + btif_a2dp_source_cb.encoder_interface->feeding_reset(); - APPL_TRACE_EVENT("starting timer %dms", BTIF_A2DP_SOURCE_MEDIA_TIMER_MS); + APPL_TRACE_EVENT("starting timer %dms", + btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms()); alarm_free(btif_a2dp_source_cb.media_alarm); btif_a2dp_source_cb.media_alarm = alarm_new_periodic("btif.a2dp_source_media_alarm"); @@ -904,11 +578,12 @@ static void btif_a2dp_source_aa_start_tx(void) return; } - alarm_set(btif_a2dp_source_cb.media_alarm, BTIF_A2DP_SOURCE_MEDIA_TIMER_MS, + alarm_set(btif_a2dp_source_cb.media_alarm, + btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(), btif_a2dp_source_alarm_cb, NULL); } -static void btif_a2dp_source_aa_stop_tx(void) +static void btif_a2dp_source_audio_tx_stop_event(void) { APPL_TRACE_DEBUG("%s media_alarm is %srunning, is_streaming %s", __func__, alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)? "" : "not ", @@ -941,69 +616,91 @@ static void btif_a2dp_source_aa_stop_tx(void) /* audio engine stopped, reset tx suspended flag */ btif_a2dp_source_cb.tx_flush = false; - last_frame_us = 0; /* Reset the media feeding state */ - btif_a2dp_source_feeding_state_reset(); + if (btif_a2dp_source_cb.encoder_interface != NULL) + btif_a2dp_source_cb.encoder_interface->feeding_reset(); } static void btif_a2dp_source_alarm_cb(UNUSED_ATTR void *context) { - thread_post(btif_a2dp_source_cb.worker_thread, - btif_a2dp_source_aa_handle_timer, NULL); + thread_post(btif_a2dp_source_cb.worker_thread, + btif_a2dp_source_audio_handle_timer, NULL); } -static void btif_a2dp_source_aa_handle_timer(UNUSED_ATTR void *context) +static void btif_a2dp_source_audio_handle_timer(UNUSED_ATTR void *context) { uint64_t timestamp_us = time_get_os_boottime_us(); log_tstamps_us("A2DP Source tx timer", timestamp_us); if (alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) { - btif_a2dp_source_send_aa_frame(timestamp_us); + assert(btif_a2dp_source_cb.encoder_interface != NULL); + btif_a2dp_source_cb.encoder_interface->send_frames(timestamp_us); + bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO); } else { APPL_TRACE_ERROR("ERROR Media task Scheduled after Suspend"); } } -static void btif_a2dp_source_send_aa_frame(uint64_t timestamp_us) +static uint32_t btif_a2dp_source_read_callback(uint8_t *p_buf, uint32_t len) { - uint8_t nb_frame_2_send = 0; - uint8_t nb_iterations = 0; - - btif_get_num_aa_frame_iteration(&nb_iterations, &nb_frame_2_send); + uint16_t event; + uint32_t bytes_read = UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, p_buf, len); - if (nb_frame_2_send != 0) { - for (uint8_t counter = 0; counter < nb_iterations; counter++) { - /* format and queue buffer to send */ - btif_a2dp_source_aa_prep_2_send(nb_frame_2_send, timestamp_us); - } + if (bytes_read < len) { + LOG_WARN(LOG_TAG, "%s: UNDERFLOW: ONLY READ %d BYTES OUT OF %d", + __func__,bytes_read, len); + btif_a2dp_source_cb.stats.media_read_total_underflow_bytes += + (len - bytes_read); + btif_a2dp_source_cb.stats.media_read_total_underflow_count++; + btif_a2dp_source_cb.stats.media_read_last_underflow_us = + time_get_os_boottime_us(); } - LOG_VERBOSE(LOG_TAG, "%s: Sent %d frames per iteration, %d iterations", - __func__, nb_frame_2_send, nb_iterations); - bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO); + return bytes_read; } -static void btif_a2dp_source_aa_prep_2_send(uint8_t nb_frame, - uint64_t timestamp_us) +static bool btif_a2dp_source_enqueue_callback(BT_HDR *p_buf, size_t frames_n) { - // Check for TX queue overflow + uint64_t now_us = time_get_os_boottime_us(); - if (nb_frame > MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) - nb_frame = MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ; + /* Check if timer was stopped (media task stopped) */ + if (! alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) { + osi_free(p_buf); + return false; + } + + /* Check if the transmission queue has been flushed */ + if (btif_a2dp_source_cb.tx_flush) { + LOG_VERBOSE(LOG_TAG, "%s: tx suspended, discarded frame", __func__); + + btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages += + fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue); + btif_a2dp_source_cb.stats.tx_queue_last_flushed_us = now_us; + fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free); + + osi_free(p_buf); + return false; + } - if (fixed_queue_length(btif_a2dp_source_cb.TxAaQ) > - (MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ - nb_frame)) { - APPL_TRACE_WARNING("%s() - TX queue buffer count %d/%d", __func__, - fixed_queue_length(btif_a2dp_source_cb.TxAaQ), - MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ - nb_frame); + // Check for TX queue overflow + // TODO: Using frames_n here is probably wrong: should be "+ 1" instead. + if (fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue) + frames_n > + MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) { + LOG_WARN(LOG_TAG, "%s: TX queue buffer size now=%u adding=%u max=%d", + __func__, + (uint32_t)fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue), + (uint32_t)frames_n, MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ); // Keep track of drop-outs btif_a2dp_source_cb.stats.tx_queue_dropouts++; - btif_a2dp_source_cb.stats.tx_queue_last_dropouts_us = timestamp_us; + btif_a2dp_source_cb.stats.tx_queue_last_dropouts_us = now_us; // Flush all queued buffers - while (fixed_queue_length(btif_a2dp_source_cb.TxAaQ)) { + size_t drop_n = fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue); + if (btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages < drop_n) + btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages = drop_n; + while (fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue)) { btif_a2dp_source_cb.stats.tx_queue_total_dropped_messages++; - osi_free(fixed_queue_try_dequeue(btif_a2dp_source_cb.TxAaQ)); + osi_free(fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue)); } // Request RSSI for log purposes if we had to flush buffers @@ -1011,303 +708,48 @@ static void btif_a2dp_source_aa_prep_2_send(uint8_t nb_frame, BTM_ReadRSSI(peer_bda.address, btm_read_rssi_cb); } - // Transcode frame - - switch (btif_a2dp_source_cb.TxTranscoding) { - case BTIF_MEDIA_TRSCD_PCM_2_SBC: - btif_a2dp_source_aa_prep_sbc_2_send(nb_frame, timestamp_us); - break; - - default: - APPL_TRACE_ERROR("%s: unsupported transcoding format 0x%x", - __func__, btif_a2dp_source_cb.TxTranscoding); - break; - } -} - -static void btif_a2dp_source_aa_prep_sbc_2_send(uint8_t nb_frame, - uint64_t timestamp_us) -{ - uint8_t remain_nb_frame = nb_frame; - uint16_t blocm_x_subband = - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks; - - while (nb_frame) { - BT_HDR *p_buf = (BT_HDR *)osi_malloc(BTIF_MEDIA_AA_BUF_SIZE); - - /* Init buffer */ - p_buf->offset = BTIF_MEDIA_AA_SBC_OFFSET; - p_buf->len = 0; - p_buf->layer_specific = 0; - - do { - /* Write @ of allocated buffer in sbc_encoder_params.pu8Packet */ - btif_a2dp_source_cb.sbc_encoder_params.pu8Packet = - (uint8_t *) (p_buf + 1) + p_buf->offset + p_buf->len; - /* Fill allocated buffer with 0 */ - memset(btif_a2dp_source_cb.sbc_encoder_params.as16PcmBuffer, 0, - blocm_x_subband * btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels); - - /* Read PCM data and upsample them if needed */ - if (btif_a2dp_source_aa_read_feeding()) { - SBC_Encoder(&(btif_a2dp_source_cb.sbc_encoder_params)); - - /* Update SBC frame length */ - p_buf->len += btif_a2dp_source_cb.sbc_encoder_params.u16PacketLength; - nb_frame--; - p_buf->layer_specific++; - } else { - APPL_TRACE_WARNING("%s: underflow %d, %d", - __func__, nb_frame, - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue); - btif_a2dp_source_cb.media_feeding_state.counter += - nb_frame * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks * - btif_a2dp_source_cb.media_feeding.num_channel * - btif_a2dp_source_cb.media_feeding.bit_per_sample / 8; - /* no more pcm to read */ - nb_frame = 0; - - /* break read loop if timer was stopped (media task stopped) */ - if (! alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) { - osi_free(p_buf); - return; - } - } - - } while (((p_buf->len + btif_a2dp_source_cb.sbc_encoder_params.u16PacketLength) < btif_a2dp_source_cb.TxAaMtuSize) - && (p_buf->layer_specific < 0x0F) && nb_frame); - - if (p_buf->len) { - /* - * Timestamp of the media packet header represent the TS of the - * first SBC frame, i.e the timestamp before including this frame. - */ - *((uint32_t *) (p_buf + 1)) = btif_a2dp_source_cb.timestamp; - - btif_a2dp_source_cb.timestamp += - p_buf->layer_specific * blocm_x_subband; - - if (btif_a2dp_source_cb.tx_flush) { - APPL_TRACE_DEBUG("### tx suspended, discarded frame ###"); - - btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages += - fixed_queue_length(btif_a2dp_source_cb.TxAaQ); - btif_a2dp_source_cb.stats.tx_queue_last_flushed_us = - timestamp_us; - fixed_queue_flush(btif_a2dp_source_cb.TxAaQ, osi_free); - - osi_free(p_buf); - return; - } - - /* Enqueue the encoded SBC frame in AA Tx Queue */ - update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_enqueue_stats, - timestamp_us, - BTIF_A2DP_SOURCE_MEDIA_TIMER_MS * 1000); - uint8_t done_nb_frame = remain_nb_frame - nb_frame; - remain_nb_frame = nb_frame; - btif_a2dp_source_cb.stats.tx_queue_total_frames += done_nb_frame; - if (done_nb_frame > btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet) - btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet = done_nb_frame; - fixed_queue_enqueue(btif_a2dp_source_cb.TxAaQ, p_buf); - } else { - osi_free(p_buf); - } - } -} - -static bool btif_a2dp_source_aa_read_feeding(void) -{ - uint16_t event; - uint16_t blocm_x_subband = - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks; - uint32_t read_size; - uint32_t sbc_sampling = 48000; - uint32_t src_samples; - uint16_t bytes_needed = blocm_x_subband * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels * - btif_a2dp_source_cb.media_feeding.bit_per_sample / 8; - static uint16_t up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS - * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2]; - static uint16_t read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS - * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS]; - uint32_t src_size_used; - uint32_t dst_size_used; - bool fract_needed; - int32_t fract_max; - int32_t fract_threshold; - uint32_t nb_byte_read; - - /* Get the SBC sampling rate */ - switch (btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq) { - case SBC_sf48000: - sbc_sampling = 48000; - break; - case SBC_sf44100: - sbc_sampling = 44100; - break; - case SBC_sf32000: - sbc_sampling = 32000; - break; - case SBC_sf16000: - sbc_sampling = 16000; - break; - } - - if (sbc_sampling == btif_a2dp_source_cb.media_feeding.sampling_freq) { - read_size = bytes_needed - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue; - nb_byte_read = UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, - ((uint8_t *)btif_a2dp_source_cb.sbc_encoder_params.as16PcmBuffer) + - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue, - read_size); - if (nb_byte_read == read_size) { - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue = 0; - return true; - } else { - APPL_TRACE_WARNING("### UNDERFLOW :: ONLY READ %d BYTES OUT OF %d ###", - nb_byte_read, read_size); - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue += nb_byte_read; - btif_a2dp_source_cb.stats.media_read_total_underflow_bytes += (read_size - nb_byte_read); - btif_a2dp_source_cb.stats.media_read_total_underflow_count++; - btif_a2dp_source_cb.stats.media_read_last_underflow_us = time_get_os_boottime_us(); - return false; - } - } - - /* - * Some Feeding PCM frequencies require to split the number of sample - * to read. - * E.g 128 / 6 = 21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0 - */ - fract_needed = false; /* Default */ - switch (btif_a2dp_source_cb.media_feeding.sampling_freq) { - case 32000: - case 8000: - fract_needed = true; - fract_max = 2; /* 0, 1 and 2 */ - fract_threshold = 0; /* Add one for the first */ - break; - case 16000: - fract_needed = true; - fract_max = 2; /* 0, 1 and 2 */ - fract_threshold = 1; /* Add one for the first two frames*/ - break; - } - - /* Compute number of sample to read from source */ - src_samples = blocm_x_subband; - src_samples *= btif_a2dp_source_cb.media_feeding.sampling_freq; - src_samples /= sbc_sampling; + /* Update the statistics */ + btif_a2dp_source_cb.stats.tx_queue_total_frames += frames_n; + if (frames_n > btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet) + btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet = frames_n; + assert(btif_a2dp_source_cb.encoder_interface != NULL); + update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_enqueue_stats, + now_us, + btif_a2dp_source_cb.encoder_interval_ms * 1000); - /* The previous division may have a remainder not null */ - if (fract_needed) { - if (btif_a2dp_source_cb.media_feeding_state.aa_feed_counter <= fract_threshold) { - src_samples++; /* for every read before threshold add one sample */ - } - - /* do nothing if counter >= threshold */ - btif_a2dp_source_cb.media_feeding_state.aa_feed_counter++; /* one more read */ - if (btif_a2dp_source_cb.media_feeding_state.aa_feed_counter > fract_max) { - btif_a2dp_source_cb.media_feeding_state.aa_feed_counter = 0; - } - } + fixed_queue_enqueue(btif_a2dp_source_cb.tx_audio_queue, p_buf); - /* Compute number of bytes to read from source */ - read_size = src_samples; - read_size *= btif_a2dp_source_cb.media_feeding.num_channel; - read_size *= (btif_a2dp_source_cb.media_feeding.bit_per_sample / 8); - - /* Read Data from UIPC channel */ - nb_byte_read = UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, - (uint8_t *)read_buffer, read_size); - - if (nb_byte_read < read_size) { - APPL_TRACE_WARNING("### UNDERRUN :: ONLY READ %d BYTES OUT OF %d ###", - nb_byte_read, read_size); - btif_a2dp_source_cb.stats.media_read_total_underrun_bytes += (read_size - nb_byte_read); - btif_a2dp_source_cb.stats.media_read_total_underrun_count++; - btif_a2dp_source_cb.stats.media_read_last_underrun_us = time_get_os_boottime_us(); - - if (nb_byte_read == 0) - return false; - - /* Fill the unfilled part of the read buffer with silence (0) */ - memset(((uint8_t *)read_buffer) + nb_byte_read, 0, - read_size - nb_byte_read); - nb_byte_read = read_size; - } - - /* Initialize PCM up-sampling engine */ - bta_av_sbc_init_up_sample(btif_a2dp_source_cb.media_feeding.sampling_freq, - sbc_sampling, - btif_a2dp_source_cb.media_feeding.bit_per_sample, - btif_a2dp_source_cb.media_feeding.num_channel); - - /* - * Re-sample the read buffer. - * The output PCM buffer will be stereo, 16 bit per sample. - */ - dst_size_used = bta_av_sbc_up_sample((uint8_t *)read_buffer, - (uint8_t *)up_sampled_buffer + btif_a2dp_source_cb.media_feeding_state.aa_feed_residue, - nb_byte_read, - sizeof(up_sampled_buffer) - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue, - &src_size_used); - - /* update the residue */ - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue += dst_size_used; - - /* only copy the pcm sample when we have up-sampled enough PCM */ - if (btif_a2dp_source_cb.media_feeding_state.aa_feed_residue >= bytes_needed) { - /* Copy the output pcm samples in SBC encoding buffer */ - memcpy((uint8_t *)btif_a2dp_source_cb.sbc_encoder_params.as16PcmBuffer, - (uint8_t *)up_sampled_buffer, - bytes_needed); - /* update the residue */ - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue -= bytes_needed; - - if (btif_a2dp_source_cb.media_feeding_state.aa_feed_residue != 0) { - memcpy((uint8_t *)up_sampled_buffer, - (uint8_t *)up_sampled_buffer + bytes_needed, - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue); - } - return true; - } - - return false; + return true; } -static void btif_a2dp_source_aa_tx_flush(UNUSED_ATTR BT_HDR *p_msg) +static void btif_a2dp_source_audio_tx_flush_event(UNUSED_ATTR BT_HDR *p_msg) { /* Flush all enqueued audio buffers (encoded) */ APPL_TRACE_DEBUG("%s", __func__); - btif_a2dp_source_cb.media_feeding_state.counter = 0; - btif_a2dp_source_cb.media_feeding_state.aa_feed_residue = 0; + if (btif_a2dp_source_cb.encoder_interface != NULL) + btif_a2dp_source_cb.encoder_interface->feeding_flush(); btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages += - fixed_queue_length(btif_a2dp_source_cb.TxAaQ); + fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue); btif_a2dp_source_cb.stats.tx_queue_last_flushed_us = time_get_os_boottime_us(); - fixed_queue_flush(btif_a2dp_source_cb.TxAaQ, osi_free); + fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free); UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, NULL); } -static bool btif_a2dp_source_aa_tx_flush_req(void) +static bool btif_a2dp_source_audio_tx_flush_req(void) { BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR)); - p_buf->event = BTIF_MEDIA_FLUSH_AA_TX; + p_buf->event = BTIF_MEDIA_AUDIO_TX_FLUSH; /* * Explicitly check whether the btif_a2dp_source_cb.cmd_msg_queue is not * NULL to avoid a race condition during shutdown of the Bluetooth stack. * This race condition is triggered when A2DP audio is streaming on * shutdown: - * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_aa_tx_flush_req()" + * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_audio_tx_flush_req()" * is called to stop the particular audio stream, and this happens right * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()" * processing during the shutdown of the Bluetooth stack. @@ -1318,10 +760,10 @@ static bool btif_a2dp_source_aa_tx_flush_req(void) return true; } -BT_HDR *btif_a2dp_source_aa_readbuf(void) +BT_HDR *btif_a2dp_source_audio_readbuf(void) { uint64_t now_us = time_get_os_boottime_us(); - BT_HDR *p_buf = (BT_HDR *)fixed_queue_try_dequeue(btif_a2dp_source_cb.TxAaQ); + BT_HDR *p_buf = (BT_HDR *)fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue); btif_a2dp_source_cb.stats.tx_queue_total_readbuf_calls++; btif_a2dp_source_cb.stats.tx_queue_last_readbuf_us = now_us; @@ -1329,7 +771,7 @@ BT_HDR *btif_a2dp_source_aa_readbuf(void) // Update the statistics update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_dequeue_stats, now_us, - BTIF_A2DP_SOURCE_MEDIA_TIMER_MS * 1000); + btif_a2dp_source_cb.encoder_interval_ms * 1000); } return p_buf; @@ -1338,277 +780,12 @@ BT_HDR *btif_a2dp_source_aa_readbuf(void) static void log_tstamps_us(const char *comment, uint64_t timestamp_us) { static uint64_t prev_us = 0; - APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment, timestamp_us, - timestamp_us - prev_us, fixed_queue_length(btif_a2dp_source_cb.TxAaQ)); + APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", + comment, timestamp_us, timestamp_us - prev_us, + fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue)); prev_us = timestamp_us; } -static void btm_read_rssi_cb(void *data) -{ - assert(data); - - tBTM_RSSI_RESULTS *result = (tBTM_RSSI_RESULTS*)data; - if (result->status != BTM_SUCCESS) - { - LOG_ERROR(LOG_TAG, "%s unable to read remote RSSI (status %d)", - __func__, result->status); - return; - } - - char temp_buffer[20] = {0}; - LOG_WARN(LOG_TAG, "%s device: %s, rssi: %d", __func__, - bdaddr_to_string((bt_bdaddr_t *)result->rem_bda, temp_buffer, - sizeof(temp_buffer)), - result->rssi); -} - -static uint16_t btif_a2dp_source_get_sbc_rate(void) -{ - uint16_t rate = BTIF_A2DP_DEFAULT_BITRATE; - - /* restrict bitrate if a2dp link is non-edr */ - if (!btif_av_is_peer_edr()) { - rate = BTIF_A2DP_NON_EDR_MAX_RATE; - APPL_TRACE_DEBUG("%s: non-edr a2dp sink detected, restrict rate to %d", - __func__, rate); - } - - return rate; -} - -// Obtains the number of frames to send and number of iterations -// to be used. |num_of_ietrations| and |num_of_frames| parameters -// are used as output param for returning the respective values. -static void btif_get_num_aa_frame_iteration(uint8_t *num_of_iterations, - uint8_t *num_of_frames) -{ - uint8_t nof = 0; - uint8_t noi = 1; - - switch (btif_a2dp_source_cb.TxTranscoding) { - case BTIF_MEDIA_TRSCD_PCM_2_SBC: - { - uint32_t projected_nof = 0; - uint32_t pcm_bytes_per_frame = - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks * - btif_a2dp_source_cb.media_feeding.num_channel * - btif_a2dp_source_cb.media_feeding.bit_per_sample / 8; - APPL_TRACE_DEBUG("%s: pcm_bytes_per_frame %u", __func__, - pcm_bytes_per_frame); - - uint32_t us_this_tick = BTIF_A2DP_SOURCE_MEDIA_TIMER_MS * 1000; - uint64_t now_us = time_get_os_boottime_us(); - if (last_frame_us != 0) - us_this_tick = (now_us - last_frame_us); - last_frame_us = now_us; - - btif_a2dp_source_cb.media_feeding_state.counter += - btif_a2dp_source_cb.media_feeding_state.bytes_per_tick * - us_this_tick / (BTIF_A2DP_SOURCE_MEDIA_TIMER_MS * 1000); - - /* Calculate the number of frames pending for this media tick */ - projected_nof = btif_a2dp_source_cb.media_feeding_state.counter / pcm_bytes_per_frame; - if (projected_nof > btif_a2dp_source_cb.stats.media_read_max_expected_frames) - btif_a2dp_source_cb.stats.media_read_max_expected_frames = projected_nof; - btif_a2dp_source_cb.stats.media_read_total_expected_frames += projected_nof; - btif_a2dp_source_cb.stats.media_read_expected_count++; - if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) { - APPL_TRACE_WARNING("%s() - Limiting frames to be sent from %d to %d", - __func__, projected_nof, - MAX_PCM_FRAME_NUM_PER_TICK); - size_t delta = projected_nof - MAX_PCM_FRAME_NUM_PER_TICK; - btif_a2dp_source_cb.stats.media_read_limited_count++; - btif_a2dp_source_cb.stats.media_read_total_limited_frames += delta; - if (delta > btif_a2dp_source_cb.stats.media_read_max_limited_frames) - btif_a2dp_source_cb.stats.media_read_max_limited_frames = delta; - projected_nof = MAX_PCM_FRAME_NUM_PER_TICK; - } - - APPL_TRACE_DEBUG("%s: frames for available PCM data %u", - __func__, projected_nof); - - if (btif_av_is_peer_edr()) { - if (!btif_a2dp_source_cb.tx_sbc_frames) { - APPL_TRACE_ERROR("%s: tx_sbc_frames not updated, update from here", __func__); - btif_a2dp_source_cb.tx_sbc_frames = calculate_max_frames_per_packet(); - } - - nof = btif_a2dp_source_cb.tx_sbc_frames; - if (!nof) { - APPL_TRACE_ERROR("%s: number of frames not updated, set calculated values", - __func__); - nof = projected_nof; - noi = 1; - } else { - if (nof < projected_nof) { - noi = projected_nof / nof; // number of iterations would vary - if (noi > MAX_PCM_ITER_NUM_PER_TICK) { - APPL_TRACE_ERROR("%s ## Audio Congestion (iterations:%d > max (%d))", - __func__, noi, MAX_PCM_ITER_NUM_PER_TICK); - noi = MAX_PCM_ITER_NUM_PER_TICK; - btif_a2dp_source_cb.media_feeding_state.counter - = noi * nof * pcm_bytes_per_frame; - } - projected_nof = nof; - } else { - noi = 1; // number of iterations is 1 - APPL_TRACE_DEBUG("%s reducing frames for available PCM data", __func__); - nof = projected_nof; - } - } - } else { - // For BR cases nof will be same as the value retrieved at projected_nof - APPL_TRACE_DEBUG("%s headset BR, number of frames %u", - __func__, nof); - if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) { - APPL_TRACE_ERROR("%s ## Audio Congestion (frames: %d > max (%d))", - __func__, projected_nof, MAX_PCM_FRAME_NUM_PER_TICK); - projected_nof = MAX_PCM_FRAME_NUM_PER_TICK; - btif_a2dp_source_cb.media_feeding_state.counter = - noi * projected_nof * pcm_bytes_per_frame; - } - nof = projected_nof; - } - btif_a2dp_source_cb.media_feeding_state.counter -= noi * nof * pcm_bytes_per_frame; - APPL_TRACE_DEBUG("%s effective num of frames %u, iterations %u", - __func__, nof, noi); - } - break; - - default: - APPL_TRACE_ERROR("%s: Unsupported transcoding format 0x%x", - __func__, btif_a2dp_source_cb.TxTranscoding); - nof = 0; - noi = 0; - break; - } - *num_of_frames = nof; - *num_of_iterations = noi; -} - -static uint8_t calculate_max_frames_per_packet(void) -{ - uint16_t result = 0; - uint16_t effective_mtu_size = btif_a2dp_source_cb.TxAaMtuSize; - uint32_t frame_len; - - APPL_TRACE_DEBUG("%s original AVDTP MTU size: %d", - __func__, btif_a2dp_source_cb.TxAaMtuSize); - if (btif_av_is_peer_edr() && !btif_av_peer_supports_3mbps()) { - // This condition would be satisfied only if the remote device is - // EDR and supports only 2 Mbps, but the effective AVDTP MTU size - // exceeds the 2DH5 packet size. - APPL_TRACE_DEBUG("%s The remote devce is EDR but does not support 3 Mbps", __func__); - - if (effective_mtu_size > MAX_2MBPS_AVDTP_MTU) { - APPL_TRACE_WARNING("%s Restricting AVDTP MTU size to %d", - __func__, MAX_2MBPS_AVDTP_MTU); - effective_mtu_size = MAX_2MBPS_AVDTP_MTU; - btif_a2dp_source_cb.TxAaMtuSize = effective_mtu_size; - } - } - - if (!btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands) { - APPL_TRACE_ERROR("%s SubBands are set to 0, resetting to %d", - __func__, SBC_MAX_NUM_OF_SUBBANDS); - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS; - } - if (!btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks) { - APPL_TRACE_ERROR("%s Blocks are set to 0, resetting to %d", - __func__, SBC_MAX_NUM_OF_BLOCKS); - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS; - } - if (!btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels) { - APPL_TRACE_ERROR("%s Channels are set to 0, resetting to %d", - __func__, SBC_MAX_NUM_OF_CHANNELS); - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS; - } - - frame_len = get_frame_length(); - - APPL_TRACE_DEBUG("%s Effective Tx MTU to be considered: %d", - __func__, effective_mtu_size); - - switch (btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq) { - case SBC_sf44100: - if (frame_len == 0) { - APPL_TRACE_ERROR("%s Calculating frame length, \ - resetting it to default 119", __func__); - frame_len = MAX_SBC_HQ_FRAME_SIZE_44_1; - } - result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len; - APPL_TRACE_DEBUG("%s Max number of SBC frames: %d", - __func__, result); - break; - - case SBC_sf48000: - if (frame_len == 0) { - APPL_TRACE_ERROR("%s Calculating frame length, \ - resetting it to default 115", __func__); - frame_len = MAX_SBC_HQ_FRAME_SIZE_48; - } - result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len; - APPL_TRACE_DEBUG("%s Max number of SBC frames: %d", - __func__, result); - break; - - default: - APPL_TRACE_ERROR("%s Max number of SBC frames: %d", __func__, result); - break; - - } - return result; -} - -static uint32_t get_frame_length(void) -{ - uint32_t frame_len = 0; - APPL_TRACE_DEBUG("%s channel mode: %d, sub-band: %d, number of block: %d, \ - bitpool: %d, sampling frequency: %d, num channels: %d", - __func__, - btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode, - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands, - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks, - btif_a2dp_source_cb.sbc_encoder_params.s16BitPool, - btif_a2dp_source_cb.sbc_encoder_params.s16SamplingFreq, - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels); - - switch (btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode) { - case SBC_MONO: - /* FALLTHROUGH */ - case SBC_DUAL: - frame_len = SBC_FRAME_HEADER_SIZE_BYTES + - ((uint32_t)(SBC_SCALE_FACTOR_BITS * btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels) / CHAR_BIT) + - ((uint32_t)(btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels * - btif_a2dp_source_cb.sbc_encoder_params.s16BitPool) / CHAR_BIT); - break; - case SBC_STEREO: - frame_len = SBC_FRAME_HEADER_SIZE_BYTES + - ((uint32_t)(SBC_SCALE_FACTOR_BITS * btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels) / CHAR_BIT) + - ((uint32_t)(btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks * - btif_a2dp_source_cb.sbc_encoder_params.s16BitPool) / CHAR_BIT); - break; - case SBC_JOINT_STEREO: - frame_len = SBC_FRAME_HEADER_SIZE_BYTES + - ((uint32_t)(SBC_SCALE_FACTOR_BITS * btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands * - btif_a2dp_source_cb.sbc_encoder_params.s16NumOfChannels) / CHAR_BIT) + - ((uint32_t)(btif_a2dp_source_cb.sbc_encoder_params.s16NumOfSubBands + - (btif_a2dp_source_cb.sbc_encoder_params.s16NumOfBlocks * - btif_a2dp_source_cb.sbc_encoder_params.s16BitPool)) / CHAR_BIT); - break; - default: - APPL_TRACE_DEBUG("%s Invalid channel number: %d", - __func__, btif_a2dp_source_cb.sbc_encoder_params.s16ChannelMode); - break; - } - APPL_TRACE_DEBUG("%s calculated frame length: %d", __func__, frame_len); - return frame_len; -} - static void update_scheduling_stats(scheduling_stats_t *stats, uint64_t now_us, uint64_t expected_delta) { @@ -1676,26 +853,6 @@ void btif_a2dp_source_debug_dump(int fd) (unsigned long long)(now_us - stats->tx_queue_last_readbuf_us) / 1000 : 0); ave_size = 0; - if (stats->media_read_expected_count != 0) - ave_size = stats->media_read_total_expected_frames / stats->media_read_expected_count; - dprintf(fd, " Frames expected (total/max/ave) : %zu / %zu / %zu\n", - stats->media_read_total_expected_frames, - stats->media_read_max_expected_frames, - ave_size); - - ave_size = 0; - if (stats->media_read_limited_count != 0) - ave_size = stats->media_read_total_limited_frames / stats->media_read_limited_count; - dprintf(fd, " Frames limited (total/max/ave) : %zu / %zu / %zu\n", - stats->media_read_total_limited_frames, - stats->media_read_max_limited_frames, - ave_size); - - dprintf(fd, " Counts (expected/limited) : %zu / %zu\n", - stats->media_read_expected_count, - stats->media_read_limited_count); - - ave_size = 0; if (enqueue_stats->total_updates != 0) ave_size = stats->tx_queue_total_frames / enqueue_stats->total_updates; dprintf(fd, " Frames per packet (total/max/ave) : %zu / %zu / %zu\n", @@ -1708,25 +865,24 @@ void btif_a2dp_source_debug_dump(int fd) stats->tx_queue_total_dropped_messages, stats->tx_queue_dropouts); + dprintf(fd, " Counts (max dropped) : %zu\n", + stats->tx_queue_max_dropped_messages); + dprintf(fd, " Last update time ago in ms (flushed/dropped) : %llu / %llu\n", (stats->tx_queue_last_flushed_us > 0) ? (unsigned long long)(now_us - stats->tx_queue_last_flushed_us) / 1000 : 0, (stats->tx_queue_last_dropouts_us > 0)? (unsigned long long)(now_us - stats->tx_queue_last_dropouts_us)/ 1000 : 0); - dprintf(fd, " Counts (underflow/underrun) : %zu / %zu\n", - stats->media_read_total_underflow_count, - stats->media_read_total_underrun_count); + dprintf(fd, " Counts (underflow) : %zu\n", + stats->media_read_total_underflow_count); - dprintf(fd, " Bytes (underflow/underrun) : %zu / %zu\n", - stats->media_read_total_underflow_bytes, - stats->media_read_total_underrun_bytes); + dprintf(fd, " Bytes (underflow) : %zu\n", + stats->media_read_total_underflow_bytes); - dprintf(fd, " Last update time ago in ms (underflow/underrun) : %llu / %llu\n", + dprintf(fd, " Last update time ago in ms (underflow) : %llu\n", (stats->media_read_last_underflow_us > 0) ? - (unsigned long long)(now_us - stats->media_read_last_underflow_us) / 1000 : 0, - (stats->media_read_last_underrun_us > 0)? - (unsigned long long)(now_us - stats->media_read_last_underrun_us) / 1000 : 0); + (unsigned long long)(now_us - stats->media_read_last_underflow_us) / 1000 : 0); // // TxQueue enqueue stats @@ -1806,9 +962,9 @@ void btif_a2dp_source_update_metrics(void) uint32_t device_class = BTM_COD_MAJOR_AUDIO; if (dequeue_stats->total_updates > 1) { - media_timer_min_ms = BTIF_A2DP_SOURCE_MEDIA_TIMER_MS - + media_timer_min_ms = btif_a2dp_source_cb.encoder_interval_ms - (dequeue_stats->max_premature_scheduling_delta_us / 1000); - media_timer_max_ms = BTIF_A2DP_SOURCE_MEDIA_TIMER_MS + + media_timer_max_ms = btif_a2dp_source_cb.encoder_interval_ms + (dequeue_stats->max_overdue_scheduling_delta_us / 1000); uint64_t total_scheduling_count = @@ -1820,13 +976,12 @@ void btif_a2dp_source_update_metrics(void) (1000 * total_scheduling_count); } - buffer_overruns_max_count = stats->media_read_max_expected_frames; + buffer_overruns_max_count = stats->tx_queue_max_dropped_messages; buffer_overruns_total = stats->tx_queue_total_dropped_messages; - buffer_underruns_count = stats->media_read_total_underflow_count + - stats->media_read_total_underrun_count; + buffer_underruns_count = stats->media_read_total_underflow_count; if (buffer_underruns_count > 0) { buffer_underruns_average = - (stats->media_read_total_underflow_bytes + stats->media_read_total_underrun_bytes) / buffer_underruns_count; + stats->media_read_total_underflow_bytes / buffer_underruns_count; } } @@ -1836,3 +991,22 @@ void btif_a2dp_source_update_metrics(void) buffer_overruns_total, buffer_underruns_average, buffer_underruns_count); } + + +static void btm_read_rssi_cb(void *data) +{ + assert(data); + + tBTM_RSSI_RESULTS *result = (tBTM_RSSI_RESULTS *)data; + if (result->status != BTM_SUCCESS) { + LOG_ERROR(LOG_TAG, "%s unable to read remote RSSI (status %d)", + __func__, result->status); + return; + } + + char temp_buffer[20] = {0}; + LOG_WARN(LOG_TAG, "%s device: %s, rssi: %d", __func__, + bdaddr_to_string((bt_bdaddr_t *)result->rem_bda, temp_buffer, + sizeof(temp_buffer)), + result->rssi); +} diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc index 58602876e..56be6ee67 100644 --- a/btif/src/btif_av.cc +++ b/btif/src/btif_av.cc @@ -1285,7 +1285,7 @@ static bt_status_t init_sink(btav_callbacks_t* callbacks) static void update_audio_focus_state(int state) { BTIF_TRACE_DEBUG("%s: state %d",__func__, state); - btif_a2dp_sink_set_audio_focus_state_req((btif_a2dp_sink_audio_focus_state_t)state); + btif_a2dp_sink_set_focus_state_req((btif_a2dp_sink_focus_state_t)state); } /******************************************************************************* diff --git a/stack/Android.mk b/stack/Android.mk index 022b44f2e..5bbbcde23 100644 --- a/stack/Android.mk +++ b/stack/Android.mk @@ -38,6 +38,8 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := \ ./a2dp/a2d_api.c \ ./a2dp/a2d_sbc.c \ + ./a2dp/a2d_sbc_encoder.c \ + ./a2dp/a2d_sbc_up_sample.c \ ./a2dp/a2d_vendor.c \ ./avrc/avrc_api.c \ ./avrc/avrc_sdp.c \ diff --git a/stack/BUILD.gn b/stack/BUILD.gn index 14740321e..82be1b2da 100644 --- a/stack/BUILD.gn +++ b/stack/BUILD.gn @@ -18,6 +18,8 @@ static_library("stack") { sources = [ "a2dp/a2d_api.c", "a2dp/a2d_sbc.c", + "a2dp/a2d_sbc_encoder.c", + "a2dp/a2d_sbc_up_sample.c", "a2dp/a2d_vendor.c", "avrc/avrc_api.c", "avrc/avrc_sdp.c", diff --git a/stack/a2dp/a2d_api.c b/stack/a2dp/a2d_api.c index f13a769e5..f6934e64c 100644 --- a/stack/a2dp/a2d_api.c +++ b/stack/a2dp/a2d_api.c @@ -70,7 +70,7 @@ static void a2d_sdp_cback(uint16_t status) tA2D_Service a2d_svc; tSDP_PROTOCOL_ELEM elem; - LOG_DEBUG(LOG_TAG, "%s: status: %d", __func__, status); + LOG_VERBOSE(LOG_TAG, "%s: status: %d", __func__, status); if (status == SDP_SUCCESS) { @@ -112,7 +112,8 @@ static void a2d_sdp_cback(uint16_t status) if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem)) { a2d_svc.avdt_version = elem.params[0]; - LOG_DEBUG(LOG_TAG, "avdt_version: 0x%x", a2d_svc.avdt_version); + LOG_VERBOSE(LOG_TAG, "avdt_version: 0x%x", + a2d_svc.avdt_version); } /* we've got everything, we're done */ @@ -187,7 +188,7 @@ tA2D_STATUS A2D_AddRecord(uint16_t service_uuid, char *p_service_name, char *p_p uint8_t *p; tSDP_PROTOCOL_ELEM proto_list [A2D_NUM_PROTO_ELEMS]; - LOG_DEBUG(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid); + LOG_VERBOSE(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid); if( (sdp_handle == 0) || (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) ) @@ -289,7 +290,7 @@ tA2D_STATUS A2D_FindService(uint16_t service_uuid, BD_ADDR bd_addr, ATTR_ID_PROTOCOL_DESC_LIST, ATTR_ID_PROVIDER_NAME}; - LOG_DEBUG(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid); + LOG_VERBOSE(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid); if( (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) || p_db == NULL || p_cback == NULL) return A2D_INVALID_PARAMS; @@ -416,7 +417,7 @@ bool A2D_IsSourceCodecValid(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -434,7 +435,7 @@ bool A2D_IsSinkCodecValid(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -452,7 +453,7 @@ bool A2D_IsPeerSourceCodecValid(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -470,7 +471,7 @@ bool A2D_IsPeerSinkCodecValid(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -488,7 +489,7 @@ bool A2D_IsSourceCodecSupported(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -508,7 +509,7 @@ bool A2D_IsSinkCodecSupported(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -528,7 +529,7 @@ bool A2D_IsPeerSourceCodecSupported(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -549,11 +550,11 @@ void A2D_InitDefaultCodec(uint8_t *p_codec_info) A2D_InitDefaultCodecSbc(p_codec_info); } -bool A2D_SetCodec(const tA2D_AV_MEDIA_FEEDINGS *p_feeding, +bool A2D_SetCodec(const tA2D_FEEDING_PARAMS *p_feeding_params, uint8_t *p_codec_info) { // TODO: Needs to support vendor-specific codecs as well. - return A2D_SetCodecSbc(p_feeding, p_codec_info); + return A2D_SetCodecSbc(p_feeding_params, p_codec_info); } tA2D_STATUS A2D_BuildSrc2SinkConfig(const uint8_t *p_src_cap, @@ -561,7 +562,7 @@ tA2D_STATUS A2D_BuildSrc2SinkConfig(const uint8_t *p_src_cap, { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_src_cap); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -586,7 +587,7 @@ tA2D_STATUS A2D_BuildSinkConfig(const uint8_t *p_src_config, if (codec_type != A2D_GetCodecType(p_sink_cap)) return A2D_FAIL; - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -632,8 +633,8 @@ const char *A2D_CodecSepIndexStr(tA2D_CODEC_SEP_INDEX codec_sep_index) bool A2D_InitCodecConfig(tA2D_CODEC_SEP_INDEX codec_sep_index, tAVDT_CFG *p_cfg) { - LOG_DEBUG(LOG_TAG, "%s: codec %s", __func__, - A2D_CodecSepIndexStr(codec_sep_index)); + LOG_VERBOSE(LOG_TAG, "%s: codec %s", __func__, + A2D_CodecSepIndexStr(codec_sep_index)); /* Default: no content protection info */ p_cfg->num_protect = 0; @@ -661,7 +662,7 @@ const char *A2D_CodecName(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -775,7 +776,7 @@ int A2D_GetTrackFrequency(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -795,7 +796,7 @@ int A2D_GetTrackChannelCount(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -815,7 +816,7 @@ int A2D_GetNumberOfSubbands(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -835,7 +836,7 @@ int A2D_GetNumberOfBlocks(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -855,7 +856,7 @@ int A2D_GetAllocationMethodCode(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -875,7 +876,7 @@ int A2D_GetChannelModeCode(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -895,7 +896,7 @@ int A2D_GetSamplingFrequencyCode(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -915,7 +916,7 @@ int A2D_GetMinBitpool(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -935,7 +936,7 @@ int A2D_GetMaxBitpool(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -955,7 +956,7 @@ int A2D_GetSinkTrackChannelType(const uint8_t *p_codec_info) { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -976,7 +977,7 @@ int A2D_GetSinkFramesCountToProcess(uint64_t time_interval_ms, { tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); - LOG_DEBUG(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); switch (codec_type) { case A2D_MEDIA_CT_SBC: @@ -1032,3 +1033,24 @@ bool A2D_BuildCodecHeader(const uint8_t *p_codec_info, codec_type); return false; } + +const tA2D_ENCODER_INTERFACE *A2D_GetEncoderInterface( + const uint8_t *p_codec_info) +{ + tA2D_CODEC_TYPE codec_type = A2D_GetCodecType(p_codec_info); + + LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type); + + switch (codec_type) { + case A2D_MEDIA_CT_SBC: + return A2D_GetEncoderInterfaceSbc(p_codec_info); + case A2D_MEDIA_CT_NON_A2DP: + return A2D_VendorGetEncoderInterface(p_codec_info); + default: + break; + } + + LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, + codec_type); + return NULL; +} diff --git a/stack/a2dp/a2d_sbc.c b/stack/a2dp/a2d_sbc.c index fcc296bcc..ed672d1ef 100644 --- a/stack/a2dp/a2d_sbc.c +++ b/stack/a2dp/a2d_sbc.c @@ -31,6 +31,7 @@ #include "a2d_api.h" #include "a2d_int.h" #include "a2d_sbc.h" +#include "a2d_sbc_encoder.h" #include "bt_utils.h" #include "embdrv/sbc/encoder/include/sbc_encoder.h" #include "osi/include/log.h" @@ -89,6 +90,17 @@ const tA2D_SBC_CIE a2d_sbc_default_config = A2D_SBC_MAX_BITPOOL /* max_bitpool */ }; +static const tA2D_ENCODER_INTERFACE a2d_encoder_interface_sbc = { + a2d_sbc_encoder_init, + a2d_sbc_encoder_update, + a2d_sbc_encoder_cleanup, + a2d_sbc_feeding_init, + a2d_sbc_feeding_reset, + a2d_sbc_feeding_flush, + a2d_sbc_get_encoder_interval_ms, + a2d_sbc_send_frames +}; + static tA2D_STATUS A2D_CodecInfoMatchesCapabilitySbc( const tA2D_SBC_CIE *p_cap, const uint8_t *p_codec_info, @@ -367,30 +379,31 @@ void A2D_InitDefaultCodecSbc(uint8_t *p_codec_info) } } -bool A2D_SetCodecSbc(const tA2D_AV_MEDIA_FEEDINGS *p_feeding, +bool A2D_SetCodecSbc(const tA2D_FEEDING_PARAMS *p_feeding_params, uint8_t *p_codec_info) { tA2D_SBC_CIE sbc_config = a2d_sbc_default_config; - LOG_DEBUG(LOG_TAG, "%s", __func__); + LOG_VERBOSE(LOG_TAG, "%s", __func__); /* Check the number of channels */ - if ((p_feeding->num_channel != 1) && (p_feeding->num_channel != 2)) { + if ((p_feeding_params->num_channel != 1) && + (p_feeding_params->num_channel != 2)) { LOG_ERROR(LOG_TAG, "%s: Unsupported PCM channel number %d", - __func__, p_feeding->num_channel); + __func__, p_feeding_params->num_channel); return false; } /* Check the bits per sample */ - if ((p_feeding->bit_per_sample != 8) && - (p_feeding->bit_per_sample != 16)) { + if ((p_feeding_params->bit_per_sample != 8) && + (p_feeding_params->bit_per_sample != 16)) { LOG_ERROR(LOG_TAG, "%s: Unsupported PCM sample size %d", - __func__, p_feeding->bit_per_sample); + __func__, p_feeding_params->bit_per_sample); return false; } /* Check the sampling frequency */ - switch (p_feeding->sampling_freq) { + switch (p_feeding_params->sampling_freq) { case 8000: case 12000: case 16000: @@ -406,7 +419,7 @@ bool A2D_SetCodecSbc(const tA2D_AV_MEDIA_FEEDINGS *p_feeding, break; default: LOG_ERROR(LOG_TAG, "%s: Unsupported PCM sampling frequency %d", - __func__, p_feeding->sampling_freq); + __func__, p_feeding_params->sampling_freq); return false; } @@ -712,14 +725,14 @@ bool A2D_CodecConfigMatchesCapabilitiesSbc(const uint8_t *p_codec_config, (sbc_cie_config.alloc_method & sbc_cie_caps.alloc_method); LOG_DEBUG(LOG_TAG, "%s: result=%s", __func__, result ? "true" : "false"); - LOG_DEBUG(LOG_TAG, "%s: config samp_freq=0x%x ch_mode=0x%x block_len=0x%x " - "num_subbands=0x%x alloc_method=0x%x", + LOG_DEBUG(LOG_TAG, "%s: config samp_freq=0x%x ch_mode=0x%x " + "block_len=0x%x num_subbands=0x%x alloc_method=0x%x", __func__, sbc_cie_config.samp_freq, sbc_cie_config.ch_mode, sbc_cie_config.block_len, sbc_cie_config.num_subbands, sbc_cie_config.alloc_method); - LOG_DEBUG(LOG_TAG, "%s: caps samp_freq=0x%x ch_mode=0x%x block_len=0x%x " - "num_subbands=0x%x alloc_method=0x%x", + LOG_DEBUG(LOG_TAG, "%s: caps samp_freq=0x%x ch_mode=0x%x " + "block_len=0x%x num_subbands=0x%x alloc_method=0x%x", __func__, sbc_cie_caps.samp_freq, sbc_cie_caps.ch_mode, sbc_cie_caps.block_len, sbc_cie_caps.num_subbands, @@ -979,23 +992,23 @@ int A2D_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms, // Check the sample frequency switch (sbc_cie.samp_freq) { case A2D_SBC_IE_SAMP_FREQ_16: - LOG_DEBUG(LOG_TAG, "%s: samp_freq:%d (16000)", __func__, - sbc_cie.samp_freq); + LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (16000)", __func__, + sbc_cie.samp_freq); freq_multiple = 16 * time_interval_ms; break; case A2D_SBC_IE_SAMP_FREQ_32: - LOG_DEBUG(LOG_TAG, "%s: samp_freq:%d (32000)", __func__, - sbc_cie.samp_freq); + LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (32000)", __func__, + sbc_cie.samp_freq); freq_multiple = 32 * time_interval_ms; break; case A2D_SBC_IE_SAMP_FREQ_44: - LOG_DEBUG(LOG_TAG, "%s: samp_freq:%d (44100)", __func__, - sbc_cie.samp_freq); + LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (44100)", __func__, + sbc_cie.samp_freq); freq_multiple = (441 * time_interval_ms) / 10; break; case A2D_SBC_IE_SAMP_FREQ_48: - LOG_DEBUG(LOG_TAG, "%s: samp_freq:%d (48000)", __func__, - sbc_cie.samp_freq); + LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (48000)", __func__, + sbc_cie.samp_freq); freq_multiple = 48 * time_interval_ms; break; default: @@ -1007,20 +1020,20 @@ int A2D_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms, // Check the channel mode switch (sbc_cie.ch_mode) { case A2D_SBC_IE_CH_MD_MONO: - LOG_DEBUG(LOG_TAG, "%s: ch_mode:%d (Mono)", __func__, - sbc_cie.ch_mode); + LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (Mono)", __func__, + sbc_cie.ch_mode); break; case A2D_SBC_IE_CH_MD_DUAL: - LOG_DEBUG(LOG_TAG, "%s: ch_mode:%d (DUAL)", __func__, - sbc_cie.ch_mode); + LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (DUAL)", __func__, + sbc_cie.ch_mode); break; case A2D_SBC_IE_CH_MD_STEREO: - LOG_DEBUG(LOG_TAG, "%s: ch_mode:%d (STEREO)", __func__, - sbc_cie.ch_mode); + LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (STEREO)", __func__, + sbc_cie.ch_mode); break; case A2D_SBC_IE_CH_MD_JOINT: - LOG_DEBUG(LOG_TAG, "%s: ch_mode:%d (JOINT)", __func__, - sbc_cie.ch_mode); + LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (JOINT)", __func__, + sbc_cie.ch_mode); break; default: LOG_ERROR(LOG_TAG, "%s: unknown channel mode: %d", __func__, @@ -1031,23 +1044,23 @@ int A2D_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms, // Check the block length switch (sbc_cie.block_len) { case A2D_SBC_IE_BLOCKS_4: - LOG_DEBUG(LOG_TAG, "%s: block_len:%d (4)", __func__, - sbc_cie.block_len); + LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (4)", __func__, + sbc_cie.block_len); num_blocks = 4; break; case A2D_SBC_IE_BLOCKS_8: - LOG_DEBUG(LOG_TAG, "%s: block_len:%d (8)", __func__, - sbc_cie.block_len); + LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (8)", __func__, + sbc_cie.block_len); num_blocks = 8; break; case A2D_SBC_IE_BLOCKS_12: - LOG_DEBUG(LOG_TAG, "%s: block_len:%d (12)", __func__, - sbc_cie.block_len); + LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (12)", __func__, + sbc_cie.block_len); num_blocks = 12; break; case A2D_SBC_IE_BLOCKS_16: - LOG_DEBUG(LOG_TAG, "%s: block_len:%d (16)", __func__, - sbc_cie.block_len); + LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (16)", __func__, + sbc_cie.block_len); num_blocks = 16; break; default: @@ -1059,13 +1072,13 @@ int A2D_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms, // Check the number of sub-bands switch (sbc_cie.num_subbands) { case A2D_SBC_IE_SUBBAND_4: - LOG_DEBUG(LOG_TAG, "%s: num_subbands:%d (4)", __func__, - sbc_cie.num_subbands); + LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (4)", __func__, + sbc_cie.num_subbands); num_subbands = 4; break; case A2D_SBC_IE_SUBBAND_8: - LOG_DEBUG(LOG_TAG, "%s: num_subbands:%d (8)", __func__, - sbc_cie.num_subbands); + LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (8)", __func__, + sbc_cie.num_subbands); num_subbands = 8; break; default: @@ -1077,12 +1090,12 @@ int A2D_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms, // Check the allocation method switch (sbc_cie.alloc_method) { case A2D_SBC_IE_ALLOC_MD_S: - LOG_DEBUG(LOG_TAG, "%s: alloc_method:%d (SNR)", __func__, - sbc_cie.alloc_method); + LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (SNR)", __func__, + sbc_cie.alloc_method); break; case A2D_SBC_IE_ALLOC_MD_L: - LOG_DEBUG(LOG_TAG, "%s: alloc_method:%d (Loudness)", __func__, - sbc_cie.alloc_method); + LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (Loudness)", __func__, + sbc_cie.alloc_method); break; default: LOG_ERROR(LOG_TAG, "%s: unknown allocation method: %d", __func__, @@ -1090,8 +1103,8 @@ int A2D_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms, return -1; } - LOG_DEBUG(LOG_TAG, "%s: Bit pool Min:%d Max:%d", __func__, - sbc_cie.min_bitpool, sbc_cie.max_bitpool); + LOG_VERBOSE(LOG_TAG, "%s: Bit pool Min:%d Max:%d", __func__, + sbc_cie.min_bitpool, sbc_cie.max_bitpool); frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1; @@ -1187,3 +1200,12 @@ void A2D_DumpCodecInfoSbc(const uint8_t *p_codec_info) LOG_DEBUG(LOG_TAG, "\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool, sbc_cie.max_bitpool); } + +const tA2D_ENCODER_INTERFACE *A2D_GetEncoderInterfaceSbc( + const uint8_t *p_codec_info) +{ + if (!A2D_IsSourceCodecValidSbc(p_codec_info)) + return NULL; + + return &a2d_encoder_interface_sbc; +} diff --git a/stack/a2dp/a2d_sbc_encoder.c b/stack/a2dp/a2d_sbc_encoder.c new file mode 100644 index 000000000..fcd2859dd --- /dev/null +++ b/stack/a2dp/a2d_sbc_encoder.c @@ -0,0 +1,880 @@ +/****************************************************************************** + * + * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#define LOG_TAG "a2d_sbc_encoder" + +#include + +#include "bt_target.h" +#include "bt_common.h" +#include "a2d_api.h" +#include "a2d_sbc.h" +#include "a2d_sbc_encoder.h" +#include "a2d_sbc_up_sample.h" +#include "avdt_api.h" +#include "embdrv/sbc/encoder/include/sbc_encoder.h" +#include "osi/include/log.h" + +/* Buffer pool */ +#define A2D_SBC_BUFFER_SIZE BT_DEFAULT_BUFFER_SIZE + +// A2DP SBC encoder interval in milliseconds. +#define A2D_SBC_ENCODER_INTERVAL_MS 20 + +/* High quality quality setting @ 44.1 khz */ +#define A2D_SBC_DEFAULT_BITRATE 328 + +#define A2D_SBC_NON_EDR_MAX_RATE 229 + +/* + * 2DH5 payload size of: + * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header) + */ +#define MAX_2MBPS_AVDTP_MTU 663 +#define A2D_SBC_MAX_PCM_ITER_NUM_PER_TICK 3 + +#define A2D_SBC_MAX_HQ_FRAME_SIZE_44_1 119 +#define A2D_SBC_MAX_HQ_FRAME_SIZE_48 115 + +/* Define the bitrate step when trying to match bitpool value */ +#define A2D_SBC_BITRATE_STEP 5 + +/* Readability constants */ +#define A2D_SBC_FRAME_HEADER_SIZE_BYTES 4 // A2DP Spec v1.3, 12.4, Table 12.12 +#define A2D_SBC_SCALE_FACTOR_BITS 4 // A2DP Spec v1.3, 12.4, Table 12.13 + +/* offset */ +#if (BTA_AV_CO_CP_SCMS_T == TRUE) +/* A2DP header will contain a CP header of size 1 */ +#define A2DP_HDR_SIZE 2 +#define A2D_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2D_SBC_MPL_HDR_LEN + 1) +#else +#define A2DP_HDR_SIZE 1 +#define A2D_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2D_SBC_MPL_HDR_LEN) +#endif + +typedef struct { + uint32_t aa_frame_counter; + int32_t aa_feed_counter; + int32_t aa_feed_residue; + uint32_t counter; + uint32_t bytes_per_tick; /* pcm bytes read each media task tick */ + uint64_t last_frame_us; +} tA2D_FEEDING_STATE; + +typedef struct { + a2d_source_read_callback_t read_callback; + a2d_source_enqueue_callback_t enqueue_callback; + uint16_t TxAaMtuSize; + uint8_t tx_sbc_frames; + bool is_peer_edr; /* True if the peer device supports EDR */ + bool peer_supports_3mbps; /* True if the peer device supports 3Mbps EDR */ + uint32_t timestamp; /* Timestamp for the A2DP frames */ + SBC_ENC_PARAMS sbc_encoder_params; + tA2D_FEEDING_PARAMS feeding_params; + tA2D_FEEDING_STATE feeding_state; +} tA2D_SBC_ENCODER_CB; + +static tA2D_SBC_ENCODER_CB a2d_sbc_encoder_cb; + +static bool a2d_sbc_read_feeding(void); +static void a2d_sbc_encode_frames(uint8_t nb_frame); +static void a2d_sbc_get_num_frame_iteration(uint8_t *num_of_iterations, + uint8_t *num_of_frames, + uint64_t timestamp_us); +static uint8_t calculate_max_frames_per_packet(void); +static uint16_t a2d_sbc_source_rate(void); +static uint32_t a2d_sbc_frame_length(void); + +void a2d_sbc_encoder_init(bool is_peer_edr, bool peer_supports_3mbps, + const tA2D_ENCODER_INIT_PARAMS *p_init_params, + a2d_source_read_callback_t read_callback, + a2d_source_enqueue_callback_t enqueue_callback) +{ + SBC_ENC_PARAMS *p_encoder_params = &a2d_sbc_encoder_cb.sbc_encoder_params; + + memset(&a2d_sbc_encoder_cb, 0, sizeof(a2d_sbc_encoder_cb)); + + a2d_sbc_encoder_cb.read_callback = read_callback; + a2d_sbc_encoder_cb.enqueue_callback = enqueue_callback; + a2d_sbc_encoder_cb.is_peer_edr = is_peer_edr; + a2d_sbc_encoder_cb.peer_supports_3mbps = peer_supports_3mbps; + a2d_sbc_encoder_cb.timestamp = 0; + + /* SBC encoder config (enforced even if not used) */ + p_encoder_params->s16ChannelMode = p_init_params->ChannelMode; + p_encoder_params->s16NumOfSubBands = p_init_params->NumOfSubBands; + p_encoder_params->s16NumOfBlocks = p_init_params->NumOfBlocks; + p_encoder_params->s16AllocationMethod = p_init_params->AllocationMethod; + p_encoder_params->s16SamplingFreq = p_init_params->SamplingFreq; + + p_encoder_params->u16BitRate = a2d_sbc_source_rate(); + + uint16_t mtu_size = A2D_SBC_BUFFER_SIZE - A2D_SBC_OFFSET - sizeof(BT_HDR); + if (mtu_size < p_init_params->MtuSize) { + a2d_sbc_encoder_cb.TxAaMtuSize = mtu_size; + } else { + a2d_sbc_encoder_cb.TxAaMtuSize = p_init_params->MtuSize; + } + + LOG_DEBUG(LOG_TAG, "%s: mtu %d, peer mtu %d", __func__, + a2d_sbc_encoder_cb.TxAaMtuSize, p_init_params->MtuSize); + LOG_DEBUG(LOG_TAG, "%s: ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d", + __func__, + p_encoder_params->s16ChannelMode, + p_encoder_params->s16NumOfSubBands, + p_encoder_params->s16NumOfBlocks, + p_encoder_params->s16AllocationMethod, + p_encoder_params->u16BitRate, + p_encoder_params->s16SamplingFreq); + + /* Reset entirely the SBC encoder */ + SBC_Encoder_Init(&a2d_sbc_encoder_cb.sbc_encoder_params); + a2d_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet(); + + LOG_DEBUG(LOG_TAG, "%s: bit pool %d", __func__, + p_encoder_params->s16BitPool); +} + +void a2d_sbc_encoder_update(const tA2D_ENCODER_UPDATE_PARAMS *p_update_params) +{ + SBC_ENC_PARAMS *p_encoder_params = &a2d_sbc_encoder_cb.sbc_encoder_params; + uint16_t s16SamplingFreq; + int16_t s16BitPool = 0; + int16_t s16BitRate; + int16_t s16FrameLen; + uint8_t protect = 0; + + LOG_DEBUG(LOG_TAG, "%s: minmtu %d, maxbp %d minbp %d", __func__, + p_update_params->MinMtuSize, p_update_params->MaxBitPool, + p_update_params->MinBitPool); + + if (!p_encoder_params->s16NumOfSubBands) { + LOG_WARN(LOG_TAG, "%s: SubBands are set to 0, resetting to max (%d)", + __func__, SBC_MAX_NUM_OF_SUBBANDS); + p_encoder_params->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS; + } + + if (!p_encoder_params->s16NumOfBlocks) { + LOG_WARN(LOG_TAG, "%s: Blocks are set to 0, resetting to max (%d)", + __func__, SBC_MAX_NUM_OF_BLOCKS); + p_encoder_params->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS; + } + + if (!p_encoder_params->s16NumOfChannels) { + LOG_WARN(LOG_TAG, "%s: Channels are set to 0, resetting to max (%d)", + __func__, SBC_MAX_NUM_OF_CHANNELS); + p_encoder_params->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS; + } + + uint16_t mtu_size = A2D_SBC_BUFFER_SIZE - A2D_SBC_OFFSET - sizeof(BT_HDR); + if (mtu_size < p_update_params->MinMtuSize) { + a2d_sbc_encoder_cb.TxAaMtuSize = mtu_size; + } else { + a2d_sbc_encoder_cb.TxAaMtuSize = p_update_params->MinMtuSize; + } + + /* Set the initial target bit rate */ + p_encoder_params->u16BitRate = a2d_sbc_source_rate(); + + if (p_encoder_params->s16SamplingFreq == SBC_sf16000) + s16SamplingFreq = 16000; + else if (p_encoder_params->s16SamplingFreq == SBC_sf32000) + s16SamplingFreq = 32000; + else if (p_encoder_params->s16SamplingFreq == SBC_sf44100) + s16SamplingFreq = 44100; + else + s16SamplingFreq = 48000; + + do { + if (p_encoder_params->s16NumOfBlocks == 0 || + p_encoder_params->s16NumOfSubBands == 0 || + p_encoder_params->s16NumOfChannels == 0) { + LOG_ERROR(LOG_TAG, "%s: avoiding division by zero...", __func__); + LOG_ERROR(LOG_TAG, "%s: block=%d, subBands=%d, channels=%d", + __func__, + p_encoder_params->s16NumOfBlocks, + p_encoder_params->s16NumOfSubBands, + p_encoder_params->s16NumOfChannels); + break; + } + + if ((p_encoder_params->s16ChannelMode == SBC_JOINT_STEREO) || + (p_encoder_params->s16ChannelMode == SBC_STEREO)) { + s16BitPool = (int16_t)((p_encoder_params->u16BitRate * + p_encoder_params->s16NumOfSubBands * 1000 / s16SamplingFreq) + - ((32 + (4 * p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfChannels) + + ((p_encoder_params->s16ChannelMode - 2) * + p_encoder_params->s16NumOfSubBands)) + / p_encoder_params->s16NumOfBlocks)); + + s16FrameLen = 4 + (4*p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfChannels) / 8 + + (((p_encoder_params->s16ChannelMode - 2) * + p_encoder_params->s16NumOfSubBands) + + (p_encoder_params->s16NumOfBlocks * s16BitPool)) / 8; + + s16BitRate = (8 * s16FrameLen * s16SamplingFreq) + / (p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfBlocks * 1000); + + if (s16BitRate > p_encoder_params->u16BitRate) + s16BitPool--; + + if (p_encoder_params->s16NumOfSubBands == 8) + s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool; + else + s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool; + } else { + s16BitPool = (int16_t)(((p_encoder_params->s16NumOfSubBands * + p_encoder_params->u16BitRate * 1000) + / (s16SamplingFreq * p_encoder_params->s16NumOfChannels)) + - (((32 / p_encoder_params->s16NumOfChannels) + + (4 * p_encoder_params->s16NumOfSubBands)) + / p_encoder_params->s16NumOfBlocks)); + + p_encoder_params->s16BitPool = + (s16BitPool > (16 * p_encoder_params->s16NumOfSubBands)) ? + (16 * p_encoder_params->s16NumOfSubBands) : s16BitPool; + } + + if (s16BitPool < 0) + s16BitPool = 0; + + LOG_DEBUG(LOG_TAG, "%s: bitpool candidate: %d (%d kbps)", __func__, + s16BitPool, p_encoder_params->u16BitRate); + + if (s16BitPool > p_update_params->MaxBitPool) { + LOG_DEBUG(LOG_TAG, "%s: computed bitpool too large (%d)", + __func__, s16BitPool); + /* Decrease bitrate */ + p_encoder_params->u16BitRate -= A2D_SBC_BITRATE_STEP; + /* Record that we have decreased the bitrate */ + protect |= 1; + } else if (s16BitPool < p_update_params->MinBitPool) { + LOG_WARN(LOG_TAG, "%s: computed bitpool too small (%d)", __func__, + s16BitPool); + + /* Increase bitrate */ + uint16_t previous_u16BitRate = p_encoder_params->u16BitRate; + p_encoder_params->u16BitRate += A2D_SBC_BITRATE_STEP; + /* Record that we have increased the bitrate */ + protect |= 2; + /* Check over-flow */ + if (p_encoder_params->u16BitRate < previous_u16BitRate) + protect |= 3; + } else { + break; + } + /* In case we have already increased and decreased the bitrate, just stop */ + if (protect == 3) { + LOG_ERROR(LOG_TAG, "%s: could not find bitpool in range", + __func__); + break; + } + } while (true); + + /* Finally update the bitpool in the encoder structure */ + p_encoder_params->s16BitPool = s16BitPool; + + LOG_DEBUG(LOG_TAG, "%s: final bit rate %d, final bit pool %d", __func__, + p_encoder_params->u16BitRate, p_encoder_params->s16BitPool); + + /* make sure we reinitialize encoder with new settings */ + SBC_Encoder_Init(&a2d_sbc_encoder_cb.sbc_encoder_params); + + a2d_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet(); +} + +void a2d_sbc_encoder_cleanup(void) +{ + memset(&a2d_sbc_encoder_cb, 0, sizeof(a2d_sbc_encoder_cb)); +} + +void a2d_sbc_feeding_init(const tA2D_FEEDING_PARAMS *p_feeding_params) +{ + SBC_ENC_PARAMS *p_encoder_params = &a2d_sbc_encoder_cb.sbc_encoder_params; + bool reconfig_needed = false; + + LOG_DEBUG(LOG_TAG, "%s: PCM feeding: sampling_freq:%d num_channel:%d bit_per_sample:%d", + __func__, + p_feeding_params->sampling_freq, + p_feeding_params->num_channel, + p_feeding_params->bit_per_sample); + + /* Save the feeding information */ + memcpy(&a2d_sbc_encoder_cb.feeding_params, p_feeding_params, + sizeof(tA2D_FEEDING_PARAMS)); + + /* Check the PCM feeding sampling_freq */ + switch (p_feeding_params->sampling_freq) { + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 48000: + /* For these sampling_freq the AV connection must be 48000 */ + if (p_encoder_params->s16SamplingFreq != SBC_sf48000) { + /* Reconfiguration needed at 48000 */ + LOG_DEBUG(LOG_TAG, "%s: SBC Reconfiguration needed at 48000", + __func__); + p_encoder_params->s16SamplingFreq = SBC_sf48000; + reconfig_needed = true; + } + break; + + case 11025: + case 22050: + case 44100: + /* For these sampling_freq the AV connection must be 44100 */ + if (p_encoder_params->s16SamplingFreq != SBC_sf44100) { + /* Reconfiguration needed at 44100 */ + LOG_DEBUG(LOG_TAG, "%s: SBC Reconfiguration needed at 44100", + __func__); + p_encoder_params->s16SamplingFreq = SBC_sf44100; + reconfig_needed = true; + } + break; + default: + LOG_DEBUG(LOG_TAG, "%s: Feeding PCM sampling_freq unsupported", + __func__); + break; + } + + /* Some AV Headsets do not support Mono => always ask for Stereo */ + if (p_encoder_params->s16ChannelMode == SBC_MONO) { + LOG_DEBUG(LOG_TAG, "%s: SBC Reconfiguration needed in Stereo", + __func__); + p_encoder_params->s16ChannelMode = SBC_JOINT_STEREO; + reconfig_needed = true; + } + + if (reconfig_needed) { + LOG_DEBUG(LOG_TAG, "%s: mtu %d ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d", + __func__, + a2d_sbc_encoder_cb.TxAaMtuSize, + p_encoder_params->s16ChannelMode, + p_encoder_params->s16NumOfSubBands, + p_encoder_params->s16NumOfBlocks, + p_encoder_params->s16AllocationMethod, + p_encoder_params->u16BitRate, + p_encoder_params->s16SamplingFreq); + SBC_Encoder_Init(p_encoder_params); + } else { + LOG_DEBUG(LOG_TAG, "%s: no SBC reconfig needed", __func__); + } +} + +void a2d_sbc_feeding_reset(void) +{ + /* By default, just clear the entire state */ + memset(&a2d_sbc_encoder_cb.feeding_state, 0, + sizeof(a2d_sbc_encoder_cb.feeding_state)); + + a2d_sbc_encoder_cb.feeding_state.bytes_per_tick = + (a2d_sbc_encoder_cb.feeding_params.sampling_freq * + a2d_sbc_encoder_cb.feeding_params.bit_per_sample / 8 * + a2d_sbc_encoder_cb.feeding_params.num_channel * + A2D_SBC_ENCODER_INTERVAL_MS) / 1000; + + LOG_DEBUG(LOG_TAG, "%s: PCM bytes per tick %u", + __func__, a2d_sbc_encoder_cb.feeding_state.bytes_per_tick); +} + +void a2d_sbc_feeding_flush(void) +{ + a2d_sbc_encoder_cb.feeding_state.counter = 0; + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue = 0; +} + +period_ms_t a2d_sbc_get_encoder_interval_ms(void) +{ + return A2D_SBC_ENCODER_INTERVAL_MS; +} + +void a2d_sbc_send_frames(uint64_t timestamp_us) +{ + uint8_t nb_frame = 0; + uint8_t nb_iterations = 0; + + a2d_sbc_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us); + LOG_VERBOSE(LOG_TAG, "%s: Sending %d frames per iteration, %d iterations", + __func__, nb_frame, nb_iterations); + if (nb_frame == 0) + return; + + for (uint8_t counter = 0; counter < nb_iterations; counter++) { + // Transcode frame and enqueue + a2d_sbc_encode_frames(nb_frame); + } +} + +// Obtains the number of frames to send and number of iterations +// to be used. |num_of_iterations| and |num_of_frames| parameters +// are used as output param for returning the respective values. +static void a2d_sbc_get_num_frame_iteration(uint8_t *num_of_iterations, + uint8_t *num_of_frames, + uint64_t timestamp_us) +{ + uint8_t nof = 0; + uint8_t noi = 1; + + uint32_t projected_nof = 0; + uint32_t pcm_bytes_per_frame = + a2d_sbc_encoder_cb.sbc_encoder_params.s16NumOfSubBands * + a2d_sbc_encoder_cb.sbc_encoder_params.s16NumOfBlocks * + a2d_sbc_encoder_cb.feeding_params.num_channel * + a2d_sbc_encoder_cb.feeding_params.bit_per_sample / 8; + LOG_VERBOSE(LOG_TAG, "%s: pcm_bytes_per_frame %u", __func__, + pcm_bytes_per_frame); + + uint32_t us_this_tick = A2D_SBC_ENCODER_INTERVAL_MS * 1000; + uint64_t now_us = timestamp_us; + if (a2d_sbc_encoder_cb.feeding_state.last_frame_us != 0) + us_this_tick = (now_us - a2d_sbc_encoder_cb.feeding_state.last_frame_us); + a2d_sbc_encoder_cb.feeding_state.last_frame_us = now_us; + + a2d_sbc_encoder_cb.feeding_state.counter += + a2d_sbc_encoder_cb.feeding_state.bytes_per_tick * + us_this_tick / (A2D_SBC_ENCODER_INTERVAL_MS * 1000); + + /* Calculate the number of frames pending for this media tick */ + projected_nof = a2d_sbc_encoder_cb.feeding_state.counter / pcm_bytes_per_frame; + + if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) { + LOG_WARN(LOG_TAG, "%s: limiting frames to be sent from %d to %d", + __func__, projected_nof, MAX_PCM_FRAME_NUM_PER_TICK); + projected_nof = MAX_PCM_FRAME_NUM_PER_TICK; + } + + LOG_VERBOSE(LOG_TAG, "%s: frames for available PCM data %u", + __func__, projected_nof); + + if (a2d_sbc_encoder_cb.is_peer_edr) { + if (!a2d_sbc_encoder_cb.tx_sbc_frames) { + LOG_ERROR(LOG_TAG, "%s: tx_sbc_frames not updated, update from here", + __func__); + a2d_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet(); + } + + nof = a2d_sbc_encoder_cb.tx_sbc_frames; + if (!nof) { + LOG_ERROR(LOG_TAG, "%s: number of frames not updated, set calculated values", + __func__); + nof = projected_nof; + noi = 1; + } else { + if (nof < projected_nof) { + noi = projected_nof / nof; // number of iterations would vary + if (noi > A2D_SBC_MAX_PCM_ITER_NUM_PER_TICK) { + LOG_ERROR(LOG_TAG, "%s: Audio Congestion (iterations:%d > max (%d))", + __func__, noi, A2D_SBC_MAX_PCM_ITER_NUM_PER_TICK); + noi = A2D_SBC_MAX_PCM_ITER_NUM_PER_TICK; + a2d_sbc_encoder_cb.feeding_state.counter + = noi * nof * pcm_bytes_per_frame; + } + projected_nof = nof; + } else { + noi = 1; // number of iterations is 1 + LOG_VERBOSE(LOG_TAG, "%s: reducing frames for available PCM data", + __func__); + nof = projected_nof; + } + } + } else { + // For BR cases nof will be same as the value retrieved at projected_nof + LOG_VERBOSE(LOG_TAG, "%s: headset BR, number of frames %u", + __func__, nof); + if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) { + LOG_ERROR(LOG_TAG, "%s: Audio Congestion (frames: %d > max (%d))", + __func__, projected_nof, MAX_PCM_FRAME_NUM_PER_TICK); + projected_nof = MAX_PCM_FRAME_NUM_PER_TICK; + a2d_sbc_encoder_cb.feeding_state.counter = + noi * projected_nof * pcm_bytes_per_frame; + } + nof = projected_nof; + } + a2d_sbc_encoder_cb.feeding_state.counter -= noi * nof * pcm_bytes_per_frame; + LOG_VERBOSE(LOG_TAG, "%s: effective num of frames %u, iterations %u", + __func__, nof, noi); + + *num_of_frames = nof; + *num_of_iterations = noi; +} + +static void a2d_sbc_encode_frames(uint8_t nb_frame) +{ + SBC_ENC_PARAMS *p_encoder_params = &a2d_sbc_encoder_cb.sbc_encoder_params; + uint8_t remain_nb_frame = nb_frame; + uint16_t blocm_x_subband = p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfBlocks; + + while (nb_frame) { + BT_HDR *p_buf = (BT_HDR *)osi_malloc(A2D_SBC_BUFFER_SIZE); + + /* Init buffer */ + p_buf->offset = A2D_SBC_OFFSET; + p_buf->len = 0; + p_buf->layer_specific = 0; + + do { + /* Write @ of allocated buffer in sbc_encoder_params.pu8Packet */ + p_encoder_params->pu8Packet = + (uint8_t *) (p_buf + 1) + p_buf->offset + p_buf->len; + /* Fill allocated buffer with 0 */ + memset(p_encoder_params->as16PcmBuffer, 0, + blocm_x_subband * p_encoder_params->s16NumOfChannels); + + /* Read PCM data and upsample them if needed */ + if (a2d_sbc_read_feeding()) { + SBC_Encoder(p_encoder_params); + + /* Update SBC frame length */ + p_buf->len += p_encoder_params->u16PacketLength; + nb_frame--; + p_buf->layer_specific++; + } else { + LOG_WARN(LOG_TAG, "%s: underflow %d, %d", + __func__, nb_frame, + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue); + a2d_sbc_encoder_cb.feeding_state.counter += + nb_frame * + p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfBlocks * + a2d_sbc_encoder_cb.feeding_params.num_channel * + a2d_sbc_encoder_cb.feeding_params.bit_per_sample / 8; + /* no more pcm to read */ + nb_frame = 0; + } + } while (((p_buf->len + p_encoder_params->u16PacketLength) < + a2d_sbc_encoder_cb.TxAaMtuSize) + && (p_buf->layer_specific < 0x0F) && nb_frame); + + if (p_buf->len) { + /* + * Timestamp of the media packet header represent the TS of the + * first SBC frame, i.e the timestamp before including this frame. + */ + *((uint32_t *) (p_buf + 1)) = a2d_sbc_encoder_cb.timestamp; + + a2d_sbc_encoder_cb.timestamp += + p_buf->layer_specific * blocm_x_subband; + + uint8_t done_nb_frame = remain_nb_frame - nb_frame; + remain_nb_frame = nb_frame; + if (!a2d_sbc_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) + return; + } else { + osi_free(p_buf); + } + } +} + +static bool a2d_sbc_read_feeding(void) +{ + SBC_ENC_PARAMS *p_encoder_params = &a2d_sbc_encoder_cb.sbc_encoder_params; + uint16_t blocm_x_subband = p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfBlocks; + uint32_t read_size; + uint32_t sbc_sampling = 48000; + uint32_t src_samples; + uint16_t bytes_needed = blocm_x_subband * + p_encoder_params->s16NumOfChannels * + a2d_sbc_encoder_cb.feeding_params.bit_per_sample / 8; + static uint16_t up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS + * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2]; + static uint16_t read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS + * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS]; + uint32_t src_size_used; + uint32_t dst_size_used; + bool fract_needed; + int32_t fract_max; + int32_t fract_threshold; + uint32_t nb_byte_read; + + /* Get the SBC sampling rate */ + switch (p_encoder_params->s16SamplingFreq) { + case SBC_sf48000: + sbc_sampling = 48000; + break; + case SBC_sf44100: + sbc_sampling = 44100; + break; + case SBC_sf32000: + sbc_sampling = 32000; + break; + case SBC_sf16000: + sbc_sampling = 16000; + break; + } + + if (sbc_sampling == a2d_sbc_encoder_cb.feeding_params.sampling_freq) { + read_size = + bytes_needed - a2d_sbc_encoder_cb.feeding_state.aa_feed_residue; + nb_byte_read = a2d_sbc_encoder_cb.read_callback( + ((uint8_t *)p_encoder_params->as16PcmBuffer) + + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue, + read_size); + if (nb_byte_read != read_size) { + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue += nb_byte_read; + return false; + } + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue = 0; + return true; + } + + /* + * Some Feeding PCM frequencies require to split the number of sample + * to read. + * E.g 128 / 6 = 21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0 + */ + fract_needed = false; /* Default */ + switch (a2d_sbc_encoder_cb.feeding_params.sampling_freq) { + case 32000: + case 8000: + fract_needed = true; + fract_max = 2; /* 0, 1 and 2 */ + fract_threshold = 0; /* Add one for the first */ + break; + case 16000: + fract_needed = true; + fract_max = 2; /* 0, 1 and 2 */ + fract_threshold = 1; /* Add one for the first two frames*/ + break; + } + + /* Compute number of sample to read from source */ + src_samples = blocm_x_subband; + src_samples *= a2d_sbc_encoder_cb.feeding_params.sampling_freq; + src_samples /= sbc_sampling; + + /* The previous division may have a remainder not null */ + if (fract_needed) { + if (a2d_sbc_encoder_cb.feeding_state.aa_feed_counter <= fract_threshold) { + src_samples++; /* for every read before threshold add one sample */ + } + + /* do nothing if counter >= threshold */ + a2d_sbc_encoder_cb.feeding_state.aa_feed_counter++; /* one more read */ + if (a2d_sbc_encoder_cb.feeding_state.aa_feed_counter > fract_max) { + a2d_sbc_encoder_cb.feeding_state.aa_feed_counter = 0; + } + } + + /* Compute number of bytes to read from source */ + read_size = src_samples; + read_size *= a2d_sbc_encoder_cb.feeding_params.num_channel; + read_size *= (a2d_sbc_encoder_cb.feeding_params.bit_per_sample / 8); + + /* Read Data from UIPC channel */ + nb_byte_read = a2d_sbc_encoder_cb.read_callback((uint8_t *)read_buffer, + read_size); + + if (nb_byte_read < read_size) { + if (nb_byte_read == 0) + return false; + + /* Fill the unfilled part of the read buffer with silence (0) */ + memset(((uint8_t *)read_buffer) + nb_byte_read, 0, + read_size - nb_byte_read); + nb_byte_read = read_size; + } + + /* Initialize PCM up-sampling engine */ + a2d_sbc_init_up_sample(a2d_sbc_encoder_cb.feeding_params.sampling_freq, + sbc_sampling, + a2d_sbc_encoder_cb.feeding_params.bit_per_sample, + a2d_sbc_encoder_cb.feeding_params.num_channel); + + /* + * Re-sample the read buffer. + * The output PCM buffer will be stereo, 16 bit per sample. + */ + dst_size_used = a2d_sbc_up_sample((uint8_t *)read_buffer, + (uint8_t *)up_sampled_buffer + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue, + nb_byte_read, + sizeof(up_sampled_buffer) - a2d_sbc_encoder_cb.feeding_state.aa_feed_residue, + &src_size_used); + + /* update the residue */ + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue += dst_size_used; + + /* only copy the pcm sample when we have up-sampled enough PCM */ + if (a2d_sbc_encoder_cb.feeding_state.aa_feed_residue < bytes_needed) + return false; + + /* Copy the output pcm samples in SBC encoding buffer */ + memcpy((uint8_t *)p_encoder_params->as16PcmBuffer, + (uint8_t *)up_sampled_buffer, bytes_needed); + /* update the residue */ + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue -= bytes_needed; + + if (a2d_sbc_encoder_cb.feeding_state.aa_feed_residue != 0) { + memcpy((uint8_t *)up_sampled_buffer, + (uint8_t *)up_sampled_buffer + bytes_needed, + a2d_sbc_encoder_cb.feeding_state.aa_feed_residue); + } + return true; +} + +static uint8_t calculate_max_frames_per_packet(void) +{ + uint16_t effective_mtu_size = a2d_sbc_encoder_cb.TxAaMtuSize; + SBC_ENC_PARAMS *p_encoder_params = &a2d_sbc_encoder_cb.sbc_encoder_params; + uint16_t result = 0; + uint32_t frame_len; + + LOG_VERBOSE(LOG_TAG, "%s: original AVDTP MTU size: %d", + __func__, a2d_sbc_encoder_cb.TxAaMtuSize); + if (a2d_sbc_encoder_cb.is_peer_edr && + !a2d_sbc_encoder_cb.peer_supports_3mbps) { + // This condition would be satisfied only if the remote device is + // EDR and supports only 2 Mbps, but the effective AVDTP MTU size + // exceeds the 2DH5 packet size. + LOG_VERBOSE(LOG_TAG, "%s: The remote devce is EDR but does not support 3 Mbps", + __func__); + + if (effective_mtu_size > MAX_2MBPS_AVDTP_MTU) { + LOG_WARN(LOG_TAG, "%s: Restricting AVDTP MTU size to %d", + __func__, MAX_2MBPS_AVDTP_MTU); + effective_mtu_size = MAX_2MBPS_AVDTP_MTU; + a2d_sbc_encoder_cb.TxAaMtuSize = effective_mtu_size; + } + } + + if (!p_encoder_params->s16NumOfSubBands) { + LOG_ERROR(LOG_TAG, "%s: SubBands are set to 0, resetting to %d", + __func__, SBC_MAX_NUM_OF_SUBBANDS); + p_encoder_params->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS; + } + if (!p_encoder_params->s16NumOfBlocks) { + LOG_ERROR(LOG_TAG, "%s: Blocks are set to 0, resetting to %d", + __func__, SBC_MAX_NUM_OF_BLOCKS); + p_encoder_params->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS; + } + if (!p_encoder_params->s16NumOfChannels) { + LOG_ERROR(LOG_TAG, "%s: Channels are set to 0, resetting to %d", + __func__, SBC_MAX_NUM_OF_CHANNELS); + p_encoder_params->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS; + } + + frame_len = a2d_sbc_frame_length(); + + LOG_VERBOSE(LOG_TAG, "%s: Effective Tx MTU to be considered: %d", + __func__, effective_mtu_size); + + switch (p_encoder_params->s16SamplingFreq) { + case SBC_sf44100: + if (frame_len == 0) { + LOG_ERROR(LOG_TAG, "%s: Calculating frame length, resetting it to default %d", + __func__, A2D_SBC_MAX_HQ_FRAME_SIZE_44_1); + frame_len = A2D_SBC_MAX_HQ_FRAME_SIZE_44_1; + } + result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len; + LOG_VERBOSE(LOG_TAG, "%s: Max number of SBC frames: %d", + __func__, result); + break; + + case SBC_sf48000: + if (frame_len == 0) { + LOG_ERROR(LOG_TAG, "%s: Calculating frame length, resetting it to default %d", + __func__, A2D_SBC_MAX_HQ_FRAME_SIZE_48); + frame_len = A2D_SBC_MAX_HQ_FRAME_SIZE_48; + } + result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len; + LOG_VERBOSE(LOG_TAG, "%s: Max number of SBC frames: %d", + __func__, result); + break; + + default: + LOG_ERROR(LOG_TAG, "%s: Max number of SBC frames: %d", + __func__, result); + break; + } + return result; +} + +static uint16_t a2d_sbc_source_rate(void) +{ + uint16_t rate = A2D_SBC_DEFAULT_BITRATE; + + /* restrict bitrate if a2dp link is non-edr */ + if (!a2d_sbc_encoder_cb.is_peer_edr) { + rate = A2D_SBC_NON_EDR_MAX_RATE; + LOG_VERBOSE(LOG_TAG, "%s: non-edr a2dp sink detected, restrict rate to %d", + __func__, rate); + } + + return rate; +} + +static uint32_t a2d_sbc_frame_length(void) +{ + SBC_ENC_PARAMS *p_encoder_params = &a2d_sbc_encoder_cb.sbc_encoder_params; + uint32_t frame_len = 0; + + LOG_VERBOSE(LOG_TAG, "%s: channel mode: %d, sub-band: %d, number of block: %d, bitpool: %d, sampling frequency: %d, num channels: %d", + __func__, + p_encoder_params->s16ChannelMode, + p_encoder_params->s16NumOfSubBands, + p_encoder_params->s16NumOfBlocks, + p_encoder_params->s16BitPool, + p_encoder_params->s16SamplingFreq, + p_encoder_params->s16NumOfChannels); + + switch (p_encoder_params->s16ChannelMode) { + case SBC_MONO: + /* FALLTHROUGH */ + case SBC_DUAL: + frame_len = A2D_SBC_FRAME_HEADER_SIZE_BYTES + + ((uint32_t)(A2D_SBC_SCALE_FACTOR_BITS * + p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfChannels) / CHAR_BIT) + + ((uint32_t)(p_encoder_params->s16NumOfBlocks * + p_encoder_params->s16NumOfChannels * + p_encoder_params->s16BitPool) / CHAR_BIT); + break; + case SBC_STEREO: + frame_len = A2D_SBC_FRAME_HEADER_SIZE_BYTES + + ((uint32_t)(A2D_SBC_SCALE_FACTOR_BITS * + p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfChannels) / CHAR_BIT) + + ((uint32_t)(p_encoder_params->s16NumOfBlocks * + p_encoder_params->s16BitPool) / CHAR_BIT); + break; + case SBC_JOINT_STEREO: + frame_len = A2D_SBC_FRAME_HEADER_SIZE_BYTES + + ((uint32_t)(A2D_SBC_SCALE_FACTOR_BITS * + p_encoder_params->s16NumOfSubBands * + p_encoder_params->s16NumOfChannels) / CHAR_BIT) + + ((uint32_t)(p_encoder_params->s16NumOfSubBands + + (p_encoder_params->s16NumOfBlocks * + p_encoder_params->s16BitPool)) / CHAR_BIT); + break; + default: + LOG_VERBOSE(LOG_TAG, "%s: Invalid channel number: %d", + __func__, p_encoder_params->s16ChannelMode); + break; + } + LOG_VERBOSE(LOG_TAG, "%s: calculated frame length: %d", + __func__, frame_len); + return frame_len; +} diff --git a/bta/av/bta_av_sbc.c b/stack/a2dp/a2d_sbc_up_sample.c similarity index 65% rename from bta/av/bta_av_sbc.c rename to stack/a2dp/a2d_sbc_up_sample.c index 691665eec..be5296dd9 100644 --- a/bta/av/bta_av_sbc.c +++ b/stack/a2dp/a2d_sbc_up_sample.c @@ -23,33 +23,29 @@ * ******************************************************************************/ -#include "a2d_api.h" -#include "a2d_sbc.h" -#include "bta_av_sbc.h" -#include "utl.h" +#include "a2d_sbc_up_sample.h" -typedef int (tBTA_AV_SBC_ACT)(void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret); +typedef int (tA2D_SBC_ACT)(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret); typedef struct { int32_t cur_pos; /* current position */ uint32_t src_sps; /* samples per second (source audio data) */ uint32_t dst_sps; /* samples per second (converted audio data) */ - tBTA_AV_SBC_ACT *p_act; /* the action function to do the conversion */ + tA2D_SBC_ACT *p_act; /* the action function to do the conversion */ uint8_t bits; /* number of bits per pcm sample */ uint8_t n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */ int16_t worker1; int16_t worker2; uint8_t div; -} tBTA_AV_SBC_UPS_CB; +} tA2D_SBC_UPS_CB; -tBTA_AV_SBC_UPS_CB bta_av_sbc_ups_cb; +tA2D_SBC_UPS_CB a2d_sbc_ups_cb; /******************************************************************************* ** -** Function bta_av_sbc_init_up_sample +** Function a2d_sbc_init_up_sample ** ** Description initialize the up sample ** @@ -61,27 +57,27 @@ tBTA_AV_SBC_UPS_CB bta_av_sbc_ups_cb; ** Returns none ** *******************************************************************************/ -void bta_av_sbc_init_up_sample (uint32_t src_sps, uint32_t dst_sps, - uint8_t bits, uint8_t n_channels) +void a2d_sbc_init_up_sample(uint32_t src_sps, uint32_t dst_sps, uint8_t bits, + uint8_t n_channels) { - bta_av_sbc_ups_cb.cur_pos = -1; - bta_av_sbc_ups_cb.src_sps = src_sps; - bta_av_sbc_ups_cb.dst_sps = dst_sps; - bta_av_sbc_ups_cb.bits = bits; - bta_av_sbc_ups_cb.n_channels= n_channels; + a2d_sbc_ups_cb.cur_pos = -1; + a2d_sbc_ups_cb.src_sps = src_sps; + a2d_sbc_ups_cb.dst_sps = dst_sps; + a2d_sbc_ups_cb.bits = bits; + a2d_sbc_ups_cb.n_channels= n_channels; if(n_channels == 1) { /* mono */ if(bits == 8) { - bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_8m; - bta_av_sbc_ups_cb.div = 1; + a2d_sbc_ups_cb.p_act = a2d_sbc_up_sample_8m; + a2d_sbc_ups_cb.div = 1; } else { - bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_16m; - bta_av_sbc_ups_cb.div = 2; + a2d_sbc_ups_cb.p_act = a2d_sbc_up_sample_16m; + a2d_sbc_ups_cb.div = 2; } } else @@ -89,20 +85,20 @@ void bta_av_sbc_init_up_sample (uint32_t src_sps, uint32_t dst_sps, /* stereo */ if(bits == 8) { - bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_8s; - bta_av_sbc_ups_cb.div = 2; + a2d_sbc_ups_cb.p_act = a2d_sbc_up_sample_8s; + a2d_sbc_ups_cb.div = 2; } else { - bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_16s; - bta_av_sbc_ups_cb.div = 4; + a2d_sbc_ups_cb.p_act = a2d_sbc_up_sample_16s; + a2d_sbc_ups_cb.div = 4; } } } /******************************************************************************* ** -** Function bta_av_sbc_up_sample +** Function a2d_sbc_up_sample ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -114,7 +110,7 @@ void bta_av_sbc_init_up_sample (uint32_t src_sps, uint32_t dst_sps, ** dst_samples: The size of p_dst (number of bytes) ** ** Note: An AE reported an issue with this function. -** When called with bta_av_sbc_up_sample(src, uint8_array_dst..) +** When called with a2d_sbc_up_sample(src, uint8_array_dst..) ** the byte before uint8_array_dst may get overwritten. ** Using uint16_array_dst avoids the problem. ** This issue is related to endian-ness and is hard to resolve @@ -125,18 +121,17 @@ void bta_av_sbc_init_up_sample (uint32_t src_sps, uint32_t dst_sps, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -int bta_av_sbc_up_sample (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret) +int a2d_sbc_up_sample(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret) { uint32_t src; uint32_t dst; - if(bta_av_sbc_ups_cb.p_act) + if(a2d_sbc_ups_cb.p_act) { - src = src_samples/bta_av_sbc_ups_cb.div; - dst = dst_samples/bta_av_sbc_ups_cb.div; - return (*bta_av_sbc_ups_cb.p_act)(p_src, p_dst, src, dst, p_ret); + src = src_samples/a2d_sbc_ups_cb.div; + dst = dst_samples/a2d_sbc_ups_cb.div; + return (*a2d_sbc_ups_cb.p_act)(p_src, p_dst, src, dst, p_ret); } else { @@ -147,7 +142,7 @@ int bta_av_sbc_up_sample (void *p_src, void *p_dst, /******************************************************************************* ** -** Function bta_av_sbc_up_sample_16s (16bits-stereo) +** Function a2d_sbc_up_sample_16s (16bits-stereo) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -162,27 +157,26 @@ int bta_av_sbc_up_sample (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret) +int a2d_sbc_up_sample_16s(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret) { int16_t *p_src_tmp = (int16_t *)p_src; int16_t *p_dst_tmp = (int16_t *)p_dst; - int16_t *p_worker1 = &bta_av_sbc_ups_cb.worker1; - int16_t *p_worker2 = &bta_av_sbc_ups_cb.worker2; - uint32_t src_sps = bta_av_sbc_ups_cb.src_sps; - uint32_t dst_sps = bta_av_sbc_ups_cb.dst_sps; + int16_t *p_worker1 = &a2d_sbc_ups_cb.worker1; + int16_t *p_worker2 = &a2d_sbc_ups_cb.worker2; + uint32_t src_sps = a2d_sbc_ups_cb.src_sps; + uint32_t dst_sps = a2d_sbc_ups_cb.dst_sps; - while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples) { *p_dst_tmp++ = *p_worker1; *p_dst_tmp++ = *p_worker2; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples--; } - bta_av_sbc_ups_cb.cur_pos = dst_sps; + a2d_sbc_ups_cb.cur_pos = dst_sps; while (src_samples-- && dst_samples) { @@ -194,15 +188,15 @@ int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, *p_dst_tmp++ = *p_worker1; *p_dst_tmp++ = *p_worker2; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples--; - } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + } while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples); - bta_av_sbc_ups_cb.cur_pos += dst_sps; + a2d_sbc_ups_cb.cur_pos += dst_sps; } - if (bta_av_sbc_ups_cb.cur_pos == (int32_t)dst_sps) - bta_av_sbc_ups_cb.cur_pos = 0; + if (a2d_sbc_ups_cb.cur_pos == (int32_t)dst_sps) + a2d_sbc_ups_cb.cur_pos = 0; *p_ret = ((char *)p_src_tmp - (char *)p_src); return ((char *)p_dst_tmp - (char *)p_dst); @@ -210,7 +204,7 @@ int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, /******************************************************************************* ** -** Function bta_av_sbc_up_sample_16m (16bits-mono) +** Function a2d_sbc_up_sample_16m (16bits-mono) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -225,28 +219,27 @@ int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret) +int a2d_sbc_up_sample_16m(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret) { int16_t *p_src_tmp = (int16_t *)p_src; int16_t *p_dst_tmp = (int16_t *)p_dst; - int16_t *p_worker = &bta_av_sbc_ups_cb.worker1; - uint32_t src_sps = bta_av_sbc_ups_cb.src_sps; - uint32_t dst_sps = bta_av_sbc_ups_cb.dst_sps; + int16_t *p_worker = &a2d_sbc_ups_cb.worker1; + uint32_t src_sps = a2d_sbc_ups_cb.src_sps; + uint32_t dst_sps = a2d_sbc_ups_cb.dst_sps; - while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples) { *p_dst_tmp++ = *p_worker; *p_dst_tmp++ = *p_worker; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples--; dst_samples--; } - bta_av_sbc_ups_cb.cur_pos = dst_sps; + a2d_sbc_ups_cb.cur_pos = dst_sps; while (src_samples-- && dst_samples) { @@ -257,17 +250,17 @@ int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, *p_dst_tmp++ = *p_worker; *p_dst_tmp++ = *p_worker; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples--; dst_samples--; - } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + } while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples); - bta_av_sbc_ups_cb.cur_pos += dst_sps; + a2d_sbc_ups_cb.cur_pos += dst_sps; } - if (bta_av_sbc_ups_cb.cur_pos == (int32_t)dst_sps) - bta_av_sbc_ups_cb.cur_pos = 0; + if (a2d_sbc_ups_cb.cur_pos == (int32_t)dst_sps) + a2d_sbc_ups_cb.cur_pos = 0; *p_ret = ((char *)p_src_tmp - (char *)p_src); return ((char *)p_dst_tmp - (char *)p_dst); @@ -275,7 +268,7 @@ int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, /******************************************************************************* ** -** Function bta_av_sbc_up_sample_8s (8bits-stereo) +** Function a2d_sbc_up_sample_8s (8bits-stereo) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -290,28 +283,27 @@ int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret) +int a2d_sbc_up_sample_8s(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret) { uint8_t *p_src_tmp = (uint8_t *)p_src; int16_t *p_dst_tmp = (int16_t *)p_dst; - int16_t *p_worker1 = &bta_av_sbc_ups_cb.worker1; - int16_t *p_worker2 = &bta_av_sbc_ups_cb.worker2; - uint32_t src_sps = bta_av_sbc_ups_cb.src_sps; - uint32_t dst_sps = bta_av_sbc_ups_cb.dst_sps; + int16_t *p_worker1 = &a2d_sbc_ups_cb.worker1; + int16_t *p_worker2 = &a2d_sbc_ups_cb.worker2; + uint32_t src_sps = a2d_sbc_ups_cb.src_sps; + uint32_t dst_sps = a2d_sbc_ups_cb.dst_sps; - while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples) { *p_dst_tmp++ = *p_worker1; *p_dst_tmp++ = *p_worker2; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples--; dst_samples--; } - bta_av_sbc_ups_cb.cur_pos = dst_sps; + a2d_sbc_ups_cb.cur_pos = dst_sps; while (src_samples -- && dst_samples) { @@ -327,16 +319,16 @@ int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, *p_dst_tmp++ = *p_worker1; *p_dst_tmp++ = *p_worker2; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples--; dst_samples--; - } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + } while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples); - bta_av_sbc_ups_cb.cur_pos += dst_sps; + a2d_sbc_ups_cb.cur_pos += dst_sps; } - if (bta_av_sbc_ups_cb.cur_pos == (int32_t)dst_sps) - bta_av_sbc_ups_cb.cur_pos = 0; + if (a2d_sbc_ups_cb.cur_pos == (int32_t)dst_sps) + a2d_sbc_ups_cb.cur_pos = 0; *p_ret = ((char *)p_src_tmp - (char *)p_src); return ((char *)p_dst_tmp - (char *)p_dst); @@ -344,7 +336,7 @@ int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, /******************************************************************************* ** -** Function bta_av_sbc_up_sample_8m (8bits-mono) +** Function a2d_sbc_up_sample_8m (8bits-mono) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -359,27 +351,26 @@ int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -int bta_av_sbc_up_sample_8m (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret) +int a2d_sbc_up_sample_8m(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret) { uint8_t *p_src_tmp = (uint8_t *)p_src; int16_t *p_dst_tmp = (int16_t *)p_dst; - int16_t *p_worker = &bta_av_sbc_ups_cb.worker1; - uint32_t src_sps = bta_av_sbc_ups_cb.src_sps; - uint32_t dst_sps = bta_av_sbc_ups_cb.dst_sps; + int16_t *p_worker = &a2d_sbc_ups_cb.worker1; + uint32_t src_sps = a2d_sbc_ups_cb.src_sps; + uint32_t dst_sps = a2d_sbc_ups_cb.dst_sps; - while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples) { *p_dst_tmp++ = *p_worker; *p_dst_tmp++ = *p_worker; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples -= 4; } - bta_av_sbc_ups_cb.cur_pos = dst_sps; + a2d_sbc_ups_cb.cur_pos = dst_sps; while (src_samples-- && dst_samples) { @@ -392,16 +383,16 @@ int bta_av_sbc_up_sample_8m (void *p_src, void *p_dst, *p_dst_tmp++ = *p_worker; *p_dst_tmp++ = *p_worker; - bta_av_sbc_ups_cb.cur_pos -= src_sps; + a2d_sbc_ups_cb.cur_pos -= src_sps; dst_samples -= 4; - } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + } while (a2d_sbc_ups_cb.cur_pos > 0 && dst_samples); - bta_av_sbc_ups_cb.cur_pos += dst_sps; + a2d_sbc_ups_cb.cur_pos += dst_sps; } - if (bta_av_sbc_ups_cb.cur_pos == (int32_t)dst_sps) - bta_av_sbc_ups_cb.cur_pos = 0; + if (a2d_sbc_ups_cb.cur_pos == (int32_t)dst_sps) + a2d_sbc_ups_cb.cur_pos = 0; *p_ret = ((char *)p_src_tmp - (char *)p_src); return ((char *)p_dst_tmp - (char *)p_dst); diff --git a/stack/a2dp/a2d_vendor.c b/stack/a2dp/a2d_vendor.c index 3959459d0..8d2fee853 100644 --- a/stack/a2dp/a2d_vendor.c +++ b/stack/a2dp/a2d_vendor.c @@ -381,3 +381,14 @@ bool A2D_VendorBuildCodecHeader(UNUSED_ATTR const uint8_t *p_codec_info, return false; } + +const tA2D_ENCODER_INTERFACE *A2D_VendorGetEncoderInterface( + const uint8_t *p_codec_info) +{ + // uint32_t vendor_id = A2D_VendorCodecGetVendorId(p_codec_info); + // uint16_t codec_id = A2D_VendorCodecGetCodecId(p_codec_info); + + // Add checks based on + + return NULL; +} diff --git a/stack/include/a2d_api.h b/stack/include/a2d_api.h index bfc29282d..f70b1697a 100644 --- a/stack/include/a2d_api.h +++ b/stack/include/a2d_api.h @@ -24,6 +24,7 @@ #ifndef A2D_API_H #define A2D_API_H +#include "osi/include/time.h" #include "avdt_api.h" #include "sdp_api.h" @@ -35,6 +36,14 @@ extern "C" { ** constants *****************************************************************************/ +// +// |MAX_PCM_FRAME_NUM_PER_TICK| controls how many buffers we can hold in +// the A2DP buffer queues during temporary link congestion. +// +#ifndef MAX_PCM_FRAME_NUM_PER_TICK +#define MAX_PCM_FRAME_NUM_PER_TICK 14 +#endif + /* Profile supported features */ #define A2D_SUPF_PLAYER 0x0001 #define A2D_SUPF_MIC 0x0002 @@ -138,13 +147,89 @@ typedef enum { } tA2D_CODEC_SEP_INDEX; /** - * Structure used to configure the AV media feeding + * Structure used to configure the A2DP feeding. */ typedef struct { uint32_t sampling_freq; /* 44100, 48000 etc */ uint8_t num_channel; /* 1 for mono or 2 stereo */ uint8_t bit_per_sample; /* Number of bits per sample (8, 16) */ -} tA2D_AV_MEDIA_FEEDINGS; +} tA2D_FEEDING_PARAMS; + +/** + * Structure used to initialize the A2DP encoder. + */ +typedef struct { + uint16_t SamplingFreq; /* 16k, 32k, 44.1k or 48k */ + uint8_t ChannelMode; /* mono, dual, stereo or joint stereo */ + uint8_t NumOfSubBands; /* 4 or 8 */ + uint8_t NumOfBlocks; /* 4, 8, 12 or 16 */ + uint8_t AllocationMethod; /* loudness or SNR */ + uint16_t MtuSize; /* peer mtu size */ +} tA2D_ENCODER_INIT_PARAMS; + +/** + * Structure used to update the A2DP encoder. + */ +typedef struct { + uint16_t MinMtuSize; /* Minimum peer mtu size */ + uint8_t MaxBitPool; /* Maximum peer bitpool */ + uint8_t MinBitPool; /* Minimum peer bitpool */ +} tA2D_ENCODER_UPDATE_PARAMS; + +// Prototype for a callback to read audio data for encoding. +// |p_buf| is the buffer to store the data. |len| is the number of octets to +// read. +// Returns the number of octets read. +typedef uint32_t (*a2d_source_read_callback_t)(uint8_t *p_buf, uint32_t len); + +// Prototype for a callback to enqueue A2DP source packets for transmission. +// |p_buf| is the buffer with the audio data to enqueue. The callback is +// responsible for freeing |p_buf|. +// |frames_n| is the number of audio frames in |p_buf| - it is used for +// statistics purpose. +// Returns true if the packet was enqueued, otherwise false. +typedef bool (*a2d_source_enqueue_callback_t)(BT_HDR *p_buf, size_t frames_n); + +// +// A2DP encoder callbacks interface. +// +typedef struct { + // Initialize the A2DP encoder. + // If |is_peer_edr| is true, the A2DP peer device supports EDR. + // If |peer_supports_3mbps| is true, the A2DP peer device supports 3Mbps + // EDR. + // The encoder initialization parameters are in |p_init_params|. + // |enqueue_callback} is the callback for enqueueing the encoded audio + // data. + void (*encoder_init)(bool is_peer_edr, bool peer_supports_3mbps, + const tA2D_ENCODER_INIT_PARAMS *p_init_params, + a2d_source_read_callback_t read_callback, + a2d_source_enqueue_callback_t enqueue_callback); + + // Update the A2DP encoder. + // The encoder update parameters are in |p_update_params|. + void (*encoder_update)(const tA2D_ENCODER_UPDATE_PARAMS *p_update_params); + + // Cleanup the A2DP encoder. + void (*encoder_cleanup)(void); + + // Initialize the feeding for the A2DP encoder. + // The feeding initialization parameters are in |p_feeding_params|. + void (*feeding_init)(const tA2D_FEEDING_PARAMS *p_feeding_params); + + // Reset the feeding for the A2DP encoder. + void (*feeding_reset)(void); + + // Flush the feeding for the A2DP encoder. + void (*feeding_flush)(void); + + // Get the A2DP encoder interval (in milliseconds). + period_ms_t (*get_encoder_interval_ms)(void); + + // Prepare and send A2DP encoded frames. + // |timestamp_us| is the current timestamp (in microseconds). + void (*send_frames)(uint64_t timestamp_us); +} tA2D_ENCODER_INTERFACE; /***************************************************************************** ** external function declarations @@ -317,10 +402,11 @@ bool A2D_IsPeerSourceCodecSupported(const uint8_t *p_codec_info); // |p_codec_info|. void A2D_InitDefaultCodec(uint8_t *p_codec_info); -// Sets A2DB codec state based on the feeding information from |p_feeding|. +// Sets A2DB codec state based on the feeding information from +// |p_feeding_params|. // The state with the codec capabilities is stored in |p_codec_info|. // Returns true on success, otherwise false. -bool A2D_SetCodec(const tA2D_AV_MEDIA_FEEDINGS *p_feeding, +bool A2D_SetCodec(const tA2D_FEEDING_PARAMS *p_feeding_params, uint8_t *p_codec_info); // Builds A2DP preferred Sink capability from Source capability. @@ -485,6 +571,14 @@ bool A2D_GetPacketTimestamp(const uint8_t *p_codec_info, const uint8_t *p_data, bool A2D_BuildCodecHeader(const uint8_t *p_codec_info, BT_HDR *p_buf, uint16_t frames_per_packet); +// Gets the A2DP encoder interface that can be used to encode and prepare +// A2DP packets for transmission - see |tA2D_ENCODER_INTERFACE|. +// |p_codec_info| contains the codec information. +// Returns the A2DP encoder interface if the |p_codec_info| is valid and +// supported, otherwise NULL. +const tA2D_ENCODER_INTERFACE *A2D_GetEncoderInterface( + const uint8_t *p_codec_info); + #ifdef __cplusplus } #endif diff --git a/stack/include/a2d_sbc.h b/stack/include/a2d_sbc.h index 826d8fb51..72d0604c3 100644 --- a/stack/include/a2d_sbc.h +++ b/stack/include/a2d_sbc.h @@ -18,12 +18,15 @@ /****************************************************************************** * - * nterface to low complexity subband codec (SBC) + * Interface to low complexity subband codec (SBC) * ******************************************************************************/ #ifndef A2D_SBC_H #define A2D_SBC_H +#include "avdt_api.h" +#include "a2d_api.h" + #ifdef __cplusplus extern "C" { #endif @@ -165,10 +168,11 @@ bool A2D_IsPeerSourceCodecSupportedSbc(const uint8_t *p_codec_info); // |p_codec_info|. void A2D_InitDefaultCodecSbc(uint8_t *p_codec_info); -// Sets A2DB SBC codec state based on the feeding information from |p_feeding|. +// Sets A2DB SBC codec state based on the feeding information from +// |p_feeding_params|. // The state with the codec capabilities is stored in |p_codec_info|. // Returns true on success, otherwise false. -bool A2D_SetCodecSbc(const tA2D_AV_MEDIA_FEEDINGS *p_feeding, +bool A2D_SetCodecSbc(const tA2D_FEEDING_PARAMS *p_feeding_params, uint8_t *p_codec_info); // Builds A2DP preferred SBC Sink capability from SBC Source capability. @@ -314,6 +318,14 @@ bool A2D_BuildCodecHeaderSbc(const uint8_t *p_codec_info, BT_HDR *p_buf, // |p_codec_info| is a pointer to the SBC codec_info to decode and display. void A2D_DumpCodecInfoSbc(const uint8_t *p_codec_info); +// Gets the A2DP SBC encoder interface that can be used to encode and prepare +// A2DP packets for transmission - see |tA2D_ENCODER_INTERFACE|. +// |p_codec_info| contains the codec information. +// Returns the A2DP SBC encoder interface if the |p_codec_info| is valid and +// supported, otherwise NULL. +const tA2D_ENCODER_INTERFACE *A2D_GetEncoderInterfaceSbc( + const uint8_t *p_codec_info); + #ifdef __cplusplus } #endif diff --git a/stack/include/a2d_sbc_encoder.h b/stack/include/a2d_sbc_encoder.h new file mode 100644 index 000000000..5a973d922 --- /dev/null +++ b/stack/include/a2d_sbc_encoder.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * + * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +// +// Interface to the A2DP SBC Encoder +// + +#ifndef A2D_SBC_ENCODER_H +#define A2D_SBC_ENCODER_H + +#include "osi/include/time.h" +#include "a2d_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize the A2DP SBC encoder. +// If |is_peer_edr| is true, the A2DP peer device supports EDR. +// If |peer_supports_3mbps| is true, the A2DP peer device supports 3Mbps EDR. +// The encoder initialization parameters are in |p_init_params|. +// |enqueue_callback} is the callback for enqueueing the encoded audio data. +void a2d_sbc_encoder_init(bool is_peer_edr, bool peer_supports_3mbps, + const tA2D_ENCODER_INIT_PARAMS *p_init_params, + a2d_source_read_callback_t read_callback, + a2d_source_enqueue_callback_t enqueue_callback); + +// Update the A2DP SBC encoder. +// The encoder update parameters are in |p_update_params|. +void a2d_sbc_encoder_update(const tA2D_ENCODER_UPDATE_PARAMS *p_update_params); + +// Cleanup the A2DP SBC encoder. +void a2d_sbc_encoder_cleanup(void); + +// Initialize the feeding for the A2DP SBC encoder. +// The feeding initialization parameters are in |p_feeding_params|. +void a2d_sbc_feeding_init(const tA2D_FEEDING_PARAMS *p_feeding_params); + +// Reset the feeding for the A2DP SBC encoder. +void a2d_sbc_feeding_reset(void); + +// Flush the feeding for the A2DP SBC encoder. +void a2d_sbc_feeding_flush(void); + +// Get the A2DP SBC encoder interval (in milliseconds). +period_ms_t a2d_sbc_get_encoder_interval_ms(void); + +// Prepare and send A2DP SBC encoded frames. +// |timestamp_us| is the current timestamp (in microseconds). +void a2d_sbc_send_frames(uint64_t timestamp_us); + +#ifdef __cplusplus +} +#endif + +#endif // A2D_SBC_ENCODER_H diff --git a/bta/include/bta_av_sbc.h b/stack/include/a2d_sbc_up_sample.h similarity index 79% rename from bta/include/bta_av_sbc.h rename to stack/include/a2d_sbc_up_sample.h index b6121b394..94b785485 100644 --- a/bta/include/bta_av_sbc.h +++ b/stack/include/a2d_sbc_up_sample.h @@ -22,8 +22,10 @@ * frames and codec capabilities. * ******************************************************************************/ -#ifndef BTA_AV_SBC_H -#define BTA_AV_SBC_H +#ifndef A2D_SBC_UP_SAMPLE_H +#define A2D_SBC_UP_SAMPLE_H + +#include #ifdef __cplusplus extern "C" { @@ -31,7 +33,7 @@ extern "C" { /******************************************************************************* ** -** Function bta_av_sbc_init_up_sample +** Function a2d_sbc_init_up_sample ** ** Description initialize the up sample ** @@ -43,12 +45,12 @@ extern "C" { ** Returns none ** *******************************************************************************/ -extern void bta_av_sbc_init_up_sample (uint32_t src_sps, uint32_t dst_sps, - uint8_t bits, uint8_t n_channels); +void a2d_sbc_init_up_sample(uint32_t src_sps, uint32_t dst_sps, uint8_t bits, + uint8_t n_channels); /******************************************************************************* ** -** Function bta_av_sbc_up_sample +** Function a2d_sbc_up_sample ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -60,7 +62,7 @@ extern void bta_av_sbc_init_up_sample (uint32_t src_sps, uint32_t dst_sps, ** dst_samples: The size of p_dst (number of bytes) ** ** Note: An AE reported an issue with this function. -** When called with bta_av_sbc_up_sample(src, uint8_array_dst..) +** When called with a2d_sbc_up_sample(src, uint8_array_dst..) ** the byte before uint8_array_dst may get overwritten. ** Using uint16_array_dst avoids the problem. ** This issue is related to endian-ness and is hard to resolve @@ -71,13 +73,12 @@ extern void bta_av_sbc_init_up_sample (uint32_t src_sps, uint32_t dst_sps, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -extern int bta_av_sbc_up_sample (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret); +int a2d_sbc_up_sample(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret); /******************************************************************************* ** -** Function bta_av_sbc_up_sample_16s (16bits-stereo) +** Function a2d_sbc_up_sample_16s (16bits-stereo) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -92,13 +93,12 @@ extern int bta_av_sbc_up_sample (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -extern int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret); +int a2d_sbc_up_sample_16s(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret); /******************************************************************************* ** -** Function bta_av_sbc_up_sample_16m (16bits-mono) +** Function a2d_sbc_up_sample_16m (16bits-mono) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -113,13 +113,12 @@ extern int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -extern int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret); +int a2d_sbc_up_sample_16m(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret); /******************************************************************************* ** -** Function bta_av_sbc_up_sample_8s (8bits-stereo) +** Function a2d_sbc_up_sample_8s (8bits-stereo) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -134,13 +133,12 @@ extern int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -extern int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret); +int a2d_sbc_up_sample_8s(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret); /******************************************************************************* ** -** Function bta_av_sbc_up_sample_8m (8bits-mono) +** Function a2d_sbc_up_sample_8m (8bits-mono) ** ** Description Given the source (p_src) audio data and ** source speed (src_sps, samples per second), @@ -155,13 +153,11 @@ extern int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, ** The number of bytes used in p_src (in *p_ret) ** *******************************************************************************/ -extern int bta_av_sbc_up_sample_8m (void *p_src, void *p_dst, - uint32_t src_samples, uint32_t dst_samples, - uint32_t *p_ret); +int a2d_sbc_up_sample_8m(void *p_src, void *p_dst, uint32_t src_samples, + uint32_t dst_samples, uint32_t *p_ret); #ifdef __cplusplus } #endif -#endif /* BTA_AV_SBC_H */ - +#endif /* A2D_SBC_UP_SAMPLE_H */ diff --git a/stack/include/a2d_vendor.h b/stack/include/a2d_vendor.h index eb05d148a..16d3260fc 100644 --- a/stack/include/a2d_vendor.h +++ b/stack/include/a2d_vendor.h @@ -248,6 +248,14 @@ bool A2D_VendorGetPacketTimestamp(const uint8_t *p_codec_info, bool A2D_VendorBuildCodecHeader(const uint8_t *p_codec_info, BT_HDR *p_buf, uint16_t frames_per_packet); +// Gets the A2DP vendor encoder interface that can be used to encode and +// prepare A2DP packets for transmission - see |tA2D_ENCODER_INTERFACE|. +// |p_codec_info| contains the codec information. +// Returns the A2DP vendor encoder interface if the |p_codec_info| is valid and +// supported, otherwise NULL. +const tA2D_ENCODER_INTERFACE *A2D_VendorGetEncoderInterface( + const uint8_t *p_codec_info); + #ifdef __cplusplus } #endif diff --git a/stack/test/stack_a2d_test.cc b/stack/test/stack_a2d_test.cc index 87cae7e6c..95c29e70c 100644 --- a/stack/test/stack_a2d_test.cc +++ b/stack/test/stack_a2d_test.cc @@ -157,14 +157,14 @@ TEST(StackA2dpTest, test_init_default_codec) { TEST(StackA2dpTest, test_set_codec) { uint8_t codec_info_result[AVDT_CODEC_SIZE]; - const tA2D_AV_MEDIA_FEEDINGS feeding = { + const tA2D_FEEDING_PARAMS feeding_params = { .sampling_freq = 44100, .num_channel = 2, .bit_per_sample = 16 }; - tA2D_AV_MEDIA_FEEDINGS bad_feeding; + tA2D_FEEDING_PARAMS bad_feeding_params; - EXPECT_TRUE(A2D_SetCodec(&feeding, codec_info_result)); + EXPECT_TRUE(A2D_SetCodec(&feeding_params, codec_info_result)); // Compare the result codec with the local test codec info for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) { @@ -172,19 +172,19 @@ TEST(StackA2dpTest, test_set_codec) { } // Test invalid feeding - invalid num_channel - bad_feeding = feeding; - bad_feeding.num_channel = 3; - EXPECT_FALSE(A2D_SetCodec(&bad_feeding, codec_info_result)); + bad_feeding_params = feeding_params; + bad_feeding_params.num_channel = 3; + EXPECT_FALSE(A2D_SetCodec(&bad_feeding_params, codec_info_result)); // Test invalid feeding - invalid bit_per_sample - bad_feeding = feeding; - bad_feeding.bit_per_sample = 7; - EXPECT_FALSE(A2D_SetCodec(&bad_feeding, codec_info_result)); + bad_feeding_params = feeding_params; + bad_feeding_params.bit_per_sample = 7; + EXPECT_FALSE(A2D_SetCodec(&bad_feeding_params, codec_info_result)); // Test invalid feeding - invalid sampling_freq - bad_feeding = feeding; - bad_feeding.sampling_freq = 7999; - EXPECT_FALSE(A2D_SetCodec(&bad_feeding, codec_info_result)); + bad_feeding_params = feeding_params; + bad_feeding_params.sampling_freq = 7999; + EXPECT_FALSE(A2D_SetCodec(&bad_feeding_params, codec_info_result)); } TEST(StackA2dpTest, test_build_src2sink_config) { -- 2.11.0