From 32379e3062f8c83388937674ba02ff4a04446b37 Mon Sep 17 00:00:00 2001 From: Cheney Ni Date: Tue, 14 Apr 2020 14:25:20 +0800 Subject: [PATCH] A2DP: Don't select disabled optional codecs when local SRC reconnecting MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When local SRC is establishing a connection, the Bluetooth stack follows those default priorities to choose a codec, and A2dpService needs to judge again after this connection up event. If a user prefers the mandatory codec, the peer state is OPEN -> RECONFIG -> OPEN which is redundant but lousy. Since codecs preference is saved at the upper-layer, this change queries the mandatory codec, and raises the priority for more preferred codec while reconnecting from local. Bug: 134131114 Bug: 147572898 Test: Local A2DP initializes connections Change-Id: I110ffa463dd4c9ec62e18e1843b5aebc84d73093 Merged-In: I110ffa463dd4c9ec62e18e1843b5aebc84d73093 (cherry picked from commit 2fda2f0e415b2da9e7d5201bf8089492db88e73a) --- btif/co/bta_av_co.cc | 31 +++++++++++++++++++++++-- btif/include/btif_av.h | 8 +++++++ btif/src/btif_av.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++---- include/hardware/bt_av.h | 8 +++++++ 4 files changed, 100 insertions(+), 6 deletions(-) diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc index b2a02d9e9..708bb4076 100644 --- a/btif/co/bta_av_co.cc +++ b/btif/co/bta_av_co.cc @@ -958,8 +958,9 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) { return A2DP_FAIL; } - APPL_TRACE_DEBUG("%s: last Sink codec reached for peer %s", __func__, - p_peer->addr.ToString().c_str()); + APPL_TRACE_DEBUG("%s: last Sink codec reached for peer %s (local %s)", + __func__, p_peer->addr.ToString().c_str(), + p_peer->acceptor ? "acceptor" : "initiator"); // Select the Source codec const BtaAvCoSep* p_sink = nullptr; @@ -977,6 +978,32 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( return A2DP_FAIL; } } else { + if (btif_av_peer_prefers_mandatory_codec(p_peer->addr)) { + // Apply user preferred codec directly before first codec selected. + p_sink = FindPeerSink(p_peer, BTAV_A2DP_CODEC_INDEX_SOURCE_SBC); + if (p_sink != nullptr) { + APPL_TRACE_API("%s: mandatory codec preferred for peer %s", __func__, + p_peer->addr.ToString().c_str()); + btav_a2dp_codec_config_t high_priority_mandatory{ + .codec_type = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, + .codec_priority = BTAV_A2DP_CODEC_PRIORITY_HIGHEST, + // Using default settings for those untouched fields + }; + uint8_t result_codec_config[AVDT_CODEC_SIZE]; + bool restart_input = false; + bool restart_output = false; + bool config_updated = false; + tA2DP_ENCODER_INIT_PEER_PARAMS peer_params; + GetPeerEncoderParameters(p_peer->addr, &peer_params); + p_peer->GetCodecs()->setCodecUserConfig( + high_priority_mandatory, &peer_params, p_sink->codec_caps, + result_codec_config, &restart_input, &restart_output, + &config_updated); + } else { + APPL_TRACE_WARNING("%s: mandatory codec not found for peer %s", + __func__, p_peer->addr.ToString().c_str()); + } + } p_sink = SelectSourceCodec(p_peer); if (p_sink == nullptr) { APPL_TRACE_ERROR("%s: cannot set up codec for peer %s", __func__, diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h index adbc33324..8ddfc6ae8 100644 --- a/btif/include/btif_av.h +++ b/btif/include/btif_av.h @@ -114,6 +114,14 @@ bool btif_av_is_peer_edr(const RawAddress& peer_address); bool btif_av_peer_supports_3mbps(const RawAddress& peer_address); /** + * Check whether the mandatory codec is more preferred for this peer. + * + * @param peer_address the target peer address + * @return true if optional codecs are not preferred to be used + */ +bool btif_av_peer_prefers_mandatory_codec(const RawAddress& peer_address); + +/** * Report A2DP Source Codec State for a peer. * * @param peer_address the address of the peer to report diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc index ae5333332..1003b0f82 100644 --- a/btif/src/btif_av.cc +++ b/btif/src/btif_av.cc @@ -278,13 +278,18 @@ class BtifAvPeer { bool IsConnected() const; bool IsStreaming() const; - bool IsInSilenceMode() const { return is_silenced_; }; + bool IsInSilenceMode() const { return is_silenced_; } - void SetSilence(bool silence) { is_silenced_ = silence; }; + void SetSilence(bool silence) { is_silenced_ = silence; } // AVDTP delay reporting in 1/10 milliseconds - void SetDelayReport(uint16_t delay) { delay_report_ = delay; }; - uint16_t GetDelayReport() const { return delay_report_; }; + void SetDelayReport(uint16_t delay) { delay_report_ = delay; } + uint16_t GetDelayReport() const { return delay_report_; } + + void SetMandatoryCodecPreferred(bool preferred) { + mandatory_codec_preferred_ = preferred; + } + bool IsMandatoryCodecPreferred() const { return mandatory_codec_preferred_; } /** * Check whether any of the flags specified by the bitlags mask is set. @@ -335,6 +340,7 @@ class BtifAvPeer { bool self_initiated_connection_; bool is_silenced_; uint16_t delay_report_; + bool mandatory_codec_preferred_ = false; }; class BtifAvSource { @@ -682,6 +688,8 @@ static void btif_report_audio_state(const RawAddress& peer_address, btav_audio_state_t state); static void btif_av_report_sink_audio_config_state( const RawAddress& peer_address, int sample_rate, int channel_count); +static void btif_av_query_mandatory_codec_priority( + const RawAddress& peer_address); static void btif_av_source_initiate_av_open_timer_timeout(void* data); static void btif_av_sink_initiate_av_open_timer_timeout(void* data); static void bta_av_sink_media_callback(const RawAddress& peer_address, @@ -1459,6 +1467,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { } break; } + btif_av_query_mandatory_codec_priority(peer_.PeerAddress()); BTA_AvOpen(peer_.PeerAddress(), peer_.BtaHandle(), true, BTA_SEC_AUTHENTICATE, peer_.LocalUuidServiceClass()); peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateOpening); @@ -2439,6 +2448,36 @@ static void btif_av_report_sink_audio_config_state( } /** + * Call out to JNI / JAVA layers to retrieve whether the mandatory codec is more + * preferred than others. + * + * @param peer_address the peer address + */ +static void btif_av_query_mandatory_codec_priority( + const RawAddress& peer_address) { + auto query_priority = [](const RawAddress& peer_address) { + auto apply_priority = [](const RawAddress& peer_address, bool preferred) { + BtifAvPeer* peer = btif_av_source_find_peer(peer_address); + if (peer == nullptr) { + BTIF_TRACE_WARNING( + "btif_av_query_mandatory_codec_priority: peer is null"); + return; + } + peer->SetMandatoryCodecPreferred(preferred); + }; + bool preferred = + btif_av_source.Callbacks()->mandatory_codec_preferred_cb(peer_address); + if (preferred) { + do_in_main_thread( + FROM_HERE, base::BindOnce(apply_priority, peer_address, preferred)); + } + }; + if (btif_av_source.Enabled()) { + do_in_jni_thread(FROM_HERE, base::BindOnce(query_priority, peer_address)); + } +} + +/** * Process BTIF or BTA AV or BTA AVRCP events. The processing is done on the * JNI thread. * @@ -3255,6 +3294,16 @@ bool btif_av_peer_supports_3mbps(const RawAddress& peer_address) { return (is_connected && is3mbps); } +bool btif_av_peer_prefers_mandatory_codec(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer == nullptr) { + BTIF_TRACE_WARNING("%s: No peer found for peer_address=%s", __func__, + peer_address.ToString().c_str()); + return false; + } + return peer->IsMandatoryCodecPreferred(); +} + void btif_av_acl_disconnected(const RawAddress& peer_address) { // Inform the application that ACL is disconnected and move to idle state LOG_INFO(LOG_TAG, "%s: Peer %s : ACL Disconnected", __func__, @@ -3308,6 +3357,8 @@ static void btif_debug_av_peer_dump(int fd, const BtifAvPeer& peer) { dprintf(fd, " Self Initiated Connection: %s\n", peer.SelfInitiatedConnection() ? "true" : "false"); dprintf(fd, " Delay Reporting: %u\n", peer.GetDelayReport()); + dprintf(fd, " Codec Preferred: %s\n", + peer.IsMandatoryCodecPreferred() ? "Mandatory" : "Optional"); } static void btif_debug_av_source_dump(int fd) { diff --git a/include/hardware/bt_av.h b/include/hardware/bt_av.h index 41f512b6d..c4c0ecc82 100644 --- a/include/hardware/bt_av.h +++ b/include/hardware/bt_av.h @@ -266,6 +266,13 @@ typedef void (*btav_audio_sink_config_callback)(const RawAddress& bd_addr, uint32_t sample_rate, uint8_t channel_count); +/** Callback for querying whether the mandatory codec is more preferred. + * Used only for the A2DP Source interface. + * Return true if optional codecs are not preferred. + */ +typedef bool (*btav_mandatory_codec_preferred_callback)( + const RawAddress& bd_addr); + /** BT-AV A2DP Source callback structure. */ typedef struct { /** set to sizeof(btav_source_callbacks_t) */ @@ -273,6 +280,7 @@ typedef struct { btav_connection_state_callback connection_state_cb; btav_audio_state_callback audio_state_cb; btav_audio_source_config_callback audio_config_cb; + btav_mandatory_codec_preferred_callback mandatory_codec_preferred_cb; } btav_source_callbacks_t; /** BT-AV A2DP Sink callback structure. */ -- 2.11.0