From 4cff8923044f0166f7f31089a2c8dfbb3cf3ce03 Mon Sep 17 00:00:00 2001 From: "jinyao.yu" <jinyao.yu@mediatek.com> Date: Mon, 19 Dec 2022 12:19:47 +0800 Subject: [PATCH] Add A2DP src and sink co-exist feature btif layer (2/5) [Description] Add A2DP src and sink co-exist feature, that we can connect both sink and src remote device at the same time while only keep 1 streaming. Bug: 256938279 Test: A2DP src/sink connect, streaming successully, net_test_btif_rc unit test pass Change-Id: I89ee8391f53daffaa992a5e7fafba36635419641 --- system/btif/Android.bp | 4 +- system/btif/avrcp/avrcp_service.cc | 10 +- system/btif/avrcp/avrcp_service.h | 4 + system/btif/include/btif_a2dp.h | 2 +- system/btif/include/btif_av.h | 25 + system/btif/src/btif_a2dp.cc | 14 +- system/btif/src/btif_av.cc | 716 ++++++++++++++++++++++-- system/btif/src/btif_rc.cc | 245 +++++++- system/btif/test/btif_rc_test.cc | 299 +++++++++- system/test/mock/mock_stack_avrc_api.cc | 7 +- 10 files changed, 1251 insertions(+), 75 deletions(-) diff --git a/system/btif/Android.bp b/system/btif/Android.bp index 113ffd0a2ce..a8850a5314c 100644 --- a/system/btif/Android.bp +++ b/system/btif/Android.bp @@ -397,6 +397,9 @@ cc_test { include_dirs: btifCommonIncludes, srcs: [ ":TestCommonLogMsg", + ":TestCommonMockFunctions", + ":TestMockCommon", + ":TestMockOsi", "test/btif_rc_test.cc", ], header_libs: ["libbluetooth_headers"], @@ -411,7 +414,6 @@ cc_test { "libbt-protos-lite", "libchrome", "libevent", - "libosi", "libosi-AllocationTestHarness", ], target: { diff --git a/system/btif/avrcp/avrcp_service.cc b/system/btif/avrcp/avrcp_service.cc index a960298d163..7cf4bafaa83 100644 --- a/system/btif/avrcp/avrcp_service.cc +++ b/system/btif/avrcp/avrcp_service.cc @@ -109,7 +109,7 @@ class AvrcpInterfaceImpl : public AvrcpInterface { uint16_t MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, BT_HDR* p_pkt) override { - return AVRC_MsgReq(handle, label, ctype, p_pkt); + return AVRC_MsgReq(handle, label, ctype, p_pkt, true); } void SaveControllerVersion(const RawAddress& bdaddr, @@ -684,5 +684,13 @@ void AvrcpService::DebugDump(int fd) { dprintf(fd, "%s", stream.str().c_str()); } +/** when a2dp connected, btif will start register vol changed, so we need a + * interface for it. */ +void AvrcpService::RegisterVolChanged(const RawAddress& bdaddr) { + LOG(INFO) << ": address=" << ADDRESS_TO_LOGGABLE_STR(bdaddr); + + connection_handler_->RegisterVolChanged(bdaddr); +} + } // namespace avrcp } // namespace bluetooth diff --git a/system/btif/avrcp/avrcp_service.h b/system/btif/avrcp/avrcp_service.h index 20a35444fba..7bd9081e00f 100644 --- a/system/btif/avrcp/avrcp_service.h +++ b/system/btif/avrcp/avrcp_service.h @@ -76,6 +76,10 @@ class AvrcpService : public MediaCallbacks { void SendPlayerSettingsChanged(std::vector<PlayerAttribute> attributes, std::vector<uint8_t> values) override; + /** when a2dp connected, btif will start register vol changed, so we need a + * interface for it. */ + void RegisterVolChanged(const RawAddress& bdaddr); + class ServiceInterfaceImpl : public ServiceInterface { public: void Init(MediaInterface* media_interface, diff --git a/system/btif/include/btif_a2dp.h b/system/btif/include/btif_a2dp.h index c4d95618b06..d9c44d11753 100644 --- a/system/btif/include/btif_a2dp.h +++ b/system/btif/include/btif_a2dp.h @@ -26,7 +26,7 @@ #include "types/raw_address.h" // Process 'idle' request from the BTIF state machine during initialization. -void btif_a2dp_on_idle(void); +void btif_a2dp_on_idle(const RawAddress& peer_addr); // Process 'start' request from the BTIF state machine to prepare for A2DP // streaming. diff --git a/system/btif/include/btif_av.h b/system/btif/include/btif_av.h index 09c0e2721c2..f85656c063a 100644 --- a/system/btif/include/btif_av.h +++ b/system/btif/include/btif_av.h @@ -46,6 +46,11 @@ RawAddress btif_av_sink_active_peer(void); */ bool btif_av_is_sink_enabled(void); +/** + * Check whether A2DP Source is enabled. + */ +bool btif_av_is_source_enabled(void); + /** * Start streaming. */ @@ -226,6 +231,14 @@ bool btif_av_is_a2dp_offload_running(void); */ bool btif_av_is_peer_silenced(const RawAddress& peer_address); +/** + * check the a2dp connect status + * + * @param address : checked device address + * + */ +bool btif_av_is_connected_addr(const RawAddress& peer_address); + /** * Set the dynamic audio buffer size * @@ -240,4 +253,16 @@ void btif_av_set_dynamic_audio_buffer_size(uint8_t dynamic_audio_buffer_size); */ void btif_av_set_low_latency(bool is_low_latency); +/** + * Check whether A2DP Source is enabled. + */ +extern bool btif_av_is_source_enabled(void); +extern bool btif_av_both_enable(void); +extern bool btif_av_src_sink_coexist_enabled(void); +extern bool btif_av_is_sink_enabled(void); +extern bool btif_av_is_connected_addr(const RawAddress& peer_address); +extern bool btif_av_peer_is_connected_sink(const RawAddress& peer_address); +extern bool btif_av_peer_is_connected_source(const RawAddress& peer_address); +extern bool btif_av_peer_is_sink(const RawAddress& peer_address); +extern bool btif_av_peer_is_source(const RawAddress& peer_address); #endif /* BTIF_AV_H */ diff --git a/system/btif/src/btif_a2dp.cc b/system/btif/src/btif_a2dp.cc index 9e469ce1441..58076fa8d94 100644 --- a/system/btif/src/btif_a2dp.cc +++ b/system/btif/src/btif_a2dp.cc @@ -38,9 +38,21 @@ #include <base/logging.h> -void btif_a2dp_on_idle(void) { +void btif_a2dp_on_idle(const RawAddress& peer_addr) { LOG_VERBOSE("Peer stream endpoint type:%s", peer_stream_endpoint_text(btif_av_get_peer_sep()).c_str()); + if (btif_av_src_sink_coexist_enabled()) { + bool is_sink = btif_av_peer_is_sink(peer_addr); + bool is_source = btif_av_peer_is_source(peer_addr); + LOG_INFO("## ON A2DP IDLE ## is_sink:%d is_source:%d", is_sink, is_source); + if (is_sink) { + btif_a2dp_source_on_idle(); + } else if (is_source) { + btif_a2dp_sink_on_idle(); + } + return; + } + if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) { btif_a2dp_source_on_idle(); } else if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) { diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index 019162cada2..bfc292d20ea 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -62,6 +62,10 @@ #include "types/bluetooth/uuid.h" #include "types/raw_address.h" +#ifdef OS_ANDROID +#include <a2dp.sysprop.h> +#endif + /***************************************************************************** * Constants & Macros *****************************************************************************/ @@ -137,6 +141,9 @@ class BtifAvEvent { class BtifAvPeer; static bt_status_t sink_set_active_device(const RawAddress& peer_address); +static void btif_av_sink_delete_active_peer(void); +static void btif_av_source_delete_active_peer(void); + // Should not need dedicated Suspend state as actual actions are no // different than Open state. Suspend flags are needed however to prevent // media task from trying to restart stream during remote Suspend or while @@ -279,6 +286,7 @@ class BtifAvPeer { bool IsSource() const { return (peer_sep_ == AVDT_TSEP_SRC); } bool IsSink() const { return (peer_sep_ == AVDT_TSEP_SNK); } uint8_t PeerSep() const { return peer_sep_; } + void SetSep(uint8_t sep_type) { peer_sep_ = sep_type; } /** * Get the local device's Service Class UUID * @@ -360,7 +368,7 @@ class BtifAvPeer { private: const RawAddress peer_address_; - const uint8_t peer_sep_; // SEP type of peer device + uint8_t peer_sep_; // SEP type of peer device tBTA_AV_HNDL bta_handle_; const uint8_t peer_id_; BtifAvStateMachine state_machine_; @@ -384,6 +392,7 @@ class BtifAvSource { : callbacks_(nullptr), enabled_(false), a2dp_offload_enabled_(false), + invalid_peer_check_(false), max_connected_peers_(kDefaultMaxConnectedAudioDevices) {} ~BtifAvSource(); @@ -396,7 +405,9 @@ class BtifAvSource { btav_source_callbacks_t* Callbacks() { return callbacks_; } bool Enabled() const { return enabled_; } bool A2dpOffloadEnabled() const { return a2dp_offload_enabled_; } - + void SetInvalidPeerCheck(bool invalid_peer_check) { + invalid_peer_check_ = invalid_peer_check; + } BtifAvPeer* FindPeer(const RawAddress& peer_address); BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle); BtifAvPeer* FindPeerByPeerId(uint8_t peer_id); @@ -500,10 +511,15 @@ class BtifAvSource { if (peer_address.IsEmpty()) { BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio source", __func__); - if (!bta_av_co_set_active_peer(peer_address)) { - LOG(WARNING) << __func__ - << ": unable to set active peer to empty in BtaAvCo"; + if (!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && + btif_av_sink_active_peer().IsEmpty())) { + if (!bta_av_co_set_active_peer(peer_address)) { + LOG(WARNING) << __func__ + << ": unable to set active peer to empty in BtaAvCo"; + } } + btif_a2dp_source_end_session(active_peer_); std::promise<void> shutdown_complete_promise; std::future<void> shutdown_complete_future = @@ -519,6 +535,7 @@ class BtifAvSource { return true; } + if (btif_av_src_sink_coexist_enabled()) btif_av_sink_delete_active_peer(); BtifAvPeer* peer = FindPeer(peer_address); if (peer == nullptr || !peer->IsConnected()) { LOG(ERROR) << __func__ << ": Error setting " @@ -537,6 +554,22 @@ class BtifAvSource { return true; } + void DeleteActivePeer(void) { + std::promise<void> shutdown_complete_promise; + BTIF_TRACE_EVENT("%s", __func__); + if (btif_av_sink_active_peer().IsEmpty()) { + if (!bta_av_co_set_active_peer(RawAddress::kEmpty)) { + LOG_WARN("%s : unable to set active peer to empty in BtaAvCo", + __func__); + } + } else { + LOG_WARN("%s : there is an active peer as source role", __func__); + } + btif_a2dp_source_end_session(active_peer_); + btif_a2dp_source_shutdown(std::move(shutdown_complete_promise)); + active_peer_ = RawAddress::kEmpty; + } + /** * Update source codec configuration for a peer. * @@ -561,6 +594,8 @@ class BtifAvSource { void RegisterAllBtaHandles(); void DeregisterAllBtaHandles(); void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle); + BtifAvPeer* popPeer(const RawAddress& peer_address); + void AddPeer(BtifAvPeer* peer); private: void CleanupAllPeers(); @@ -568,11 +603,15 @@ class BtifAvSource { btav_source_callbacks_t* callbacks_; bool enabled_; bool a2dp_offload_enabled_; + bool invalid_peer_check_; // pending to check at BTA_AV_OPEN_EVT int max_connected_peers_; std::map<RawAddress, BtifAvPeer*> peers_; std::set<RawAddress> silenced_peers_; RawAddress active_peer_; std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_; + std::mutex mutex_; + // protect for BtifAvSource::peers_ + std::recursive_mutex btifavsource_peer_lock_; }; class BtifAvSink { @@ -584,6 +623,7 @@ class BtifAvSink { BtifAvSink() : callbacks_(nullptr), enabled_(false), + invalid_peer_check_(false), max_connected_peers_(kDefaultMaxConnectedAudioDevices) {} ~BtifAvSink(); @@ -594,6 +634,9 @@ class BtifAvSink { btav_sink_callbacks_t* Callbacks() { return callbacks_; } bool Enabled() const { return enabled_; } + void SetInvalidPeerCheck(bool invalid_peer_check) { + invalid_peer_check_ = invalid_peer_check; + } BtifAvPeer* FindPeer(const RawAddress& peer_address); BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle); BtifAvPeer* FindPeerByPeerId(uint8_t peer_id); @@ -649,10 +692,15 @@ class BtifAvSink { if (peer_address.IsEmpty()) { BTIF_TRACE_EVENT("%s: peer address is empty, shutdown the Audio sink", __func__); - if (!bta_av_co_set_active_peer(peer_address)) { - LOG(WARNING) << __func__ - << ": unable to set active peer to empty in BtaAvCo"; + if (!btif_av_src_sink_coexist_enabled() || + (btif_av_src_sink_coexist_enabled() && + btif_av_source_active_peer().IsEmpty())) { + if (!bta_av_co_set_active_peer(peer_address)) { + LOG(WARNING) << __func__ + << ": unable to set active peer to empty in BtaAvCo"; + } } + btif_a2dp_sink_end_session(active_peer_); btif_a2dp_sink_shutdown(); active_peer_ = peer_address; @@ -660,6 +708,9 @@ class BtifAvSink { return true; } + if (btif_av_src_sink_coexist_enabled()) { + btif_av_source_delete_active_peer(); + } BtifAvPeer* peer = FindPeer(peer_address); if (peer == nullptr || !peer->IsConnected()) { LOG(ERROR) << __func__ << ": Error setting " @@ -678,17 +729,35 @@ class BtifAvSink { return true; } + void DeleteActivePeer(void) { + BTIF_TRACE_EVENT("%s", __func__); + if (btif_av_source_active_peer().IsEmpty()) { + if (!bta_av_co_set_active_peer(RawAddress::kEmpty)) { + LOG(WARNING) << __func__ + << ": unable to set active peer to empty in BtaAvCo"; + } + } else { + LOG(WARNING) << __func__ << ": there is an active peer as sink role"; + } + btif_a2dp_sink_end_session(active_peer_); + btif_a2dp_sink_shutdown(); + active_peer_ = RawAddress::kEmpty; + } + const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; } void RegisterAllBtaHandles(); void DeregisterAllBtaHandles(); void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle); + BtifAvPeer* popPeer(const RawAddress& peer_address); + void AddPeer(BtifAvPeer* peer); private: void CleanupAllPeers(); btav_sink_callbacks_t* callbacks_; bool enabled_; + bool invalid_peer_check_; // pending to check at BTA_AV_OPEN_EVT int max_connected_peers_; std::map<RawAddress, BtifAvPeer*> peers_; RawAddress active_peer_; @@ -741,6 +810,11 @@ static void btif_av_sink_initiate_av_open_timer_timeout(void* data); static void bta_av_sink_media_callback(const RawAddress& peer_address, tBTA_AV_EVT event, tBTA_AV_MEDIA* p_data); +extern bool btif_av_both_enable(void); +extern bool btif_av_is_connected_addr(const RawAddress& peer_address); +extern bool btif_av_peer_is_sink(const RawAddress& peer_address); +extern void btif_rc_check_pending_cmd(const RawAddress& peer_address); +extern void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr); static BtifAvPeer* btif_av_source_find_peer(const RawAddress& peer_address) { return btif_av_source.FindPeer(peer_address); @@ -749,11 +823,27 @@ static BtifAvPeer* btif_av_sink_find_peer(const RawAddress& peer_address) { return btif_av_sink.FindPeer(peer_address); } static BtifAvPeer* btif_av_find_peer(const RawAddress& peer_address) { + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + BtifAvPeer* peer = nullptr; + peer = btif_av_source_find_peer(peer_address); + if (nullptr == peer) { + return btif_av_sink_find_peer(peer_address); + } + return peer; + } if (btif_av_source.Enabled()) return btif_av_source_find_peer(peer_address); if (btif_av_sink.Enabled()) return btif_av_sink_find_peer(peer_address); return nullptr; } static BtifAvPeer* btif_av_find_active_peer() { + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + BtifAvPeer* peer = nullptr; + peer = btif_av_source_find_peer(btif_av_source.ActivePeer()); + if (nullptr == peer) { + return btif_av_sink_find_peer(btif_av_sink.ActivePeer()); + } + return peer; + } if (btif_av_source.Enabled()) return btif_av_source_find_peer(btif_av_source.ActivePeer()); if (btif_av_sink.Enabled()) @@ -761,6 +851,26 @@ static BtifAvPeer* btif_av_find_active_peer() { return nullptr; } +const RawAddress& btif_av_find_by_handle(tBTA_AV_HNDL bta_handle) { + BtifAvPeer* peer = nullptr; + if (btif_av_both_enable()) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + if (peer == nullptr) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + if (peer == nullptr) return RawAddress::kEmpty; + + return peer->PeerAddress(); + } + if (btif_av_source.Enabled()) + peer = btif_av_source.FindPeerByHandle(bta_handle); + if (btif_av_sink.Enabled()) peer = btif_av_sink.FindPeerByHandle(bta_handle); + + if (peer == nullptr) return RawAddress::kEmpty; + + return peer->PeerAddress(); +} + /***************************************************************************** * Local helper functions *****************************************************************************/ @@ -985,6 +1095,18 @@ const RawAddress& BtifAvPeer::ActivePeerAddress() const { if (IsSink()) { return btif_av_source.ActivePeer(); } + + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + RawAddress addr = btif_av_sink.ActivePeer(); + if (RawAddress::kEmpty == addr) { + LOG(WARNING) << __PRETTY_FUNCTION__ << ": A2DP peer " + << btif_av_source.ActivePeer() << " is Sink"; + return btif_av_source.ActivePeer(); + } + LOG(WARNING) << __PRETTY_FUNCTION__ << ": A2DP peer " + << btif_av_sink.ActivePeer() << " is Source"; + return btif_av_sink.ActivePeer(); + } LOG(FATAL) << __PRETTY_FUNCTION__ << ": A2DP peer " << ADDRESS_TO_LOGGABLE_STR(PeerAddress()) << " is neither Source nor Sink"; @@ -1029,8 +1151,8 @@ bt_status_t BtifAvSource::Init( if (!btif_a2dp_source_init()) { return BT_STATUS_FAIL; } - btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID); enabled_ = true; + btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID); return BT_STATUS_SUCCESS; } @@ -1083,6 +1205,7 @@ BtifAvPeer* BtifAvSource::FindPeerByPeerId(uint8_t peer_id) { BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address, tBTA_AV_HNDL bta_handle) { + std::unique_lock<std::mutex> lock1(mutex_); BTIF_TRACE_DEBUG("%s: peer_address=%s bta_handle=0x%x", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_handle); @@ -1092,7 +1215,14 @@ BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address, // Find next availabie Peer ID to use uint8_t peer_id; for (peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) { - if (FindPeerByPeerId(peer_id) == nullptr) break; + /* because the peer id may be in source cb and we cannot use it */ + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + if (FindPeerByPeerId(peer_id) == nullptr && + btif_av_sink.FindPeerByPeerId(peer_id) == nullptr) + break; + } else { + if (FindPeerByPeerId(peer_id) == nullptr) break; + } } if (peer_id == kPeerIdMax) { BTIF_TRACE_ERROR( @@ -1126,6 +1256,12 @@ BtifAvPeer* BtifAvSource::FindOrCreatePeer(const RawAddress& peer_address, bool BtifAvSource::AllowedToConnect(const RawAddress& peer_address) const { int connected = 0; + if (btif_av_src_sink_coexist_enabled() && invalid_peer_check_) { + LOG_INFO( + "invalid_peer_check_ so allow to connect here, when" + " BTA_AV_OPEN_EVT coming, would check again!"); + return true; + } // Count peers that are in the process of connecting or already connected for (auto it : peers_) { @@ -1135,6 +1271,10 @@ bool BtifAvSource::AllowedToConnect(const RawAddress& peer_address) const { case BtifAvStateMachine::kStateOpened: case BtifAvStateMachine::kStateStarted: if (peer->PeerAddress() == peer_address) { + /* we should check if another role is used */ + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) + break; + return true; // Already connected or accounted for } connected++; @@ -1143,6 +1283,18 @@ bool BtifAvSource::AllowedToConnect(const RawAddress& peer_address) const { break; } } + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + LOG_INFO("%s: connected=%d, max_connected_peers_=%d, sink_peers=%d", + __PRETTY_FUNCTION__, connected, max_connected_peers_, + (int)btif_av_sink.Peers().size()); + /* if source device connected, don't connect sink device */ + + if (connected >= max_connected_peers_ || !btif_av_sink.Peers().empty()) { + return false; + } else { + return true; + } + } return (connected < max_connected_peers_); } @@ -1216,6 +1368,23 @@ void BtifAvSource::BtaHandleRegistered(uint8_t peer_id, } } +BtifAvPeer* BtifAvSource::popPeer(const RawAddress& peer_address) { + auto it = peers_.find(peer_address); + if (it == peers_.end()) return nullptr; + BtifAvPeer* peer = it->second; + peers_.erase(it); + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + return peer; +} + +void BtifAvSource::AddPeer(BtifAvPeer* peer) { + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + peers_.insert(std::make_pair(peer->PeerAddress(), peer)); +} BtifAvSink::~BtifAvSink() { CleanupAllPeers(); } bt_status_t BtifAvSink::Init(btav_sink_callbacks_t* callbacks, @@ -1228,14 +1397,19 @@ bt_status_t BtifAvSink::Init(btav_sink_callbacks_t* callbacks, max_connected_peers_ = max_connected_audio_devices; callbacks_ = callbacks; - std::vector<btav_a2dp_codec_config_t> codec_priorities; // Default priorities - bta_av_co_init(codec_priorities); + /** source will have this configuration, but sink don't have, so don't + * overwrite it. */ + if (!btif_av_source.Enabled()) { + std::vector<btav_a2dp_codec_config_t> + codec_priorities; // Default priorities + bta_av_co_init(codec_priorities); + } if (!btif_a2dp_sink_init()) { return BT_STATUS_FAIL; } - btif_enable_service(BTA_A2DP_SINK_SERVICE_ID); enabled_ = true; + btif_enable_service(BTA_A2DP_SINK_SERVICE_ID); return BT_STATUS_SUCCESS; } @@ -1297,7 +1471,15 @@ BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address, // Find next availabie Peer ID to use uint8_t peer_id; for (peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) { - if (FindPeerByPeerId(peer_id) == nullptr) break; + /* because the peer id may be in source cb and we cannot use it */ + if (btif_av_both_enable()) { + if (FindPeerByPeerId(peer_id) == nullptr && + btif_av_source.FindPeerByPeerId(peer_id) == nullptr) + break; + + } else { + if (FindPeerByPeerId(peer_id) == nullptr) break; + } } if (peer_id == kPeerIdMax) { BTIF_TRACE_ERROR( @@ -1335,6 +1517,12 @@ BtifAvPeer* BtifAvSink::FindOrCreatePeer(const RawAddress& peer_address, bool BtifAvSink::AllowedToConnect(const RawAddress& peer_address) const { int connected = 0; + if (btif_av_src_sink_coexist_enabled() && invalid_peer_check_) { + LOG_INFO( + "invalid_peer_check_ so allow to connect here, when" + " BTA_AV_OPEN_EVT coming, would check again!"); + return true; + } // Count peers that are in the process of connecting or already connected for (auto it : peers_) { const BtifAvPeer* peer = it.second; @@ -1343,6 +1531,8 @@ bool BtifAvSink::AllowedToConnect(const RawAddress& peer_address) const { case BtifAvStateMachine::kStateOpened: case BtifAvStateMachine::kStateStarted: if (peer->PeerAddress() == peer_address) { + /* we should check if another role is used */ + if (btif_av_both_enable()) break; return true; // Already connected or accounted for } connected++; @@ -1351,6 +1541,14 @@ bool BtifAvSink::AllowedToConnect(const RawAddress& peer_address) const { break; } } + if (btif_av_both_enable()) { + LOG_INFO("connected=%d, max_connected_peers_=%d, source_peers=%d", + connected, max_connected_peers_, + (int)btif_av_source.Peers().size()); + /* if source device connected, don't connect sink device */ + return (connected < max_connected_peers_) && btif_av_source.Peers().empty(); + } + return (connected < max_connected_peers_); } @@ -1423,6 +1621,24 @@ void BtifAvSink::BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle) { } } +BtifAvPeer* BtifAvSink::popPeer(const RawAddress& peer_address) { + auto it = peers_.find(peer_address); + if (it == peers_.end()) return nullptr; + BtifAvPeer* peer = it->second; + peers_.erase(it); + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + return peer; +} + +void BtifAvSink::AddPeer(BtifAvPeer* peer) { + LOG_INFO("%s: peer_address=%s, state=%d", __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + peer->StateMachine().StateId()); + peers_.insert(std::make_pair(peer->PeerAddress(), peer)); +} + void BtifAvStateMachine::StateIdle::OnEnter() { BTIF_TRACE_DEBUG("%s: Peer %s", __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); @@ -1432,7 +1648,7 @@ void BtifAvStateMachine::StateIdle::OnEnter() { // Stop A2DP if this is the active peer if (peer_.IsActivePeer() || peer_.ActivePeerAddress().IsEmpty()) { - btif_a2dp_on_idle(); + btif_a2dp_on_idle(peer_.PeerAddress()); } // Reset the active peer if this was the active peer and @@ -1551,10 +1767,20 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { // Check whether connection is allowed if (peer_.IsSink()) { can_connect = btif_av_source.AllowedToConnect(peer_.PeerAddress()); - if (!can_connect) src_disconnect_sink(peer_.PeerAddress()); + if (!can_connect) { + if (btif_av_src_sink_coexist_enabled()) + BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle); + else + src_disconnect_sink(peer_.PeerAddress()); + } } else if (peer_.IsSource()) { can_connect = btif_av_sink.AllowedToConnect(peer_.PeerAddress()); - if (!can_connect) sink_disconnect_src(peer_.PeerAddress()); + if (!can_connect) { + if (btif_av_src_sink_coexist_enabled()) + BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle); + else + sink_disconnect_src(peer_.PeerAddress()); + } } if (!can_connect) { BTIF_TRACE_ERROR( @@ -1563,14 +1789,27 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { __PRETTY_FUNCTION__, ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); break; } - if (btif_av_source.Enabled()) { - alarm_set_on_mloop( - peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, - btif_av_source_initiate_av_open_timer_timeout, &peer_); - } else if (btif_av_sink.Enabled()) { - alarm_set_on_mloop(peer_.AvOpenOnRcTimer(), - BtifAvPeer::kTimeoutAvOpenOnRcMs, - btif_av_sink_initiate_av_open_timer_timeout, &peer_); + /* if peer is source, then start timer for sink connect to src */ + if (btif_av_src_sink_coexist_enabled()) { + if (peer_.IsSource()) { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_sink_initiate_av_open_timer_timeout, &peer_); + } else { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_source_initiate_av_open_timer_timeout, &peer_); + } + } else { + if (btif_av_source.Enabled()) { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_source_initiate_av_open_timer_timeout, &peer_); + } else if (btif_av_sink.Enabled()) { + alarm_set_on_mloop( + peer_.AvOpenOnRcTimer(), BtifAvPeer::kTimeoutAvOpenOnRcMs, + btif_av_sink_initiate_av_open_timer_timeout, &peer_); + } } if (event == BTA_AV_RC_OPEN_EVT) { btif_rc_handler(event, (tBTA_AV*)p_data); @@ -1610,6 +1849,44 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { if (p_bta_data->open.status == BTA_AV_SUCCESS) { peer_.SetEdr(p_bta_data->open.edr); + if (btif_av_src_sink_coexist_enabled()) { + BTIF_TRACE_DEBUG("%s: Peer %s sep=%d, open_sep=%d", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + peer_.PeerSep(), p_bta_data->open.sep); + /* if peer is wrong sep type, move it to BtifAvSxxx */ + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + BTIF_TRACE_DEBUG("set source invalid_peer_check as false"); + btif_av_source.SetInvalidPeerCheck(false); + } else { + BTIF_TRACE_DEBUG("set sink invalid_peer_check as false"); + btif_av_sink.SetInvalidPeerCheck(false); + } + if (peer_.PeerSep() != p_bta_data->open.sep) { + BtifAvPeer* tmp_peer = nullptr; + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + tmp_peer = btif_av_source.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + BTIF_TRACE_ERROR("error, not same peer"); + + btif_av_sink.AddPeer(tmp_peer); + } else { + tmp_peer = btif_av_sink.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + BTIF_TRACE_ERROR("error, not same peer"); + + btif_av_source.AddPeer(tmp_peer); + } + peer_.SetSep(p_bta_data->open.sep); + } + if (btif_rc_is_connected_peer(peer_.PeerAddress())) { + BTIF_TRACE_DEBUG("%s, AVRCP connected, update avrc sep", __func__); + BTA_AvSetPeerSep(peer_.PeerAddress(), peer_.PeerSep()); + } + btif_rc_check_pending_cmd(p_bta_data->open.bd_addr); + } CHECK(peer_.PeerSep() == p_bta_data->open.sep); can_connect = peer_.IsSink() @@ -1706,6 +1983,10 @@ void BtifAvStateMachine::StateOpening::OnEnter() { ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress())); // Inform the application that we are entering connecting state + if (btif_av_both_enable()) { + /* if peer connect to us, don't know which role it is */ + if (!peer_.SelfInitiatedConnection()) return; + } btif_report_connection_state(peer_.PeerAddress(), BTAV_CONNECTION_STATE_CONNECTING, bt_status_t::BT_STATUS_SUCCESS, BTA_AV_SUCCESS); @@ -1781,7 +2062,63 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, if (p_bta_data->open.status == BTA_AV_SUCCESS) { av_state = BtifAvStateMachine::kStateOpened; peer_.SetEdr(p_bta_data->open.edr); + if (btif_av_src_sink_coexist_enabled()) { + BTIF_TRACE_DEBUG("%s: Peer %s sep=%d, open_sep=%d", + __PRETTY_FUNCTION__, + ADDRESS_TO_LOGGABLE_CSTR(peer_.PeerAddress()), + peer_.PeerSep(), p_bta_data->open.sep); + /* if peer is wrong sep type, move it to BtifAvSxxx */ + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + BTIF_TRACE_DEBUG("set source invalid_peer_check as false"); + btif_av_source.SetInvalidPeerCheck(false); + } else { + BTIF_TRACE_DEBUG("set sink invalid_peer_check as false"); + btif_av_sink.SetInvalidPeerCheck(false); + } + if (peer_.PeerSep() != p_bta_data->open.sep) { + BtifAvPeer* tmp_peer = nullptr; + if (peer_.PeerSep() == AVDT_TSEP_SNK) { + tmp_peer = btif_av_source.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + BTIF_TRACE_ERROR("error, not same peer"); + + btif_av_sink.AddPeer(tmp_peer); + } else { + tmp_peer = btif_av_sink.popPeer(peer_.PeerAddress()); + + if (peer_.PeerAddress() != tmp_peer->PeerAddress()) + BTIF_TRACE_ERROR("error, not same peer"); + + btif_av_source.AddPeer(tmp_peer); + } + peer_.SetSep(p_bta_data->open.sep); + } + if (btif_rc_is_connected_peer(peer_.PeerAddress())) { + BTIF_TRACE_DEBUG("%s, AVRCP connected, update avrc sep", __func__); + BTA_AvSetPeerSep(peer_.PeerAddress(), peer_.PeerSep()); + } + btif_rc_check_pending_cmd(p_bta_data->open.bd_addr); + } CHECK(peer_.PeerSep() == p_bta_data->open.sep); + /** normally it can be checked in IDLE PENDING/CONNECT_REQ, in case: + * 1 speacker connected to DUT and phone connect DUT, because + * default + * connect req is as SINK peer. only at here, we can know which + * role + * it is.@{ */ + if (btif_av_src_sink_coexist_enabled()) { + bool can_connect = true; + if (peer_.IsSink()) { + can_connect = btif_av_source.AllowedToConnect(peer_.PeerAddress()); + if (!can_connect) src_disconnect_sink(peer_.PeerAddress()); + } else if (peer_.IsSource()) { + can_connect = btif_av_sink.AllowedToConnect(peer_.PeerAddress()); + if (!can_connect) sink_disconnect_src(peer_.PeerAddress()); + } + } + /** @} */ + // Report the connection state to the application btif_report_connection_state( peer_.PeerAddress(), BTAV_CONNECTION_STATE_CONNECTED, @@ -1824,7 +2161,9 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, } else if (peer_.IsSource() && (p_bta_data->open.status == BTA_AV_SUCCESS)) { // Bring up AVRCP connection as well - BTA_AvOpenRc(peer_.BtaHandle()); + if (btif_av_src_sink_coexist_enabled() && + btif_av_sink.AllowedToConnect(peer_.PeerAddress())) + BTA_AvOpenRc(peer_.BtaHandle()); } if (peer_.SelfInitiatedConnection()) { btif_queue_advance(); @@ -1834,6 +2173,13 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, case BTIF_AV_SINK_CONFIG_REQ_EVT: { const btif_av_sink_config_req_t* p_config_req = static_cast<const btif_av_sink_config_req_t*>(p_data); + /* before this point, we don't know it's role, actually peer is source */ + if (btif_av_both_enable()) { + btif_av_report_sink_audio_config_state(p_config_req->peer_address, + p_config_req->sample_rate, + p_config_req->channel_count); + break; + } if (peer_.IsSource()) { btif_av_report_sink_audio_config_state(p_config_req->peer_address, p_config_req->sample_rate, @@ -2562,6 +2908,24 @@ static void btif_report_connection_state(const RawAddress& peer_address, uint8_t error_code) { LOG_INFO("%s: peer_address=%s state=%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), state); + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer == nullptr) { + LOG_ERROR("%s: peer is null", __func__); + return; + } + + if (peer->IsSink()) { + do_in_jni_thread( + FROM_HERE, base::Bind(btif_av_source.Callbacks()->connection_state_cb, + peer_address, state, btav_error_t{})); + } else if (peer->IsSource()) { + do_in_jni_thread(FROM_HERE, + base::Bind(btif_av_sink.Callbacks()->connection_state_cb, + peer_address, state, btav_error_t{})); + } + return; + } if (btif_av_source.Enabled()) { do_in_jni_thread( @@ -2592,6 +2956,19 @@ static void btif_report_audio_state(const RawAddress& peer_address, LOG_INFO("%s: peer_address=%s state=%d", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address), state); + if (btif_av_both_enable()) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer->IsSink()) { + do_in_jni_thread(FROM_HERE, + base::Bind(btif_av_source.Callbacks()->audio_state_cb, + peer_address, state)); + } else if (peer->IsSource()) { + do_in_jni_thread(FROM_HERE, + base::Bind(btif_av_sink.Callbacks()->audio_state_cb, + peer_address, state)); + } + return; + } if (btif_av_source.Enabled()) { do_in_jni_thread(FROM_HERE, base::Bind(btif_av_source.Callbacks()->audio_state_cb, @@ -2693,6 +3070,84 @@ static void btif_av_query_mandatory_codec_priority( } } +static BtifAvPeer* btif_av_handle_both_peer(uint8_t peer_sep, + const RawAddress& peer_address, + tBTA_AV_HNDL bta_handle) { + BtifAvPeer* peer = nullptr; + + if (peer_address != RawAddress::kEmpty) { + if (btif_av_both_enable()) { + peer = btif_av_find_peer(peer_address); + /* if no this peer, default it's sink device */ + if (peer == nullptr) { + if (peer_sep == AVDT_TSEP_SRC) { + BTIF_TRACE_DEBUG("%s: peer_sep(%d), create a new source peer", + __func__, peer_sep); + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } else if (peer_sep == AVDT_TSEP_SNK) { + BTIF_TRACE_DEBUG("%s: peer_sep(%d), create a new sink peer", __func__, + peer_sep); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else { + btif_av_source.SetInvalidPeerCheck(true); + if (!btif_av_source.Peers().empty()) { + BTIF_TRACE_DEBUG( + "%s: peer_sep invalid, and already has sink peer," + " so try create a new sink peer", + __func__); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else if (!btif_av_sink.Peers().empty()) { + BTIF_TRACE_DEBUG( + "%s: peer_sep invalid, and already has source peer," + " so try create a new source peer", + __func__); + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } else { + BTIF_TRACE_DEBUG( + "%s: peer_sep invalid, and no active peer," + " so try create a new sink peer", + __func__); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } + } + } + } else { + if (peer_sep == AVDT_TSEP_SNK) { + BTIF_TRACE_DEBUG( + "%s: peer_sep(%d), only init src create a new source peer", + __func__, peer_sep); + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + BTIF_TRACE_DEBUG( + "%s: peer_sep(%d), only init sink create a new source peer", + __func__, peer_sep); + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } + } + if (peer == NULL && bta_handle != 0) { + if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + BTIF_TRACE_DEBUG("%s:peer is check 3", __func__); + } + } else if (bta_handle != 0) { + if (peer_sep == AVDT_TSEP_INVALID) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + /* if no this peer, default it's sink device */ + if (peer == nullptr) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + } else if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } + } + return peer; +} + /** * Process BTIF or BTA AV or BTA AVRCP events. The processing is done on the * JNI thread. @@ -2714,17 +3169,21 @@ static void btif_av_handle_event(uint8_t peer_sep, BtifAvPeer* peer = nullptr; // Find the peer - if (peer_address != RawAddress::kEmpty) { - if (peer_sep == AVDT_TSEP_SNK) { - peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); - } else if (peer_sep == AVDT_TSEP_SRC) { - peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); - } - } else if (bta_handle != kBtaHandleUnknown) { - if (peer_sep == AVDT_TSEP_SNK) { - peer = btif_av_source.FindPeerByHandle(bta_handle); - } else if (peer_sep == AVDT_TSEP_SRC) { - peer = btif_av_sink.FindPeerByHandle(bta_handle); + if (btif_av_src_sink_coexist_enabled()) { + peer = btif_av_handle_both_peer(peer_sep, peer_address, bta_handle); + } else { + if (peer_address != RawAddress::kEmpty) { + if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindOrCreatePeer(peer_address, bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindOrCreatePeer(peer_address, bta_handle); + } + } else if (bta_handle != kBtaHandleUnknown) { + if (peer_sep == AVDT_TSEP_SNK) { + peer = btif_av_source.FindPeerByHandle(bta_handle); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer = btif_av_sink.FindPeerByHandle(bta_handle); + } } } if (peer == nullptr) { @@ -2769,11 +3228,18 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, return; // Nothing to do } case BTA_AV_REGISTER_EVT: { - const tBTA_AV_REGISTER& registr = p_data->registr; - bta_handle = registr.hndl; - uint8_t peer_id = registr.app_id; // The PeerId is used as AppId - LOG_DEBUG("Register bta_handle=0x%x app_id=%d", bta_handle, - registr.app_id); + const tBTA_AV_REGISTER& reg = p_data->reg; + bta_handle = reg.hndl; + uint8_t peer_id = reg.app_id; // The PeerId is used as AppId + LOG_DEBUG("Register bta_handle=0x%x app_id=%d", bta_handle, reg.app_id); + if (btif_av_src_sink_coexist_enabled()) { + if (peer_sep == AVDT_TSEP_INVALID) { + if (reg.peer_sep == AVDT_TSEP_SNK) + peer_sep = AVDT_TSEP_SNK; + else + peer_sep = AVDT_TSEP_SRC; + } + } if (peer_sep == AVDT_TSEP_SNK) { btif_av_source.BtaHandleRegistered(peer_id, bta_handle); } else if (peer_sep == AVDT_TSEP_SRC) { @@ -2841,7 +3307,26 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, case BTA_AV_REMOTE_RSP_EVT: case BTA_AV_VENDOR_CMD_EVT: case BTA_AV_VENDOR_RSP_EVT: - case BTA_AV_META_MSG_EVT: + case BTA_AV_META_MSG_EVT: { + if (btif_av_src_sink_coexist_enabled()) { + if (peer_sep == AVDT_TSEP_INVALID) { + const tBTA_AV_REMOTE_CMD& rc_rmt_cmd = p_data->remote_cmd; + btif_rc_get_addr_by_handle(rc_rmt_cmd.rc_handle, peer_address); + if (peer_address == RawAddress::kEmpty) { + peer_address = btif_av_source.ActivePeer(); + if (peer_address == RawAddress::kEmpty) { + peer_address = btif_av_sink.ActivePeer(); + } + } + } else if (peer_sep == AVDT_TSEP_SNK) { + peer_address = btif_av_source.ActivePeer(); + } else if (peer_sep == AVDT_TSEP_SRC) { + peer_address = btif_av_sink.ActivePeer(); + } + break; + } else + FALLTHROUGH_INTENDED; + } case BTA_AV_OFFLOAD_START_RSP_EVT: { // TODO: Might be wrong - this code will be removed once those // events are received from the AVRCP module. @@ -2889,6 +3374,18 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, btif_av_handle_event(peer_sep, peer_address, bta_handle, btif_av_event); } +bool btif_av_both_enable(void) { + return (btif_av_sink.Enabled() && btif_av_source.Enabled()); +} + +bool btif_av_src_sink_coexist_enabled(void) { +#ifdef OS_ANDROID + return android::sysprop::bluetooth::A2dp::src_sink_coexist().value_or(false); +#else + return false; +#endif +} + static void bta_av_source_callback(tBTA_AV_EVT event, tBTA_AV* p_data) { BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV)); BTIF_TRACE_EVENT("%s: event=%s", __func__, btif_av_event.ToString().c_str()); @@ -2905,6 +3402,22 @@ static void bta_av_sink_callback(tBTA_AV_EVT event, tBTA_AV* p_data) { AVDT_TSEP_SRC /* peer_sep */, btif_av_event)); } +static void bta_av_event_callback(tBTA_AV_EVT event, tBTA_AV* p_data) { + if (btif_av_both_enable()) { + BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV)); + do_in_main_thread( + FROM_HERE, base::Bind(&btif_av_handle_bta_av_event, + AVDT_TSEP_INVALID /* peer_sep */, btif_av_event)); + return; + } + + if (btif_av_is_sink_enabled()) { + return bta_av_sink_callback(event, p_data); + } + + return bta_av_source_callback(event, p_data); +} + // TODO: All processing should be done on the JNI thread static void bta_av_sink_media_callback(const RawAddress& peer_address, tBTA_AV_EVT event, @@ -2993,6 +3506,15 @@ static void update_audio_track_gain(float gain) { static bt_status_t connect_int(RawAddress* peer_address, uint16_t uuid) { BTIF_TRACE_EVENT("%s: peer_address=%s uuid=0x%x", __func__, ADDRESS_TO_LOGGABLE_CSTR(*peer_address), uuid); + if (btif_av_both_enable()) { + const RawAddress tmp = *peer_address; + if (uuid == UUID_SERVCLASS_AUDIO_SOURCE) { + btif_av_source_dispatch_sm_event(tmp, BTIF_AV_CONNECT_REQ_EVT); + } else if (uuid == UUID_SERVCLASS_AUDIO_SINK) { + btif_av_sink_dispatch_sm_event(tmp, BTIF_AV_CONNECT_REQ_EVT); + } + return BT_STATUS_SUCCESS; + } auto connection_task = [](RawAddress* peer_address, uint16_t uuid) { BtifAvPeer* peer = nullptr; @@ -3035,16 +3557,20 @@ static void set_active_peer_int(uint8_t peer_sep, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); BtifAvPeer* peer = nullptr; if (peer_sep == AVDT_TSEP_SNK) { - if (!btif_av_source.SetActivePeer(peer_address, - std::move(peer_ready_promise))) { + if (!btif_av_src_sink_coexist_enabled() || (btif_av_src_sink_coexist_enabled() && + btif_av_both_enable() && (btif_av_sink.FindPeer(peer_address) == nullptr))) { + btif_av_source.SetActivePeer(peer_address, + std::move(peer_ready_promise)); BTIF_TRACE_ERROR("%s: Error setting %s as active Sink peer", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); } return; } if (peer_sep == AVDT_TSEP_SRC) { - if (!btif_av_sink.SetActivePeer(peer_address, - std::move(peer_ready_promise))) { + if (!btif_av_src_sink_coexist_enabled() || (btif_av_src_sink_coexist_enabled() && + btif_av_both_enable() && (btif_av_source.FindPeer(peer_address) == nullptr))) { + btif_av_sink.SetActivePeer(peer_address, + std::move(peer_ready_promise)); BTIF_TRACE_ERROR("%s: Error setting %s as active Source peer", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); } @@ -3246,6 +3772,8 @@ RawAddress btif_av_sink_active_peer(void) { return btif_av_sink.ActivePeer(); } bool btif_av_is_sink_enabled(void) { return btif_av_sink.Enabled(); } +bool btif_av_is_source_enabled(void) { return btif_av_source.Enabled(); } + void btif_av_stream_start(void) { LOG_INFO("%s", __func__); btif_av_source_dispatch_sm_event(btif_av_source_active_peer(), @@ -3419,7 +3947,12 @@ bt_status_t btif_av_source_execute_service(bool enable) { features |= BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_BROWSE; } - BTA_AvEnable(features, bta_av_source_callback); + if (btif_av_src_sink_coexist_enabled()) { + features |= BTA_AV_FEAT_SRC; + BTA_AvEnable(features, bta_av_event_callback); + } else { + BTA_AvEnable(features, bta_av_source_callback); + } btif_av_source.RegisterAllBtaHandles(); return BT_STATUS_SUCCESS; } @@ -3447,7 +3980,10 @@ bt_status_t btif_av_sink_execute_service(bool enable) { features |= BTA_AV_FEAT_DELAY_RPT; } - BTA_AvEnable(features, bta_av_sink_callback); + if (btif_av_src_sink_coexist_enabled()) + BTA_AvEnable(features, bta_av_event_callback); + else + BTA_AvEnable(features, bta_av_sink_callback); btif_av_sink.RegisterAllBtaHandles(); return BT_STATUS_SUCCESS; } @@ -3563,6 +4099,18 @@ void btif_av_acl_disconnected(const RawAddress& peer_address) { // Inform the application that ACL is disconnected and move to idle state LOG_INFO("%s: Peer %s : ACL Disconnected", __func__, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + if (btif_av_both_enable()) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer != nullptr) { + if (peer->IsSource()) { + btif_av_sink_dispatch_sm_event(peer_address, BTIF_AV_ACL_DISCONNECTED); + } else { + btif_av_source_dispatch_sm_event(peer_address, + BTIF_AV_ACL_DISCONNECTED); + } + } + return; + } if (btif_av_source.Enabled()) { btif_av_source_dispatch_sm_event(peer_address, BTIF_AV_ACL_DISCONNECTED); @@ -3709,3 +4257,73 @@ void btif_av_set_low_latency(bool is_low_latency) { btif_av_source_active_peer(), kBtaHandleUnknown, btif_av_event)); } + +static void btif_av_sink_delete_active_peer(void) { + btif_av_sink.DeleteActivePeer(); +} + +static void btif_av_source_delete_active_peer(void) { + btif_av_source.DeleteActivePeer(); +} + +bool btif_av_is_connected_addr(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_find_peer(peer_address); + if (peer == nullptr) { + BTIF_TRACE_WARNING("%s: No active peer found", __func__); + return false; + } + + bool connected = peer->IsConnected(); + BTIF_TRACE_DEBUG("%s: Peer %s is %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (connected) ? "connected" : "not connected"); + return connected; +} + +bool btif_av_peer_is_connected_sink(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_source_find_peer(peer_address); + if (peer == nullptr) { + BTIF_TRACE_WARNING("%s: No active peer found", __func__); + return false; + } + + bool connected = peer->IsConnected(); + BTIF_TRACE_DEBUG("%s: Peer %s is %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (connected) ? "connected" : "not connected"); + return connected; +} + +bool btif_av_peer_is_connected_source(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_sink_find_peer(peer_address); + if (peer == nullptr) { + BTIF_TRACE_WARNING("%s: No active peer found", __func__); + return false; + } + + bool connected = peer->IsConnected(); + BTIF_TRACE_DEBUG("%s: Peer %s is %s", __func__, + ADDRESS_TO_LOGGABLE_CSTR(peer->PeerAddress()), + (connected) ? "connected" : "not connected"); + return connected; +} + +bool btif_av_peer_is_sink(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_source_find_peer(peer_address); + if (peer == nullptr) { + BTIF_TRACE_WARNING("%s: No active peer found", __func__); + return false; + } + + return true; +} + +bool btif_av_peer_is_source(const RawAddress& peer_address) { + BtifAvPeer* peer = btif_av_sink_find_peer(peer_address); + if (peer == nullptr) { + BTIF_TRACE_WARNING("%s: No active peer found", __func__); + return false; + } + + return true; +} diff --git a/system/btif/src/btif_rc.cc b/system/btif/src/btif_rc.cc index e3812edc828..c5c00eb1e16 100644 --- a/system/btif/src/btif_rc.cc +++ b/system/btif/src/btif_rc.cc @@ -26,6 +26,7 @@ #include "btif_rc.h" +#include <base/logging.h> #include <errno.h> #include <fcntl.h> #include <hardware/bluetooth.h> @@ -40,6 +41,7 @@ #include "avrc_defs.h" #include "bta_api.h" #include "bta_av_api.h" +#include "btif/avrcp/avrcp_service.h" #include "btif_av.h" #include "btif_common.h" #include "btif_util.h" @@ -54,8 +56,6 @@ #include "stack/include/bt_hdr.h" #include "types/raw_address.h" -#include <base/logging.h> - #define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL) /***************************************************************************** @@ -220,8 +220,15 @@ typedef struct { uint64_t rc_playing_uid; bool rc_procedure_complete; rc_transaction_set_t transaction_set; + tBTA_AV_FEAT peer_ct_features; + tBTA_AV_FEAT peer_tg_features; + uint8_t launch_cmd_pending; /* true: getcap/regvolume */ } btif_rc_device_cb_t; +#define RC_PENDING_ACT_GET_CAP (1 << 0) +#define RC_PENDING_ACT_REG_VOL (1 << 1) +#define RC_PENDING_ACT_REPORT_CONN (1 << 2) + typedef struct { std::mutex lock; btif_rc_device_cb_t rc_multi_cb[BTIF_RC_NUM_CONN]; @@ -402,6 +409,23 @@ static const uint8_t media_attr_list_no_cover_art_size = *****************************************************************************/ bool check_cod(const RawAddress& remote_bdaddr, uint32_t cod); +void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr) { + BTIF_TRACE_DEBUG("%s: handle: 0x%x", __func__, handle); + for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { + if ((btif_rc_cb.rc_multi_cb[idx].rc_state != + BTRC_CONNECTION_STATE_DISCONNECTED) && + (btif_rc_cb.rc_multi_cb[idx].rc_handle == handle)) { + BTIF_TRACE_DEBUG("%s: btif_rc_cb.rc_multi_cb[idx].rc_handle: 0x%x", + __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle); + rc_addr = btif_rc_cb.rc_multi_cb[idx].rc_addr; + return; + } + } + BTIF_TRACE_ERROR("%s: returning NULL", __func__); + rc_addr = RawAddress::kEmpty; + return; +} + /***************************************************************************** * Functions *****************************************************************************/ @@ -442,6 +466,9 @@ void initialize_device(btif_rc_device_cb_t* p_dev) { p_dev->rc_features_processed = false; p_dev->rc_playing_uid = 0; p_dev->rc_procedure_complete = false; + p_dev->peer_ct_features = 0; + p_dev->peer_tg_features = 0; + p_dev->launch_cmd_pending = 0; // Leaving the value of the default constructor for the lbllock mutex is fine // but we still need to clear out the transaction label set @@ -531,7 +558,79 @@ void fill_avrc_attr_entry(tAVRC_ATTR_ENTRY* attr_vals, int num_attrs, void rc_cleanup_sent_cmd(void* p_data) { BTIF_TRACE_DEBUG("%s: ", __func__); } +void handle_rc_ctrl_features_all(btif_rc_device_cb_t* p_dev) { + if (!(p_dev->peer_tg_features & BTA_AV_FEAT_RCTG) && + (!(p_dev->peer_tg_features & BTA_AV_FEAT_RCCT) || + !(p_dev->peer_tg_features & BTA_AV_FEAT_ADV_CTRL))) { + return; + } + + int rc_features = 0; + + BTIF_TRACE_DEBUG( + "%s: peer_tg_features: 0x%x, rc_features_processed=%d, connected=%d, " + "peer_is_src:%d", + __func__, p_dev->peer_tg_features, p_dev->rc_features_processed, + btif_av_is_connected_addr(p_dev->rc_addr), + btif_av_peer_is_source(p_dev->rc_addr)); + + if ((p_dev->peer_tg_features & BTA_AV_FEAT_ADV_CTRL) && + (p_dev->peer_tg_features & BTA_AV_FEAT_RCCT)) { + rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME; + } + + if ((p_dev->peer_tg_features & BTA_AV_FEAT_METADATA) && + (p_dev->peer_tg_features & BTA_AV_FEAT_VENDOR) && + (p_dev->rc_features_processed != true)) { + rc_features |= BTRC_FEAT_METADATA; + + /* Mark rc features processed to avoid repeating + * the AVRCP procedure every time on receiving this + * update. + */ + p_dev->rc_features_processed = true; + } + + if (btif_av_is_connected_addr(p_dev->rc_addr)) { + if (btif_av_peer_is_source(p_dev->rc_addr)) { + p_dev->rc_features = p_dev->peer_tg_features; + if ((p_dev->peer_tg_features & BTA_AV_FEAT_METADATA) && + (p_dev->peer_tg_features & BTA_AV_FEAT_VENDOR)) { + getcapabilities_cmd(AVRC_CAP_COMPANY_ID, p_dev); + } + } + } else { + BTIF_TRACE_DEBUG("%s: %s is not connected, pending", __func__, + ADDRESS_TO_LOGGABLE_CSTR(p_dev->rc_addr)); + p_dev->launch_cmd_pending |= + (RC_PENDING_ACT_GET_CAP | RC_PENDING_ACT_REG_VOL); + } + + /* Add browsing feature capability */ + if (p_dev->peer_tg_features & BTA_AV_FEAT_BROWSE) { + rc_features |= BTRC_FEAT_BROWSE; + } + + /* Add cover art feature capability */ + if (p_dev->peer_tg_features & BTA_AV_FEAT_COVER_ARTWORK) { + rc_features |= BTRC_FEAT_COVER_ARTWORK; + } + + if (bt_rc_ctrl_callbacks != NULL) { + BTIF_TRACE_DEBUG("%s: Update rc features to CTRL: %d", __func__, + rc_features); + do_in_jni_thread(FROM_HERE, + base::Bind(bt_rc_ctrl_callbacks->getrcfeatures_cb, + p_dev->rc_addr, rc_features)); + } +} + void handle_rc_ctrl_features(btif_rc_device_cb_t* p_dev) { + if (btif_av_src_sink_coexist_enabled() && btif_av_both_enable()) { + handle_rc_ctrl_features_all(p_dev); + return; + } + if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG) && (!(p_dev->rc_features & BTA_AV_FEAT_RCCT) || !(p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL))) { @@ -575,14 +674,52 @@ void handle_rc_ctrl_features(btif_rc_device_cb_t* p_dev) { do_in_jni_thread(FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->getrcfeatures_cb, p_dev->rc_addr, rc_features)); } +void btif_rc_check_pending_cmd(const RawAddress& peer_address) { + btif_rc_device_cb_t* p_dev = NULL; + p_dev = btif_rc_get_device_by_bda(peer_address); + if (p_dev == NULL) { + BTIF_TRACE_ERROR("%s: p_dev NULL", __func__); + return; + } + + BTIF_TRACE_DEBUG( + "%s: launch_cmd_pending=%d, rc_connected=%d, peer_ct_features=0x%x, " + "peer_tg_features=0x%x", + __FUNCTION__, p_dev->launch_cmd_pending, p_dev->rc_connected, + p_dev->peer_ct_features, p_dev->peer_tg_features); + if (p_dev->launch_cmd_pending && p_dev->rc_connected) { + if ((p_dev->launch_cmd_pending & RC_PENDING_ACT_REG_VOL) && + btif_av_peer_is_sink(p_dev->rc_addr)) { + if (bluetooth::avrcp::AvrcpService::Get() != nullptr) { + bluetooth::avrcp::AvrcpService::Get()->RegisterVolChanged(peer_address); + } + } + if ((p_dev->launch_cmd_pending & RC_PENDING_ACT_GET_CAP) && + btif_av_peer_is_source(p_dev->rc_addr)) { + p_dev->rc_features = p_dev->peer_tg_features; + getcapabilities_cmd(AVRC_CAP_COMPANY_ID, p_dev); + } + if ((p_dev->launch_cmd_pending & RC_PENDING_ACT_REPORT_CONN) && + btif_av_peer_is_source(p_dev->rc_addr)) { + if (bt_rc_ctrl_callbacks != NULL) { + do_in_jni_thread(FROM_HERE, + base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, + true, false, p_dev->rc_addr)); + } + } + } + p_dev->launch_cmd_pending = 0; +} void handle_rc_ctrl_psm(btif_rc_device_cb_t* p_dev) { uint16_t cover_art_psm = p_dev->rc_cover_art_psm; BTIF_TRACE_DEBUG("%s: Update rc cover art psm to CTRL: %d", __func__, - cover_art_psm); - do_in_jni_thread(FROM_HERE, base::Bind( - bt_rc_ctrl_callbacks->get_cover_art_psm_cb, - p_dev->rc_addr, cover_art_psm)); + cover_art_psm); + if (bt_rc_ctrl_callbacks != NULL) { + do_in_jni_thread(FROM_HERE, + base::Bind(bt_rc_ctrl_callbacks->get_cover_art_psm_cb, + p_dev->rc_addr, cover_art_psm)); + } } void handle_rc_features(btif_rc_device_cb_t* p_dev) { @@ -640,7 +777,7 @@ void handle_rc_features(btif_rc_device_cb_t* p_dev) { } /*************************************************************************** - * Function handle_rc_connect + * Function handle_rc_browse_connect * * - Argument: tBTA_AV_RC_OPEN browse RC open data structure * @@ -663,9 +800,22 @@ void handle_rc_browse_connect(tBTA_AV_RC_BROWSE_OPEN* p_rc_br_open) { * probably not preferred anyways. */ if (p_rc_br_open->status == BTA_AV_SUCCESS) { p_dev->br_connected = true; - do_in_jni_thread(FROM_HERE, - base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, true, + if (btif_av_src_sink_coexist_enabled()) { + if (btif_av_peer_is_connected_source(p_dev->rc_addr)) { + if (bt_rc_ctrl_callbacks != NULL) { + do_in_jni_thread(FROM_HERE, + base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, + true, true, p_dev->rc_addr)); + } + } else { + p_dev->launch_cmd_pending |= RC_PENDING_ACT_REPORT_CONN; + BTIF_TRACE_API("%s: pending rc browse connection event", __func__); + } + } else { + do_in_jni_thread( + FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, true, true, p_dev->rc_addr)); + } } } @@ -690,6 +840,16 @@ void handle_rc_connect(tBTA_AV_RC_OPEN* p_rc_open) { BTIF_TRACE_ERROR("%s: Connect failed with error code: %d", __func__, p_rc_open->status); p_dev->rc_connected = false; + BTA_AvCloseRc(p_rc_open->rc_handle); + p_dev->rc_handle = 0; + p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED; + p_dev->rc_features = 0; + p_dev->peer_ct_features = 0; + p_dev->peer_tg_features = 0; + p_dev->launch_cmd_pending = 0; + p_dev->rc_vol_label = MAX_LABEL; + p_dev->rc_volume = MAX_VOLUME; + p_dev->rc_addr = RawAddress::kEmpty; return; } @@ -708,24 +868,31 @@ void handle_rc_connect(tBTA_AV_RC_OPEN* p_rc_open) { } p_dev->rc_addr = p_rc_open->peer_addr; p_dev->rc_features = p_rc_open->peer_features; - BTIF_TRACE_DEBUG("%s: handle_rc_connect in features: 0x%x out features 0x%x", - __func__, p_rc_open->peer_features, p_dev->rc_features); + p_dev->peer_ct_features = p_rc_open->peer_ct_features; + p_dev->peer_tg_features = p_rc_open->peer_tg_features; p_dev->rc_cover_art_psm = p_rc_open->cover_art_psm; - BTIF_TRACE_DEBUG("%s: cover art psm: 0x%x", - __func__, p_dev->rc_cover_art_psm); p_dev->rc_vol_label = MAX_LABEL; p_dev->rc_volume = MAX_VOLUME; + BTIF_TRACE_DEBUG( + "%s: handle_rc_connect in features=%#x, out features=%#x, " + "ct_feature=%#x, tg_feature=%#x, cover art psm=%#x", + __func__, p_rc_open->peer_features, p_dev->rc_features, + p_dev->peer_ct_features, p_dev->peer_tg_features, + p_dev->rc_cover_art_psm); + p_dev->rc_connected = true; p_dev->rc_handle = p_rc_open->rc_handle; p_dev->rc_state = BTRC_CONNECTION_STATE_CONNECTED; - /* on locally initiated connection we will get remote features as part of - * connect */ - if (p_dev->rc_features != 0 && bt_rc_callbacks != NULL) { - handle_rc_features(p_dev); - } p_dev->rc_playing_uid = RC_INVALID_TRACK_ID; + + if (btif_av_src_sink_coexist_enabled() && + !btif_av_peer_is_connected_source(p_dev->rc_addr)) { + p_dev->launch_cmd_pending |= RC_PENDING_ACT_REPORT_CONN; + BTIF_TRACE_API("%s: pending rc connection event", __func__); + return; + } if (bt_rc_ctrl_callbacks != NULL) { do_in_jni_thread(FROM_HERE, base::Bind(bt_rc_ctrl_callbacks->connection_state_cb, true, @@ -1009,8 +1176,17 @@ void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { pmeta_msg->code); p_dev->rc_notif[event_id - 1].bNotify = true; p_dev->rc_notif[event_id - 1].label = pmeta_msg->label; + /* this is sink(tg) feature, so it should not handle here */ + if (btif_av_both_enable() && event_id == AVRC_EVT_VOLUME_CHANGE) { + return; + } } + /* this is sink(tg) feature, so it should not handle here */ + if (btif_av_both_enable() && + avrc_command.cmd.pdu == AVRC_PDU_SET_ABSOLUTE_VOLUME) { + return; + } BTIF_TRACE_EVENT("%s: Passing received metamsg command to app. pdu: %s", __func__, dump_rc_pdu(avrc_command.cmd.pdu)); @@ -1086,7 +1262,19 @@ void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) { __func__); break; } + BTIF_TRACE_DEBUG("%s peer_ct_features:0x%x, peer_tg_features=0x%x", + __func__, p_data->rc_feat.peer_ct_features, + p_data->rc_feat.peer_tg_features); + if (btif_av_src_sink_coexist_enabled() && + (p_dev->peer_ct_features == p_data->rc_feat.peer_ct_features) && + (p_dev->peer_tg_features == p_data->rc_feat.peer_tg_features)) { + BTIF_TRACE_ERROR( + "do SDP twice, no need callback rc_feature to framework again"); + break; + } + p_dev->peer_ct_features = p_data->rc_feat.peer_ct_features; + p_dev->peer_tg_features = p_data->rc_feat.peer_tg_features; p_dev->rc_features = p_data->rc_feat.peer_features; if (bt_rc_callbacks != NULL) { handle_rc_features(p_dev); @@ -1792,6 +1980,8 @@ static bt_status_t init(btrc_callbacks_t* callbacks) { if (bt_rc_callbacks) return BT_STATUS_DONE; bt_rc_callbacks = callbacks; + if (bt_rc_ctrl_callbacks) return BT_STATUS_SUCCESS; + for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { initialize_device(&btif_rc_cb.rc_multi_cb[idx]); } @@ -1815,6 +2005,8 @@ static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks) { if (bt_rc_ctrl_callbacks) return BT_STATUS_DONE; bt_rc_ctrl_callbacks = callbacks; + if (bt_rc_callbacks) return BT_STATUS_SUCCESS; + for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) { initialize_device(&btif_rc_cb.rc_multi_cb[idx]); } @@ -3105,6 +3297,15 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg, return; } + if (btif_av_src_sink_coexist_enabled() && + p_rsp->event_id == AVRC_EVT_VOLUME_CHANGE) { + BTIF_TRACE_ERROR( + "%s: legacy TG don't handle absolute volume change. leave it to new " + "avrcp", + __func__); + return; + } + const uint32_t* attr_list = get_requested_attributes_list(p_dev); const uint8_t attr_list_size = get_requested_attributes_list_size(p_dev); @@ -4341,6 +4542,14 @@ static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) { BTIF_TRACE_WARNING( "%s: Error in parsing received metamsg command. status: 0x%02x", __func__, status); + if (true == btif_av_both_enable()) { + if (AVRC_PDU_GET_CAPABILITIES == avrc_cmd.pdu || + AVRC_PDU_GET_ELEMENT_ATTR == avrc_cmd.pdu || + AVRC_PDU_GET_PLAY_STATUS == avrc_cmd.pdu || + AVRC_PDU_GET_FOLDER_ITEMS == avrc_cmd.pdu || + AVRC_PDU_GET_ITEM_ATTRIBUTES == avrc_cmd.pdu) + return; + } send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu, status, pmeta_msg->p_msg->hdr.opcode); } else { diff --git a/system/btif/test/btif_rc_test.cc b/system/btif/test/btif_rc_test.cc index 48f3b748ae1..c10cee26342 100644 --- a/system/btif/test/btif_rc_test.cc +++ b/system/btif/test/btif_rc_test.cc @@ -28,21 +28,73 @@ #include "osi/test/AllocationTestHarness.h" #include "stack/include/bt_hdr.h" #include "stack/include/btm_api_types.h" +#include "test/common/mock_functions.h" +#include "test/mock/mock_osi_alarm.h" +#include "test/mock/mock_osi_allocator.h" +#include "test/mock/mock_osi_list.h" #include "types/raw_address.h" #undef LOG_TAG +#include "avrcp_service.h" #include "btif/src/btif_rc.cc" void allocation_tracker_uninit(void); +namespace bluetooth { +namespace avrcp { +int VolChanged = 0; +AvrcpService* AvrcpService::instance_ = nullptr; + +void AvrcpService::SendMediaUpdate(bool track_changed, bool play_state, + bool queue){}; +void AvrcpService::SendFolderUpdate(bool available_players, + bool addressed_players, bool uids){}; +void AvrcpService::SendActiveDeviceChanged(const RawAddress& address){}; +void AvrcpService::SendPlayerSettingsChanged( + std::vector<PlayerAttribute> attributes, std::vector<uint8_t> values){}; +void AvrcpService::ServiceInterfaceImpl::Init( + MediaInterface* media_interface, VolumeInterface* volume_interface, + PlayerSettingsInterface* player_settings_interface){}; +void AvrcpService::ServiceInterfaceImpl::RegisterBipServer(int psm){}; +void AvrcpService::ServiceInterfaceImpl::UnregisterBipServer(){}; +bool AvrcpService::ServiceInterfaceImpl::ConnectDevice( + const RawAddress& bdaddr) { + return true; +}; +bool AvrcpService::ServiceInterfaceImpl::DisconnectDevice( + const RawAddress& bdaddr) { + return true; +}; +void AvrcpService::ServiceInterfaceImpl::SetBipClientStatus( + const RawAddress& bdaddr, bool connected){}; +bool AvrcpService::ServiceInterfaceImpl::Cleanup() { return true; }; + +AvrcpService* AvrcpService::Get() { + CHECK(instance_ == nullptr); + instance_ = new AvrcpService(); + return instance_; +} + +void AvrcpService::RegisterVolChanged(const RawAddress& bdaddr) { + VolChanged++; +} +} // namespace avrcp +} // namespace bluetooth + namespace { int AVRC_BldResponse_ = 0; +int AVRC_BldCmd_ = 0; } // namespace uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING; uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING; +const RawAddress kDeviceAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); bool avrcp_absolute_volume_is_enabled() { return true; } -tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { return 0; } + +tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { + AVRC_BldCmd_++; + return 0; +} tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp, BT_HDR** pp_pkt) { AVRC_BldResponse_++; @@ -79,8 +131,8 @@ void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code, void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code, uint8_t* p_data, uint16_t len, uint32_t company_id) {} void btif_av_clear_remote_suspend_flag(void) {} -bool btif_av_is_connected(void) { return false; } -bool btif_av_is_sink_enabled(void) { return false; } +bool btif_av_is_connected(void) { return true; } +bool btif_av_is_sink_enabled(void) { return true; } RawAddress btif_av_sink_active_peer(void) { return RawAddress(); } RawAddress btif_av_source_active_peer(void) { return RawAddress(); } bool btif_av_stream_started_ready(void) { return false; } @@ -89,12 +141,29 @@ bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event, tBTIF_COPY_CBACK* p_copy_cback) { return BT_STATUS_SUCCESS; } +bool btif_av_src_sink_coexist_enabled() { return true; } +bool btif_av_is_connected_addr(const RawAddress& peer_address) { return true; } +bool btif_av_peer_is_connected_sink(const RawAddress& peer_address) { + return false; +} +bool btif_av_peer_is_connected_source(const RawAddress& peer_address) { + return true; +} +bool btif_av_peer_is_sink(const RawAddress& peer_address) { return false; } +bool btif_av_peer_is_source(const RawAddress& peer_address) { return true; } +bool btif_av_both_enable(void) { return true; } + const char* dump_rc_event(uint8_t event) { return nullptr; } const char* dump_rc_notification_event_id(uint8_t event_id) { return nullptr; } const char* dump_rc_pdu(uint8_t pdu) { return nullptr; } const char* dump_rc_opcode(uint8_t pdu) { return nullptr; } +static bluetooth::common::MessageLoopThread jni_thread("bt_jni_thread"); bt_status_t do_in_jni_thread(const base::Location& from_here, base::OnceClosure task) { + if (!jni_thread.DoInThread(from_here, std::move(task))) { + LOG(ERROR) << __func__ << ": Post task to task runner failed!"; + return BT_STATUS_FAIL; + } return BT_STATUS_SUCCESS; } bluetooth::common::MessageLoopThread* get_main_thread() { return nullptr; } @@ -133,3 +202,227 @@ TEST_F(BtifRcTest, get_element_attr_rsp) { CHECK(get_element_attr_rsp(bd_addr, num_attr, p_attrs) == BT_STATUS_SUCCESS); CHECK(AVRC_BldResponse_ == 1); } + +TEST_F(BtifRcTest, btif_rc_get_addr_by_handle) { + RawAddress get_bd_addr; + + btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + + btif_rc_get_addr_by_handle(0, get_bd_addr); + CHECK(kDeviceAddress == get_bd_addr); +} + +static btrc_ctrl_callbacks_t btrc_ctrl_callbacks = { + .size = sizeof(btrc_ctrl_callbacks_t), + .passthrough_rsp_cb = NULL, + .groupnavigation_rsp_cb = NULL, + .connection_state_cb = NULL, + .getrcfeatures_cb = NULL, + .setplayerappsetting_rsp_cb = NULL, + .playerapplicationsetting_cb = NULL, + .playerapplicationsetting_changed_cb = NULL, + .setabsvol_cmd_cb = NULL, + .registernotification_absvol_cb = NULL, + .track_changed_cb = NULL, + .play_position_changed_cb = NULL, + .play_status_changed_cb = NULL, + .get_folder_items_cb = NULL, + .change_folder_path_cb = NULL, + .set_browsed_player_cb = NULL, + .set_addressed_player_cb = NULL, + .addressed_player_changed_cb = NULL, + .now_playing_contents_changed_cb = NULL, + .available_player_changed_cb = NULL, + .get_cover_art_psm_cb = NULL, +}; + +struct rc_connection_state_cb_t { + bool rc_state; + bool bt_state; + RawAddress raw_address; +}; + +struct rc_feature_cb_t { + int feature; + RawAddress raw_address; +}; + +static std::promise<rc_connection_state_cb_t> g_btrc_connection_state_promise; +static std::promise<rc_connection_state_cb_t> + g_btrc_browse_connection_state_promise; +static std::promise<rc_feature_cb_t> g_btrc_feature; + +class BtifRcFeatureTest : public BtifRcTest { + protected: + void SetUp() override { + BtifRcTest::SetUp(); + init_ctrl(&btrc_ctrl_callbacks); + jni_thread.StartUp(); + btrc_ctrl_callbacks.getrcfeatures_cb = [](const RawAddress& bd_addr, + int features) { + rc_feature_cb_t rc_feature = { + .feature = features, + .raw_address = bd_addr, + }; + g_btrc_feature.set_value(rc_feature); + }; + } + + void TearDown() override { + bt_rc_ctrl_callbacks->getrcfeatures_cb = [](const RawAddress& bd_addr, + int features) {}; + BtifRcTest::TearDown(); + } +}; + +TEST_F(BtifRcFeatureTest, handle_rc_ctrl_features) { + AVRC_BldCmd_ = 0; + g_btrc_feature = std::promise<rc_feature_cb_t>(); + std::future<rc_feature_cb_t> future = g_btrc_feature.get_future(); + btif_rc_device_cb_t p_dev; + + p_dev.peer_tg_features = + (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT | + BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_BROWSE | + BTA_AV_FEAT_COVER_ARTWORK); + p_dev.rc_connected = true; + + handle_rc_ctrl_features(&p_dev); + CHECK(AVRC_BldCmd_ == 1); + + CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2))); + auto res = future.get(); + LOG_INFO("FEATURES:%d", res.feature); + CHECK(res.feature == (BTRC_FEAT_ABSOLUTE_VOLUME | BTRC_FEAT_METADATA | + BTRC_FEAT_BROWSE | BTRC_FEAT_COVER_ARTWORK)); +} + +class BtifRcBrowseConnectionTest : public BtifRcTest { + protected: + void SetUp() override { + BtifRcTest::SetUp(); + init_ctrl(&btrc_ctrl_callbacks); + jni_thread.StartUp(); + btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state, + const RawAddress& bd_addr) { + rc_connection_state_cb_t rc_connection_state = { + .rc_state = rc_state, + .bt_state = bt_state, + .raw_address = bd_addr, + }; + g_btrc_browse_connection_state_promise.set_value(rc_connection_state); + }; + } + + void TearDown() override { + bt_rc_ctrl_callbacks->connection_state_cb = + [](bool rc_state, bool bt_state, const RawAddress& bd_addr) {}; + BtifRcTest::TearDown(); + } +}; + +TEST_F(BtifRcBrowseConnectionTest, handle_rc_browse_connect) { + g_btrc_browse_connection_state_promise = + std::promise<rc_connection_state_cb_t>(); + std::future<rc_connection_state_cb_t> future = + g_btrc_browse_connection_state_promise.get_future(); + + tBTA_AV_RC_BROWSE_OPEN browse_data = { + .status = BTA_AV_SUCCESS, + .rc_handle = 0, + }; + + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = false; + + /* process unit test handle_rc_browse_connect */ + handle_rc_browse_connect(&browse_data); + CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2))); + auto res = future.get(); + CHECK(res.bt_state == true); +} + +class BtifRcConnectionTest : public BtifRcTest { + protected: + void SetUp() override { + BtifRcTest::SetUp(); + init_ctrl(&btrc_ctrl_callbacks); + jni_thread.StartUp(); + btrc_ctrl_callbacks.connection_state_cb = [](bool rc_state, bool bt_state, + const RawAddress& bd_addr) { + rc_connection_state_cb_t rc_connection_state = { + .rc_state = rc_state, + .bt_state = bt_state, + .raw_address = bd_addr, + }; + g_btrc_connection_state_promise.set_value(rc_connection_state); + }; + } + + void TearDown() override { + bt_rc_ctrl_callbacks->connection_state_cb = + [](bool rc_state, bool bt_state, const RawAddress& bd_addr) {}; + BtifRcTest::TearDown(); + } +}; + +TEST_F(BtifRcConnectionTest, btif_rc_check_pending_cmd) { + AVRC_BldCmd_ = 0; + g_btrc_connection_state_promise = std::promise<rc_connection_state_cb_t>(); + std::future<rc_connection_state_cb_t> future = + g_btrc_connection_state_promise.get_future(); + + btif_rc_cb.rc_multi_cb[0].rc_handle = 0xff; + btif_rc_cb.rc_multi_cb[0].rc_addr = kDeviceAddress; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = true; + btif_rc_cb.rc_multi_cb[0].launch_cmd_pending |= + (RC_PENDING_ACT_REG_VOL | RC_PENDING_ACT_GET_CAP | + RC_PENDING_ACT_REPORT_CONN); + + btif_rc_check_pending_cmd(kDeviceAddress); + CHECK(AVRC_BldCmd_ == 1); + + CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(3))); + auto res = future.get(); + CHECK(res.rc_state == true); +} + +TEST_F(BtifRcConnectionTest, BTA_AV_RC_OPEN_EVT) { + g_btrc_connection_state_promise = std::promise<rc_connection_state_cb_t>(); + std::future<rc_connection_state_cb_t> future = + g_btrc_connection_state_promise.get_future(); + + /* handle_rc_connect */ + tBTA_AV data = { + .rc_open = + { + .rc_handle = 0, + .cover_art_psm = 0, + .peer_features = 0, + .peer_ct_features = 0, + .peer_tg_features = (BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR | + BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT), + .peer_addr = kDeviceAddress, + .status = BTA_AV_SUCCESS, + }, + }; + btif_rc_cb.rc_multi_cb[0].rc_handle = 0; + btif_rc_cb.rc_multi_cb[0].rc_addr = RawAddress::kEmpty; + btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED; + btif_rc_cb.rc_multi_cb[0].rc_connected = false; + + btif_rc_handler(BTA_AV_RC_OPEN_EVT, &data); + + CHECK(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_connected == true); + CHECK(btif_rc_cb.rc_multi_cb[data.rc_open.rc_handle].rc_state == + BTRC_CONNECTION_STATE_CONNECTED); + + CHECK(std::future_status::ready == future.wait_for(std::chrono::seconds(2))); + auto res = future.get(); + CHECK(res.rc_state == true); +} diff --git a/system/test/mock/mock_stack_avrc_api.cc b/system/test/mock/mock_stack_avrc_api.cc index d7fb4513966..00ac4344f16 100644 --- a/system/test/mock/mock_stack_avrc_api.cc +++ b/system/test/mock/mock_stack_avrc_api.cc @@ -60,7 +60,7 @@ uint16_t AVRC_GetProfileVersion() { return 0; } uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype, - BT_HDR* p_pkt) { + BT_HDR* p_pkt, bool is_new_avrcp) { inc_func_call_count(__func__); return 0; } @@ -76,6 +76,11 @@ uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role) { void AVRC_SaveControllerVersion(const RawAddress& bdaddr, uint16_t version) { inc_func_call_count(__func__); } + +void AVRC_UpdateCcb(RawAddress* addr, uint32_t company_id) { + inc_func_call_count(__func__); +} + uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label, tAVRC_MSG_PASS* p_msg) { inc_func_call_count(__func__); return 0; -- GitLab