From 95ba6a2181f225b75145bb2c62c28b4598cd8c5b Mon Sep 17 00:00:00 2001 From: Alice Kuo Date: Thu, 4 Nov 2021 19:28:10 +0800 Subject: [PATCH] Fix the integration issue for HAL 2.2 Bug: 150670922 Bug: 197297498 Test: A2DP & LE aduio stream works well with HIDL 2.1/2.2 Change-Id: I64113dd4a229874b2d17ae71d088abafd8197cfd --- .../all-versions/default/service/service.cpp | 1 + .../2.2/IBluetoothAudioProvidersFactory.hal | 18 ++ .../BluetoothAudioProvidersFactory.cpp | 43 +++++ .../default/BluetoothAudioProvidersFactory.h | 3 + .../BluetoothAudioSessionControl_2_2.h | 160 ++++++++++++++++++ .../session/BluetoothAudioSession_2_2.cpp | 25 ++- .../utils/session/BluetoothAudioSession_2_2.h | 3 + 7 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp index 898c22db6a..89585b0620 100644 --- a/audio/common/all-versions/default/service/service.cpp +++ b/audio/common/all-versions/default/service/service.cpp @@ -90,6 +90,7 @@ int main(int /* argc */, char* /* argv */ []) { }, { "Bluetooth Audio API", + "android.hardware.bluetooth.audio@2.2::IBluetoothAudioProvidersFactory", "android.hardware.bluetooth.audio@2.1::IBluetoothAudioProvidersFactory", "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory", }, diff --git a/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal b/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal index eeff4de0a4..7fb5b6cb52 100644 --- a/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal +++ b/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal @@ -16,7 +16,10 @@ package android.hardware.bluetooth.audio@2.2; +import IBluetoothAudioProvider; import @2.1::IBluetoothAudioProvidersFactory; +import @2.0::Status; +import @2.1::SessionType; /** * This factory allows a HAL implementation to be split into multiple @@ -30,4 +33,19 @@ import @2.1::IBluetoothAudioProvidersFactory; * for return value must be invoked synchronously before the API call returns. */ interface IBluetoothAudioProvidersFactory extends @2.1::IBluetoothAudioProvidersFactory { + /** + * Opens an audio provider for a session type. To close the provider, it is + * necessary to release references to the returned provider object. + * + * @param sessionType The session type (e.g. + * LE_AUDIO_SOFTWARE_ENCODING_DATAPATH). + * + * @return status One of the following + * SUCCESS if the Audio HAL successfully opens the provider with the + * given session type + * FAILURE if the Audio HAL cannot open the provider + * @return provider The provider of the specified session type + */ + openProvider_2_2(SessionType sessionType) + generates (Status status, IBluetoothAudioProvider provider); }; diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp index 7438c80d4c..510833de9f 100644 --- a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp +++ b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp @@ -122,6 +122,49 @@ Return BluetoothAudioProvidersFactory::openProvider_2_1( return Void(); } +Return BluetoothAudioProvidersFactory::openProvider_2_2( + const V2_1::SessionType sessionType, openProvider_2_2_cb _hidl_cb) { + LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType); + BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS; + BluetoothAudioProvider* provider = nullptr; + + switch (sessionType) { + case V2_1::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH: + provider = &a2dp_software_provider_instance_; + break; + case V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH: + provider = &a2dp_offload_provider_instance_; + break; + case V2_1::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH: + provider = &hearing_aid_provider_instance_; + break; + case V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH: + provider = &leaudio_output_provider_instance_; + break; + case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH: + provider = &leaudio_offload_output_provider_instance_; + break; + case V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH: + provider = &leaudio_input_provider_instance_; + break; + case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH: + provider = &leaudio_offload_input_provider_instance_; + break; + default: + status = BluetoothAudioStatus::FAILURE; + } + + if (provider == nullptr || !provider->isValid(sessionType)) { + provider = nullptr; + status = BluetoothAudioStatus::FAILURE; + LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType) + << ", status=" << toString(status); + } + + _hidl_cb(status, provider); + return Void(); +} + Return BluetoothAudioProvidersFactory::getProviderCapabilities( const V2_0::SessionType sessionType, getProviderCapabilities_cb _hidl_cb) { hidl_vec audio_capabilities = diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h index 8db330b22b..658249b57b 100644 --- a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h +++ b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h @@ -46,6 +46,9 @@ class BluetoothAudioProvidersFactory : public IBluetoothAudioProvidersFactory { Return openProvider_2_1(const V2_1::SessionType sessionType, openProvider_2_1_cb _hidl_cb) override; + Return openProvider_2_2(const V2_1::SessionType sessionType, + openProvider_2_2_cb _hidl_cb) override; + Return getProviderCapabilities_2_1( const V2_1::SessionType sessionType, getProviderCapabilities_2_1_cb _hidl_cb) override; diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h new file mode 100644 index 0000000000..e20914e305 --- /dev/null +++ b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h @@ -0,0 +1,160 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "BluetoothAudioSession_2_2.h" + +namespace android { +namespace bluetooth { +namespace audio { + +class BluetoothAudioSessionControl_2_2 { + using SessionType_2_1 = + ::android::hardware::bluetooth::audio::V2_1::SessionType; + using AudioConfiguration_2_2 = + ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration; + + public: + // The control API helps to check if session is ready or not + // @return: true if the Bluetooth stack has started th specified session + static bool IsSessionReady(const SessionType_2_1& session_type) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->IsSessionReady(); + } + return false; + } + + // The control API helps the bluetooth_audio module to register + // PortStatusCallbacks + // @return: cookie - the assigned number to this bluetooth_audio output + static uint16_t RegisterControlResultCback( + const SessionType_2_1& session_type, const PortStatusCallbacks& cbacks) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioSession()->RegisterStatusCback(cbacks); + } + return kObserversCookieUndefined; + } + + // The control API helps the bluetooth_audio module to unregister + // PortStatusCallbacks + // @param: cookie - indicates which bluetooth_audio output is + static void UnregisterControlResultCback(const SessionType_2_1& session_type, + uint16_t cookie) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->GetAudioSession()->UnregisterStatusCback(cookie); + } + } + + // The control API for the bluetooth_audio module to get current + // AudioConfiguration + static const AudioConfiguration_2_2 GetAudioConfig( + const SessionType_2_1& session_type) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioConfig(); + } else if (session_type == + SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) { + return BluetoothAudioSession_2_2::kInvalidOffloadAudioConfiguration; + } else { + return BluetoothAudioSession_2_2::kInvalidSoftwareAudioConfiguration; + } + } + + // Those control APIs for the bluetooth_audio module to start / suspend / stop + // stream, to check position, and to update metadata. + static bool StartStream(const SessionType_2_1& session_type) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioSession()->StartStream(); + } + return false; + } + + static bool SuspendStream(const SessionType_2_1& session_type) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioSession()->SuspendStream(); + } + return false; + } + + static void StopStream(const SessionType_2_1& session_type) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->GetAudioSession()->StopStream(); + } + } + + static bool GetPresentationPosition(const SessionType_2_1& session_type, + uint64_t* remote_delay_report_ns, + uint64_t* total_bytes_readed, + timespec* data_position) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioSession()->GetPresentationPosition( + remote_delay_report_ns, total_bytes_readed, data_position); + } + return false; + } + + static void UpdateTracksMetadata( + const SessionType_2_1& session_type, + const struct source_metadata* source_metadata) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + session_ptr->GetAudioSession()->UpdateTracksMetadata(source_metadata); + } + } + + // The control API writes stream to FMQ + static size_t OutWritePcmData(const SessionType_2_1& session_type, + const void* buffer, size_t bytes) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioSession()->OutWritePcmData(buffer, bytes); + } + return 0; + } + + // The control API reads stream from FMQ + static size_t InReadPcmData(const SessionType_2_1& session_type, void* buffer, + size_t bytes) { + std::shared_ptr session_ptr = + BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type); + if (session_ptr != nullptr) { + return session_ptr->GetAudioSession()->InReadPcmData(buffer, bytes); + } + return 0; + } +}; + +} // namespace audio +} // namespace bluetooth +} // namespace android diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp index 9d9ea41fd3..5a6b2e7459 100644 --- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp +++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp @@ -29,6 +29,9 @@ using SessionType_2_1 = using SessionType_2_0 = ::android::hardware::bluetooth::audio::V2_0::SessionType; +using AudioConfiguration_2_1 = + ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration; + ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration BluetoothAudioSession_2_2::invalidSoftwareAudioConfiguration = {}; ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration @@ -52,7 +55,9 @@ BluetoothAudioSession_2_2::BluetoothAudioSession_2_2( const ::android::hardware::bluetooth::audio::V2_1::SessionType& session_type) : audio_session(BluetoothAudioSessionInstance::GetSessionInstance( - static_cast(session_type))) { + static_cast(session_type))), + audio_session_2_1( + BluetoothAudioSessionInstance_2_1::GetSessionInstance(session_type)) { if (is_2_0_session_type(session_type)) { session_type_2_1_ = (SessionType_2_1::UNKNOWN); } else { @@ -74,6 +79,10 @@ std::shared_ptr BluetoothAudioSession_2_2::GetAudioSession() { return audio_session; } +std::shared_ptr +BluetoothAudioSession_2_2::GetAudioSession_2_1() { + return audio_session_2_1; +} // The control function is for the bluetooth_audio module to get the current // AudioConfiguration @@ -82,7 +91,19 @@ BluetoothAudioSession_2_2::GetAudioConfig() { std::lock_guard guard(audio_session->mutex_); if (IsSessionReady()) { // If session is unknown it means it should be 2.0 type - if (session_type_2_1_ != SessionType_2_1::UNKNOWN) return audio_config_2_2_; + if (session_type_2_1_ != SessionType_2_1::UNKNOWN) { + if (audio_config_2_2_ != invalidSoftwareAudioConfiguration) + return audio_config_2_2_; + + ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration toConf; + const AudioConfiguration_2_1 fromConf = + GetAudioSession_2_1()->GetAudioConfig(); + if (fromConf.getDiscriminator() == + AudioConfiguration_2_1::hidl_discriminator::pcmConfig) { + toConf.pcmConfig() = fromConf.pcmConfig(); + return toConf; + } + } ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration toConf; const AudioConfiguration fromConf = GetAudioSession()->GetAudioConfig(); diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h index d3d0bd3dd9..7213ede96e 100644 --- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h +++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h @@ -22,6 +22,7 @@ #include #include "BluetoothAudioSession.h" +#include "BluetoothAudioSession_2_1.h" namespace android { namespace bluetooth { @@ -30,6 +31,7 @@ namespace audio { class BluetoothAudioSession_2_2 { private: std::shared_ptr audio_session; + std::shared_ptr audio_session_2_1; ::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_; @@ -56,6 +58,7 @@ class BluetoothAudioSession_2_2 { bool IsSessionReady(); std::shared_ptr GetAudioSession(); + std::shared_ptr GetAudioSession_2_1(); // The report function is used to report that the Bluetooth stack has started // this session without any failure, and will invoke session_changed_cb_ to