diff --git a/system/btif/co/bta_av_co.cc b/system/btif/co/bta_av_co.cc index de9f0dea0faf4c2754090346c14277722923c859..f703a8764722a1c8014e91ce307877fe4e12b459 100644 --- a/system/btif/co/bta_av_co.cc +++ b/system/btif/co/bta_av_co.cc @@ -132,6 +132,8 @@ static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec( static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer); static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected( A2dpCodecConfig& codec_config, tBTA_AV_CO_PEER* p_peer); +static bool bta_av_co_audio_update_selectable_codec( + A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer); static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer, const uint8_t* new_codec_config, uint8_t num_protect, @@ -848,21 +850,39 @@ static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec( // // Select the current codec configuration based on peer codec support. -// Return true on success, otherwise false. +// Furthermore, the local state for the remaining non-selected codecs is +// updated to reflect whether the codec is selectable. +// Return a pointer to the corresponding |tBTA_AV_CO_SINK| sink entry +// on success, otherwise NULL. // static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer) { + tBTA_AV_CO_SINK* p_sink = NULL; + + // Update all selectable codecs. + // This is needed to update the selectable parameters for each codec. + // NOTE: The selectable codec info is used only for informational purpose. + for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) { + APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__, + iter->name().c_str()); + bta_av_co_audio_update_selectable_codec(*iter, p_peer); + } + + // Select the codec for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) { APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str()); - // Try to select an open device for the codec - tBTA_AV_CO_SINK* p_sink = bta_av_co_audio_codec_selected(*iter, p_peer); + p_sink = bta_av_co_audio_codec_selected(*iter, p_peer); if (p_sink != NULL) { APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str()); - return p_sink; + break; } APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str()); } - return NULL; + // NOTE: Unconditionally dispatch the event to make sure a callback with + // the most recent codec info is generated. + btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0); + + return p_sink; } // Select an open device for the preferred codec specified by |codec_config|. @@ -896,8 +916,9 @@ static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected( codec_config.name().c_str()); return NULL; } - if (!bta_av_co_cb.codecs->setCodecConfig(p_sink->codec_caps, true, - new_codec_config)) { + if (!bta_av_co_cb.codecs->setCodecConfig( + p_sink->codec_caps, true /* is_capability */, new_codec_config, + true /* select_current_codec */)) { APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__, codec_config.name().c_str()); return NULL; @@ -906,11 +927,52 @@ static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected( bta_av_co_save_new_codec_config(p_peer, new_codec_config, p_sink->num_protect, p_sink->protect_info); - btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0); + // NOTE: Event BTIF_AV_SOURCE_CONFIG_UPDATED_EVT is dispatched by the caller return p_sink; } +// Update a selectable codec |codec_config| with the corresponding codec +// information from a peer device |p_peer|. +// Returns true if the codec is updated, otherwise false. +static bool bta_av_co_audio_update_selectable_codec( + A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer) { + uint8_t new_codec_config[AVDT_CODEC_SIZE]; + + APPL_TRACE_DEBUG("%s", __func__); + + // Find the peer sink for the codec + const tBTA_AV_CO_SINK* p_sink = NULL; + for (size_t index = 0; index < p_peer->num_sup_sinks; index++) { + btav_a2dp_codec_index_t peer_codec_index = + A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps); + if (peer_codec_index != codec_config.codecIndex()) { + continue; + } + if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) { + APPL_TRACE_DEBUG( + "%s: peer sink for codec %s does not support " + "Copy Protection", + __func__, codec_config.name().c_str()); + continue; + } + p_sink = &p_peer->sinks[index]; + break; + } + if (p_sink == NULL) { + // The peer sink device does not support this codec + return false; + } + if (!bta_av_co_cb.codecs->setCodecConfig( + p_sink->codec_caps, true /* is_capability */, new_codec_config, + false /* select_current_codec */)) { + APPL_TRACE_DEBUG("%s: cannot update source codec %s", __func__, + codec_config.name().c_str()); + return false; + } + return true; +} + static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer, const uint8_t* new_codec_config, uint8_t num_protect, @@ -973,9 +1035,11 @@ const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) { bool bta_av_co_set_codec_user_config( const btav_a2dp_codec_config_t& codec_user_config) { uint8_t result_codec_config[AVDT_CODEC_SIZE]; + const tBTA_AV_CO_SINK* p_sink = nullptr; bool restart_input = false; bool restart_output = false; bool config_updated = false; + bool success = true; // Find the peer that is currently open tBTA_AV_CO_PEER* p_peer = nullptr; @@ -988,11 +1052,11 @@ bool bta_av_co_set_codec_user_config( } if (p_peer == nullptr) { APPL_TRACE_ERROR("%s: no open peer to configure", __func__); - return false; + success = false; + goto done; } // Find the peer SEP codec to use - const tBTA_AV_CO_SINK* p_sink = nullptr; if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) { for (size_t index = 0; index < p_peer->num_sup_sinks; index++) { btav_a2dp_codec_index_t peer_codec_index = @@ -1008,7 +1072,8 @@ bool bta_av_co_set_codec_user_config( } if (p_sink == nullptr) { APPL_TRACE_ERROR("%s: cannot find peer SEP to configure", __func__); - return false; + success = false; + goto done; } tA2DP_ENCODER_INIT_PEER_PARAMS peer_params; @@ -1017,7 +1082,8 @@ bool bta_av_co_set_codec_user_config( codec_user_config, &peer_params, p_sink->codec_caps, result_codec_config, &restart_input, &restart_output, &config_updated)) { - return false; + success = false; + goto done; } if (restart_output) { @@ -1034,13 +1100,15 @@ bool bta_av_co_set_codec_user_config( p_peer->codec_config, num_protect, bta_av_co_cp_scmst); } - if (restart_input || config_updated) { - // NOTE: Currently, the input is restarted by sending an upcall - // and informing the Media Framework about the change. - btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0); - } +done: + // NOTE: We uncoditionally send the upcall even if there is no change + // or the user config failed. Thus, the caller would always know whether the + // request succeeded or failed. + // NOTE: Currently, the input is restarted by sending an upcall + // and informing the Media Framework about the change. + btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0); - return true; + return success; } // Sets the Over-The-Air preferred codec configuration. @@ -1211,4 +1279,8 @@ void bta_av_co_init(void) { bta_av_co_cb.codecs->init(); A2DP_InitDefaultCodec(bta_av_co_cb.codec_config); mutex_global_unlock(); + + // NOTE: Unconditionally dispatch the event to make sure a callback with + // the most recent codec info is generated. + btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0); } diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index bcfcbc4cb7b2b34b2717ea24a08eb3d4e85b5a4d..6428754479cde46b80de62ba4fa8af6aac7921c9 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -296,12 +296,14 @@ static void btif_update_source_codec(void* p_data) { static void btif_report_source_codec_state(UNUSED_ATTR void* p_data) { btav_a2dp_codec_config_t codec_config; - std::vector<btav_a2dp_codec_config_t> codec_capabilities; + std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities; + std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities; A2dpCodecs* a2dp_codecs = bta_av_get_a2dp_codecs(); if (a2dp_codecs == nullptr) return; - if (!a2dp_codecs->getCodecConfigAndCapabilities(&codec_config, - &codec_capabilities)) { + if (!a2dp_codecs->getCodecConfigAndCapabilities( + &codec_config, &codecs_local_capabilities, + &codecs_selectable_capabilities)) { BTIF_TRACE_WARNING( "BTIF_AV_SOURCE_CONFIG_UPDATED_EVT failed: " "cannot get codec config and capabilities"); @@ -309,7 +311,7 @@ static void btif_report_source_codec_state(UNUSED_ATTR void* p_data) { } if (bt_av_src_callbacks != NULL) { HAL_CBACK(bt_av_src_callbacks, audio_config_cb, codec_config, - codec_capabilities); + codecs_local_capabilities, codecs_selectable_capabilities); } } diff --git a/system/stack/a2dp/a2dp_aac.cc b/system/stack/a2dp/a2dp_aac.cc index 23207d04e42eee938621c18526c1e80bbdb64b2f..a8b09b35484af19f650e50603bed111f80635498 100644 --- a/system/stack/a2dp/a2dp_aac.cc +++ b/system/stack/a2dp/a2dp_aac.cc @@ -650,7 +650,28 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_AAC_CIE& config_cie, } A2dpCodecConfigAac::A2dpCodecConfigAac() - : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC") {} + : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC") { + // Compute the local capability + if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200; + } + if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000; + } + codec_local_capability_.bits_per_sample = a2dp_aac_caps.bits_per_sample; + if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_MONO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } +} A2dpCodecConfigAac::~A2dpCodecConfigAac() {} @@ -873,6 +894,8 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info, // Save the internal state btav_a2dp_codec_config_t saved_codec_config = codec_config_; btav_a2dp_codec_config_t saved_codec_capability = codec_capability_; + btav_a2dp_codec_config_t saved_codec_selectable_capability = + codec_selectable_capability_; btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_; btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_; uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE]; @@ -953,6 +976,24 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the sample frequency if there is no user preference do { + // Compute the selectable capability + if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_88200; + } + if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_96000; + } + if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break; // Compute the common capability @@ -1030,6 +1071,10 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the bits per sample if there is no user preference do { + // Compute the selectable capability + codec_selectable_capability_.bits_per_sample = + a2dp_aac_caps.bits_per_sample; + if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) break; @@ -1092,6 +1137,16 @@ bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the channel mode if there is no user preference do { + // Compute the selectable capability + if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break; // Compute the common capability @@ -1164,6 +1219,7 @@ fail: // Restore the internal state codec_config_ = saved_codec_config; codec_capability_ = saved_codec_capability; + codec_selectable_capability_ = saved_codec_selectable_capability; codec_user_config_ = saved_codec_user_config; codec_audio_config_ = saved_codec_audio_config; memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_)); diff --git a/system/stack/a2dp/a2dp_codec_config.cc b/system/stack/a2dp/a2dp_codec_config.cc index fb86eeee1a68ba7efb77cdba28e0ada290a49a36..f4440e6982d0af164c325fd8b5ee9c71d5059e5f 100644 --- a/system/stack/a2dp/a2dp_codec_config.cc +++ b/system/stack/a2dp/a2dp_codec_config.cc @@ -35,22 +35,34 @@ /* The Media Type offset within the codec info byte array */ #define A2DP_MEDIA_TYPE_OFFSET 1 +// Initializes the codec config. +// |codec_config| is the codec config to initialize. +// |codec_index| and |codec_priority| are the codec type and priority to use +// for the initialization. +static void init_btav_a2dp_codec_config( + btav_a2dp_codec_config_t* codec_config, btav_a2dp_codec_index_t codec_index, + btav_a2dp_codec_priority_t codec_priority) { + memset(codec_config, 0, sizeof(btav_a2dp_codec_config_t)); + codec_config->codec_type = codec_index; + codec_config->codec_priority = codec_priority; +} + A2dpCodecConfig::A2dpCodecConfig(btav_a2dp_codec_index_t codec_index, const std::string& name) : codec_index_(codec_index), name_(name) { setDefaultCodecPriority(); - memset(&codec_config_, 0, sizeof(codec_config_)); - codec_config_.codec_type = codec_index_; - - memset(&codec_capability_, 0, sizeof(codec_capability_)); - codec_capability_.codec_type = codec_index_; - - memset(&codec_user_config_, 0, sizeof(codec_user_config_)); - codec_user_config_.codec_type = codec_index_; - - memset(&codec_audio_config_, 0, sizeof(codec_audio_config_)); - codec_audio_config_.codec_type = codec_index_; + init_btav_a2dp_codec_config(&codec_config_, codec_index_, codecPriority()); + init_btav_a2dp_codec_config(&codec_capability_, codec_index_, + codecPriority()); + init_btav_a2dp_codec_config(&codec_local_capability_, codec_index_, + codecPriority()); + init_btav_a2dp_codec_config(&codec_selectable_capability_, codec_index_, + codecPriority()); + init_btav_a2dp_codec_config(&codec_user_config_, codec_index_, + BTAV_A2DP_CODEC_PRIORITY_DEFAULT); + init_btav_a2dp_codec_config(&codec_audio_config_, codec_index_, + BTAV_A2DP_CODEC_PRIORITY_DEFAULT); memset(ota_codec_config_, 0, sizeof(ota_codec_config_)); memset(ota_codec_peer_capability_, 0, sizeof(ota_codec_peer_capability_)); @@ -61,7 +73,7 @@ A2dpCodecConfig::~A2dpCodecConfig() {} void A2dpCodecConfig::setCodecPriority( btav_a2dp_codec_priority_t codec_priority) { - if (codec_priority == 0) { + if (codec_priority == BTAV_A2DP_CODEC_PRIORITY_DEFAULT) { // Compute the default codec priority setDefaultCodecPriority(); } else { @@ -71,7 +83,8 @@ void A2dpCodecConfig::setCodecPriority( void A2dpCodecConfig::setDefaultCodecPriority() { // Compute the default codec priority - codec_priority_ = 1000 * codec_index_ + 1; + uint32_t priority = 1000 * codec_index_ + 1; + codec_priority_ = static_cast<btav_a2dp_codec_priority_t>(priority); } A2dpCodecConfig* A2dpCodecConfig::createCodec( @@ -141,6 +154,20 @@ btav_a2dp_codec_config_t A2dpCodecConfig::getCodecCapability() { return codec_capability_; } +btav_a2dp_codec_config_t A2dpCodecConfig::getCodecLocalCapability() { + std::lock_guard<std::recursive_mutex> lock(codec_mutex_); + + // TODO: We should check whether the codec capability is valid + return codec_local_capability_; +} + +btav_a2dp_codec_config_t A2dpCodecConfig::getCodecSelectableCapability() { + std::lock_guard<std::recursive_mutex> lock(codec_mutex_); + + // TODO: We should check whether the codec capability is valid + return codec_selectable_capability_; +} + btav_a2dp_codec_config_t A2dpCodecConfig::getCodecUserConfig() { std::lock_guard<std::recursive_mutex> lock(codec_mutex_); @@ -172,7 +199,7 @@ uint8_t A2dpCodecConfig::getAudioBitsPerSample() { bool A2dpCodecConfig::isCodecConfigEmpty( const btav_a2dp_codec_config_t& codec_config) { return ( - (codec_config.codec_priority == 0) && + (codec_config.codec_priority == BTAV_A2DP_CODEC_PRIORITY_DEFAULT) && (codec_config.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) && (codec_config.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) && (codec_config.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) && @@ -324,7 +351,8 @@ A2dpCodecConfig* A2dpCodecs::findSourceCodecConfig( bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability, - uint8_t* p_result_codec_config) { + uint8_t* p_result_codec_config, + bool select_current_codec) { std::lock_guard<std::recursive_mutex> lock(codec_mutex_); A2dpCodecConfig* a2dp_codec_config = findSourceCodecConfig(p_peer_codec_info); if (a2dp_codec_config == nullptr) return false; @@ -332,7 +360,9 @@ bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info, p_result_codec_config)) { return false; } - current_codec_config_ = a2dp_codec_config; + if (select_current_codec) { + current_codec_config_ = a2dp_codec_config; + } return true; } @@ -522,7 +552,8 @@ fail: bool A2dpCodecs::getCodecConfigAndCapabilities( btav_a2dp_codec_config_t* p_codec_config, - std::vector<btav_a2dp_codec_config_t>* p_codec_capabilities) { + std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities, + std::vector<btav_a2dp_codec_config_t>* p_codecs_selectable_capabilities) { std::lock_guard<std::recursive_mutex> lock(codec_mutex_); if (current_codec_config_ != nullptr) { @@ -533,11 +564,26 @@ bool A2dpCodecs::getCodecConfigAndCapabilities( *p_codec_config = codec_config; } - std::vector<btav_a2dp_codec_config_t> codec_capabilities; + std::vector<btav_a2dp_codec_config_t> codecs_capabilities; for (auto codec : orderedSourceCodecs()) { - codec_capabilities.push_back(codec->getCodecCapability()); + codecs_capabilities.push_back(codec->getCodecLocalCapability()); + } + *p_codecs_local_capabilities = codecs_capabilities; + + codecs_capabilities.clear(); + for (auto codec : orderedSourceCodecs()) { + btav_a2dp_codec_config_t codec_capability = + codec->getCodecSelectableCapability(); + // Don't add entries that cannot be used + if ((codec_capability.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) || + (codec_capability.bits_per_sample == + BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) || + (codec_capability.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) { + continue; + } + codecs_capabilities.push_back(codec_capability); } - *p_codec_capabilities = codec_capabilities; + *p_codecs_selectable_capabilities = codecs_capabilities; return true; } diff --git a/system/stack/a2dp/a2dp_sbc.cc b/system/stack/a2dp/a2dp_sbc.cc index e8ab36a5965e37bdbad995053a3e711b51f9149b..1b09a8db1370fefdf7a0c5dfcc210c40832075a6 100644 --- a/system/stack/a2dp/a2dp_sbc.cc +++ b/system/stack/a2dp/a2dp_sbc.cc @@ -49,17 +49,19 @@ typedef struct { uint8_t alloc_method; /* Allocation method */ uint8_t min_bitpool; /* Minimum bitpool */ uint8_t max_bitpool; /* Maximum bitpool */ + btav_a2dp_codec_bits_per_sample_t bits_per_sample; } tA2DP_SBC_CIE; /* SBC SRC codec capabilities */ static const tA2DP_SBC_CIE a2dp_sbc_caps = { - A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */ - A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */ - A2DP_SBC_IE_BLOCKS_16, /* block_len */ - A2DP_SBC_IE_SUBBAND_8, /* num_subbands */ - A2DP_SBC_IE_ALLOC_MD_L, /* alloc_method */ - A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */ - A2DP_SBC_MAX_BITPOOL /* max_bitpool */ + A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */ + A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */ + A2DP_SBC_IE_BLOCKS_16, /* block_len */ + A2DP_SBC_IE_SUBBAND_8, /* num_subbands */ + A2DP_SBC_IE_ALLOC_MD_L, /* alloc_method */ + A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */ + A2DP_SBC_MAX_BITPOOL, /* max_bitpool */ + BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */ }; /* SBC SINK codec capabilities */ @@ -72,18 +74,20 @@ static const tA2DP_SBC_CIE a2dp_sbc_sink_caps = { (A2DP_SBC_IE_SUBBAND_4 | A2DP_SBC_IE_SUBBAND_8), /* num_subbands */ (A2DP_SBC_IE_ALLOC_MD_L | A2DP_SBC_IE_ALLOC_MD_S), /* alloc_method */ A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */ - A2DP_SBC_MAX_BITPOOL /* max_bitpool */ + A2DP_SBC_MAX_BITPOOL, /* max_bitpool */ + BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */ }; /* Default SBC codec configuration */ const tA2DP_SBC_CIE a2dp_sbc_default_config = { - A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */ - A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */ - A2DP_SBC_IE_BLOCKS_16, /* block_len */ - A2DP_SBC_IE_SUBBAND_8, /* num_subbands */ - A2DP_SBC_IE_ALLOC_MD_L, /* alloc_method */ - A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */ - A2DP_SBC_MAX_BITPOOL /* max_bitpool */ + A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */ + A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */ + A2DP_SBC_IE_BLOCKS_16, /* block_len */ + A2DP_SBC_IE_SUBBAND_8, /* num_subbands */ + A2DP_SBC_IE_ALLOC_MD_L, /* alloc_method */ + A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */ + A2DP_SBC_MAX_BITPOOL, /* max_bitpool */ + BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */ }; static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_sbc = { @@ -1014,7 +1018,7 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_SBC_CIE& config_cie, if (config_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000; - result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16; + result->bits_per_sample = config_cie.bits_per_sample; if (config_cie.ch_mode & A2DP_SBC_IE_CH_MD_MONO) result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; @@ -1026,7 +1030,28 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_SBC_CIE& config_cie, } A2dpCodecConfigSbc::A2dpCodecConfigSbc() - : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC") {} + : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC") { + // Compute the local capability + if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + codec_local_capability_.bits_per_sample = a2dp_sbc_caps.bits_per_sample; + if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_MONO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_JOINT) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_STEREO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } +} A2dpCodecConfigSbc::~A2dpCodecConfigSbc() {} @@ -1214,6 +1239,8 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info, // Save the internal state btav_a2dp_codec_config_t saved_codec_config = codec_config_; btav_a2dp_codec_config_t saved_codec_capability = codec_capability_; + btav_a2dp_codec_config_t saved_codec_selectable_capability = + codec_selectable_capability_; btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_; btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_; uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE]; @@ -1270,6 +1297,16 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the sample frequency if there is no user preference do { + // Compute the selectable capability + if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break; // Compute the common capability @@ -1326,6 +1363,10 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the bits per sample if there is no user preference do { + // Compute the selectable capability + codec_selectable_capability_.bits_per_sample = + a2dp_sbc_caps.bits_per_sample; + if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) break; @@ -1396,6 +1437,24 @@ bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the channel mode if there is no user preference do { + // Compute the selectable capability + if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (ch_mode & A2DP_SBC_IE_CH_MD_JOINT) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (ch_mode & A2DP_SBC_IE_CH_MD_STEREO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break; // Compute the common capability @@ -1538,6 +1597,7 @@ fail: // Restore the internal state codec_config_ = saved_codec_config; codec_capability_ = saved_codec_capability; + codec_selectable_capability_ = saved_codec_selectable_capability; codec_user_config_ = saved_codec_user_config; codec_audio_config_ = saved_codec_audio_config; memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_)); diff --git a/system/stack/a2dp/a2dp_vendor_aptx.cc b/system/stack/a2dp/a2dp_vendor_aptx.cc index 8de13eda38fb81fd07f51013ed7cb6c7d02d794b..812e05a69775892dc0c273533f7bf982ff03f639 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx.cc @@ -416,7 +416,22 @@ bool A2DP_VendorInitCodecConfigAptx(tAVDT_CFG* p_cfg) { } A2dpCodecConfigAptx::A2dpCodecConfigAptx() - : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, "aptX") {} + : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, "aptX") { + // Compute the local capability + if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_48000) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + codec_local_capability_.bits_per_sample = a2dp_aptx_caps.bits_per_sample; + if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_MONO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_STEREO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } +} A2dpCodecConfigAptx::~A2dpCodecConfigAptx() {} @@ -582,6 +597,8 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info, // Save the internal state btav_a2dp_codec_config_t saved_codec_config = codec_config_; btav_a2dp_codec_config_t saved_codec_capability = codec_capability_; + btav_a2dp_codec_config_t saved_codec_selectable_capability = + codec_selectable_capability_; btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_; btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_; uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE]; @@ -640,6 +657,16 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the sample frequency if there is no user preference do { + // Compute the selectable capability + if (sampleRate & A2DP_APTX_SAMPLERATE_44100) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (sampleRate & A2DP_APTX_SAMPLERATE_48000) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break; // Compute the common capability @@ -696,6 +723,10 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the bits per sample if there is no user preference do { + // Compute the selectable capability + codec_selectable_capability_.bits_per_sample = + a2dp_aptx_caps.bits_per_sample; + if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) break; @@ -753,6 +784,16 @@ bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the channel mode if there is no user preference do { + // Compute the selectable capability + if (channelMode & A2DP_APTX_CHANNELS_MONO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (channelMode & A2DP_APTX_CHANNELS_STEREO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break; // Compute the common capability @@ -831,6 +872,7 @@ fail: // Restore the internal state codec_config_ = saved_codec_config; codec_capability_ = saved_codec_capability; + codec_selectable_capability_ = saved_codec_selectable_capability; codec_user_config_ = saved_codec_user_config; codec_audio_config_ = saved_codec_audio_config; memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_)); diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc index c31486dc59e70745d22759c6ac057166cdad7c91..5bb4ddf5bf58d64f2f23191e5d0f9a8821ef470f 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_hd.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd.cc @@ -434,7 +434,22 @@ bool A2DP_VendorInitCodecConfigAptxHd(tAVDT_CFG* p_cfg) { } A2dpCodecConfigAptxHd::A2dpCodecConfigAptxHd() - : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, "aptX-HD") {} + : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, "aptX-HD") { + // Compute the local capability + if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + codec_local_capability_.bits_per_sample = a2dp_aptx_hd_caps.bits_per_sample; + if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_MONO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } +} A2dpCodecConfigAptxHd::~A2dpCodecConfigAptxHd() {} @@ -600,6 +615,8 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info, // Save the internal state btav_a2dp_codec_config_t saved_codec_config = codec_config_; btav_a2dp_codec_config_t saved_codec_capability = codec_capability_; + btav_a2dp_codec_config_t saved_codec_selectable_capability = + codec_selectable_capability_; btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_; btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_; uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE]; @@ -658,6 +675,16 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the sample frequency if there is no user preference do { + // Compute the selectable capability + if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break; // Compute the common capability @@ -714,6 +741,10 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the bits per sample if there is no user preference do { + // Compute the selectable capability + codec_selectable_capability_.bits_per_sample = + a2dp_aptx_hd_caps.bits_per_sample; + if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) break; @@ -771,6 +802,16 @@ bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the channel mode if there is no user preference do { + // Compute the selectable capability + if (channelMode & A2DP_APTX_HD_CHANNELS_MONO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break; // Compute the common capability @@ -859,6 +900,7 @@ fail: // Restore the internal state codec_config_ = saved_codec_config; codec_capability_ = saved_codec_capability; + codec_selectable_capability_ = saved_codec_selectable_capability; codec_user_config_ = saved_codec_user_config; codec_audio_config_ = saved_codec_audio_config; memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_)); diff --git a/system/stack/a2dp/a2dp_vendor_ldac.cc b/system/stack/a2dp/a2dp_vendor_ldac.cc index 0f3ae23546517fac1c3313545a24e1d7157404e7..66fa570d8b83c747cee3fa8fee5c232c6ef6cee1 100644 --- a/system/stack/a2dp/a2dp_vendor_ldac.cc +++ b/system/stack/a2dp/a2dp_vendor_ldac.cc @@ -518,6 +518,10 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_LDAC_CIE& config_cie, result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200; if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000; + if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) + result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_176400; + if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) + result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_192000; result->bits_per_sample = config_cie.bits_per_sample; @@ -530,7 +534,37 @@ UNUSED_ATTR static void build_codec_config(const tA2DP_LDAC_CIE& config_cie, } A2dpCodecConfigLdac::A2dpCodecConfigLdac() - : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, "LDAC") {} + : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, "LDAC") { + // Compute the local capability + if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200; + } + if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000; + } + if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_176400; + } + if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) { + codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_192000; + } + codec_local_capability_.bits_per_sample = a2dp_ldac_caps.bits_per_sample; + if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) { + codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } +} A2dpCodecConfigLdac::~A2dpCodecConfigLdac() {} @@ -785,6 +819,8 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info, // Save the internal state btav_a2dp_codec_config_t saved_codec_config = codec_config_; btav_a2dp_codec_config_t saved_codec_capability = codec_capability_; + btav_a2dp_codec_config_t saved_codec_selectable_capability = + codec_selectable_capability_; btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_; btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_; uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE]; @@ -866,6 +902,32 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the sample frequency if there is no user preference do { + // Compute the selectable capability + if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_44100; + } + if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_48000; + } + if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_88200; + } + if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_96000; + } + if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_176400; + } + if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) { + codec_selectable_capability_.sample_rate |= + BTAV_A2DP_CODEC_SAMPLE_RATE_192000; + } + if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break; // Compute the common capability @@ -947,6 +1009,10 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the bits per sample if there is no user preference do { + // Compute the selectable capability + codec_selectable_capability_.bits_per_sample = + a2dp_ldac_caps.bits_per_sample; + if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) break; @@ -1016,6 +1082,20 @@ bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info, // Select the channel mode if there is no user preference do { + // Compute the selectable capability + if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_MONO; + } + if (channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) { + codec_selectable_capability_.channel_mode |= + BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO; + } + if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break; // Compute the common capability @@ -1089,6 +1169,7 @@ fail: // Restore the internal state codec_config_ = saved_codec_config; codec_capability_ = saved_codec_capability; + codec_selectable_capability_ = saved_codec_selectable_capability; codec_user_config_ = saved_codec_user_config; codec_audio_config_ = saved_codec_audio_config; memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_)); diff --git a/system/stack/include/a2dp_codec_api.h b/system/stack/include/a2dp_codec_api.h index 80e4eec0af27c46635c974a0fbe2825a0f4babd6..63049eda95b2ea8abd980d839fe6d812bd9f5d4d 100644 --- a/system/stack/include/a2dp_codec_api.h +++ b/system/stack/include/a2dp_codec_api.h @@ -81,6 +81,17 @@ class A2dpCodecConfig { // Returns a copy of the current codec capability. btav_a2dp_codec_config_t getCodecCapability(); + // Gets the codec local capability. + // Returns a copy of the codec local capability. + btav_a2dp_codec_config_t getCodecLocalCapability(); + + // Gets the codec selectable capability. + // The capability is computed by intersecting the local codec's capability + // and the peer's codec capability. Any explicit user configuration is + // not included in the result. + // Returns a copy of the codec selectable capability. + btav_a2dp_codec_config_t getCodecSelectableCapability(); + // Gets the current codec user configuration. // Returns a copy of the current codec user configuration. btav_a2dp_codec_config_t getCodecUserConfig(); @@ -99,7 +110,8 @@ class A2dpCodecConfig { protected: // Sets the current priority of the codec to |codec_priority|. - // If |codec_priority| is 0, the priority is reset to its default value. + // If |codec_priority| is BTAV_A2DP_CODEC_PRIORITY_DEFAULT, the priority is + // reset to its default value. void setCodecPriority(btav_a2dp_codec_priority_t codec_priority); // Sets the current priority of the codec to its default value. @@ -175,6 +187,8 @@ class A2dpCodecConfig { btav_a2dp_codec_config_t codec_config_; btav_a2dp_codec_config_t codec_capability_; + btav_a2dp_codec_config_t codec_local_capability_; + btav_a2dp_codec_config_t codec_selectable_capability_; // The optional user configuration. The values (if set) are used // as a preference when there is a choice. If a particular value @@ -227,6 +241,8 @@ class A2dpCodecs { // to use. If |is_capability| is true, then |p_peer_codec_info| contains the // peer's A2DP Sink codec capability, otherwise it contains the peer's // preferred A2DP codec configuration to use. + // If the codec can be used and |select_current_codec| is true, then + // this codec is selected as the current one. // // The codec configuration is built by considering the optional user // configuration, the local codec capabilities, the peer's codec @@ -255,7 +271,8 @@ class A2dpCodecs { // The result codec configuration is stored in |p_result_codec_config|. // Returns true on success, othewise false. bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability, - uint8_t* p_result_codec_config); + uint8_t* p_result_codec_config, + bool select_current_codec); // Sets the user prefered codec configuration. // |codec_user_config| contains the preferred codec configuration. @@ -318,12 +335,16 @@ class A2dpCodecs { // Gets the current codec configuration and the capabilities of // all configured codecs. - // The codec configuration is stored in |p_codec_config|. - // The codecs capabilities are stored in |p_codec_capabilities|. + // The current codec configuration is stored in |p_codec_config|. + // Local device's codecs capabilities are stored in + // |p_codecs_local_capabilities|. + // The codecs capabilities that can be used between the local device + // and the remote device are stored in |p_codecs_selectable_capabilities|. // Returns true on success, otherwise false. bool getCodecConfigAndCapabilities( btav_a2dp_codec_config_t* p_codec_config, - std::vector<btav_a2dp_codec_config_t>* p_codec_capabilities); + std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities, + std::vector<btav_a2dp_codec_config_t>* p_codecs_selectable_capabilities); private: struct CompareBtBdaddr diff --git a/system/stack/test/stack_a2dp_test.cc b/system/stack/test/stack_a2dp_test.cc index 305a240dfc448541b86406674b5d2656f7fdc908..d3e40568a9b17801eb87ab3a7787882feba18668 100644 --- a/system/stack/test/stack_a2dp_test.cc +++ b/system/stack/test/stack_a2dp_test.cc @@ -835,8 +835,9 @@ TEST_F(A2dpCodecConfigTest, setCodecConfig) { codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_sbc_sink_capability); EXPECT_NE(codec_config, nullptr); - EXPECT_TRUE(a2dp_codecs->setCodecConfig(codec_info_sbc_sink_capability, true, - codec_info_result)); + EXPECT_TRUE(a2dp_codecs->setCodecConfig( + codec_info_sbc_sink_capability, true /* is_capability */, + codec_info_result, true /* select_current_codec */)); EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config); // Compare the result codec with the local test codec info for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) { @@ -850,8 +851,9 @@ TEST_F(A2dpCodecConfigTest, setCodecConfig) { codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_aac_sink_capability); EXPECT_NE(codec_config, nullptr); - EXPECT_TRUE(a2dp_codecs->setCodecConfig(codec_info_aac_sink_capability, true, - codec_info_result)); + EXPECT_TRUE(a2dp_codecs->setCodecConfig( + codec_info_aac_sink_capability, true /* is_capability */, + codec_info_result, true /* select_current_codec */)); EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config); // Compare the result codec with the local test codec info for (size_t i = 0; i < codec_info_aac[0] + 1; i++) { @@ -864,8 +866,9 @@ TEST_F(A2dpCodecConfigTest, setCodecConfig) { EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX); codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_sbc); EXPECT_NE(codec_config, nullptr); - EXPECT_TRUE( - a2dp_codecs->setCodecConfig(codec_info_sbc, false, codec_info_result)); + EXPECT_TRUE(a2dp_codecs->setCodecConfig( + codec_info_sbc, false /* is_capability */, codec_info_result, + true /* select_current_codec */)); EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config); // Compare the result codec with the local test codec info for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) { @@ -878,8 +881,9 @@ TEST_F(A2dpCodecConfigTest, setCodecConfig) { EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX); codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_aac); EXPECT_NE(codec_config, nullptr); - EXPECT_TRUE( - a2dp_codecs->setCodecConfig(codec_info_aac, false, codec_info_result)); + EXPECT_TRUE(a2dp_codecs->setCodecConfig( + codec_info_aac, false /* is_capability */, codec_info_result, + true /* select_current_codec */)); EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config); // Compare the result codec with the local test codec info for (size_t i = 0; i < codec_info_aac[0] + 1; i++) { @@ -890,8 +894,9 @@ TEST_F(A2dpCodecConfigTest, setCodecConfig) { uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE]; memset(codec_info_result, 0, sizeof(codec_info_result)); memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1)); - EXPECT_FALSE(a2dp_codecs->setCodecConfig(codec_info_sbc_test1, true, - codec_info_result)); + EXPECT_FALSE(a2dp_codecs->setCodecConfig( + codec_info_sbc_test1, true /* is_capability */, codec_info_result, + true /* select_current_codec */)); delete a2dp_codecs; }