diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl index 3abfb31b7b..edb9ee27f5 100644 --- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl +++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioConfiguration.aidl @@ -38,4 +38,5 @@ union AudioConfiguration { android.hardware.bluetooth.audio.CodecConfiguration a2dpConfig; android.hardware.bluetooth.audio.LeAudioConfiguration leAudioConfig; android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration leAudioBroadcastConfig; + android.hardware.bluetooth.audio.HfpConfiguration hfpConfig; } diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl new file mode 100644 index 0000000000..490a05d3f1 --- /dev/null +++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/HfpConfiguration.aidl @@ -0,0 +1,41 @@ +/* + * Copyright 2023 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.bluetooth.audio; +@VintfStability +parcelable HfpConfiguration { + android.hardware.bluetooth.audio.CodecId codecId; + int connectionHandle; + boolean nrec; + boolean controllerCodec; +} diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl index 4b2c10f71d..71cca5364f 100644 --- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl +++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl @@ -46,4 +46,7 @@ enum SessionType { LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH, A2DP_SOFTWARE_DECODING_DATAPATH, A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH, + HFP_SOFTWARE_ENCODING_DATAPATH, + HFP_SOFTWARE_DECODING_DATAPATH, + HFP_HARDWARE_OFFLOAD_DATAPATH, } diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl index a06337ec4a..b7f7f292ea 100644 --- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl +++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/AudioConfiguration.aidl @@ -17,6 +17,7 @@ package android.hardware.bluetooth.audio; import android.hardware.bluetooth.audio.CodecConfiguration; +import android.hardware.bluetooth.audio.HfpConfiguration; import android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration; import android.hardware.bluetooth.audio.LeAudioConfiguration; import android.hardware.bluetooth.audio.PcmConfiguration; @@ -30,4 +31,5 @@ union AudioConfiguration { CodecConfiguration a2dpConfig; LeAudioConfiguration leAudioConfig; LeAudioBroadcastConfiguration leAudioBroadcastConfig; + HfpConfiguration hfpConfig; } diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl new file mode 100644 index 0000000000..9494bb986b --- /dev/null +++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/HfpConfiguration.aidl @@ -0,0 +1,44 @@ +/* + * Copyright 2023 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. + */ + +package android.hardware.bluetooth.audio; + +import android.hardware.bluetooth.audio.CodecId; + +@VintfStability +parcelable HfpConfiguration { + /** + * Codec identifier. + */ + CodecId codecId; + + /** + * The connection handle used for SCO connection. + * Range: 0x0000 to 0x0EFF. + */ + int connectionHandle; + + /** + * Echo canceling and noise reduction functions resident in the AG. + */ + boolean nrec; + + /** + * Indicate whether the codec is encoded and decoded in the controller. + * If the codec is inside the DSP, then it would be transparent mode. + */ + boolean controllerCodec; +} diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl index 7acb5c6e49..35292a1731 100644 --- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl +++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/SessionType.aidl @@ -70,4 +70,17 @@ enum SessionType { * The decoding of AVDTP media is done by HW and there is control only */ A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH, + /** + * Used when audio is encoded by Bluetooth Stack and is streaming to HFP device. + */ + HFP_SOFTWARE_ENCODING_DATAPATH, + /** + * Used when audio is decoded by Bluetooth Stack and is streaming to HFP device. + */ + HFP_SOFTWARE_DECODING_DATAPATH, + /** + * Used when encoded and decoded by hardware offload and is streamed to HFP device. + * This is a control path only. + */ + HFP_HARDWARE_OFFLOAD_DATAPATH, } diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp index 40aea32839..ad4d8ce4be 100644 --- a/bluetooth/audio/aidl/default/Android.bp +++ b/bluetooth/audio/aidl/default/Android.bp @@ -20,6 +20,8 @@ cc_library_shared { "A2dpOffloadAudioProvider.cpp", "A2dpSoftwareAudioProvider.cpp", "HearingAidAudioProvider.cpp", + "HfpOffloadAudioProvider.cpp", + "HfpSoftwareAudioProvider.cpp", "LeAudioOffloadAudioProvider.cpp", "LeAudioSoftwareAudioProvider.cpp", "service.cpp", diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp index 7e928e99bf..8c6421d590 100644 --- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp +++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp @@ -25,6 +25,8 @@ #include "A2dpSoftwareAudioProvider.h" #include "BluetoothAudioProvider.h" #include "HearingAidAudioProvider.h" +#include "HfpOffloadAudioProvider.h" +#include "HfpSoftwareAudioProvider.h" #include "LeAudioOffloadAudioProvider.h" #include "LeAudioSoftwareAudioProvider.h" @@ -78,6 +80,15 @@ ndk::ScopedAStatus BluetoothAudioProviderFactory::openProvider( case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH: provider = ndk::SharedRefBase::make(); break; + case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH: + provider = ndk::SharedRefBase::make(); + break; + case SessionType::HFP_SOFTWARE_DECODING_DATAPATH: + provider = ndk::SharedRefBase::make(); + break; + case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH: + provider = ndk::SharedRefBase::make(); + break; default: provider = nullptr; break; diff --git a/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp new file mode 100644 index 0000000000..7196bb6af5 --- /dev/null +++ b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 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. + */ + +#define LOG_TAG "BTAudioProviderHfpHW" + +#include "HfpOffloadAudioProvider.h" + +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +HfpOffloadAudioProvider::HfpOffloadAudioProvider() { + session_type_ = SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH; +} + +bool HfpOffloadAudioProvider::isValid(const SessionType& session_type) { + return (session_type == session_type_); +} + +ndk::ScopedAStatus HfpOffloadAudioProvider::startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return) { + if (audio_config.getTag() != AudioConfiguration::hfpConfig) { + LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" + << audio_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + return BluetoothAudioProvider::startSession(host_if, audio_config, + latency_modes, _aidl_return); +} + +ndk::ScopedAStatus HfpOffloadAudioProvider::onSessionReady( + DataMQDesc* _aidl_return) { + *_aidl_return = DataMQDesc(); + BluetoothAudioSessionReport::OnSessionStarted( + session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_); + return ndk::ScopedAStatus::ok(); +} + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h new file mode 100644 index 0000000000..5526b46ebf --- /dev/null +++ b/bluetooth/audio/aidl/default/HfpOffloadAudioProvider.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 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 "BluetoothAudioProvider.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +class HfpOffloadAudioProvider : public BluetoothAudioProvider { + public: + HfpOffloadAudioProvider(); + + bool isValid(const SessionType& sessionType) override; + + ndk::ScopedAStatus startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return); + + private: + ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override; +}; + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp new file mode 100644 index 0000000000..0f9604647b --- /dev/null +++ b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2023 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. + */ + +#define LOG_TAG "BTAudioProviderHfpSW" + +#include "HfpSoftwareAudioProvider.h" + +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +static constexpr uint32_t kBufferCount = 2; // two frame buffer + +HfpSoftwareOutputAudioProvider::HfpSoftwareOutputAudioProvider() + : HfpSoftwareAudioProvider() { + session_type_ = SessionType::HFP_SOFTWARE_ENCODING_DATAPATH; +} + +HfpSoftwareInputAudioProvider::HfpSoftwareInputAudioProvider() + : HfpSoftwareAudioProvider() { + session_type_ = SessionType::HFP_SOFTWARE_DECODING_DATAPATH; +} + +HfpSoftwareAudioProvider::HfpSoftwareAudioProvider() + : BluetoothAudioProvider(), data_mq_(nullptr) { +} + +bool HfpSoftwareAudioProvider::isValid(const SessionType& sessionType) { + return (sessionType == session_type_); +} + +ndk::ScopedAStatus HfpSoftwareAudioProvider::startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return) { + if (audio_config.getTag() != AudioConfiguration::pcmConfig) { + LOG(WARNING) << __func__ << " - Invalid Audio Configuration=" + << audio_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + const PcmConfiguration& pcm_config = + audio_config.get(); + if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) { + LOG(WARNING) << __func__ << " - Unsupported PCM Configuration=" + << pcm_config.toString(); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + bool isValidConfig = true; + + if (pcm_config.bitsPerSample != 16) { + isValidConfig = false; + } + + if (pcm_config.sampleRateHz != 8000 && pcm_config.sampleRateHz != 16000 && + pcm_config.sampleRateHz != 32000) { + isValidConfig = false; + } + + if (pcm_config.channelMode != ChannelMode::MONO) { + isValidConfig = false; + } + + if (pcm_config.dataIntervalUs != 7500) { + isValidConfig = false; + } + + int bytes_per_sample = pcm_config.bitsPerSample / 8; + + uint32_t data_mq_size = kBufferCount * bytes_per_sample * + (pcm_config.sampleRateHz / 1000) * + pcm_config.dataIntervalUs / 1000; + if (!isValidConfig) { + LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size + << ", SampleRateHz: " << pcm_config.sampleRateHz + << ", ChannelMode: " << toString(pcm_config.channelMode) + << ", BitsPerSample: " + << static_cast(pcm_config.bitsPerSample) + << ", BytesPerSample: " << bytes_per_sample + << ", DataIntervalUs: " << pcm_config.dataIntervalUs + << ", SessionType: " << toString(session_type_); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size + << " byte(s)"; + + std::unique_ptr temp_data_mq( + new DataMQ(data_mq_size, /* EventFlag */ true)); + if (temp_data_mq == nullptr || !temp_data_mq->isValid()) { + ALOGE_IF(!temp_data_mq, "failed to allocate data MQ"); + ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid"); + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + data_mq_ = std::move(temp_data_mq); + + return BluetoothAudioProvider::startSession(host_if, audio_config, + latency_modes, _aidl_return); +} + +ndk::ScopedAStatus HfpSoftwareAudioProvider::onSessionReady( + DataMQDesc* _aidl_return) { + if (data_mq_ == nullptr || !data_mq_->isValid()) { + *_aidl_return = DataMQDesc(); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + *_aidl_return = data_mq_->dupeDesc(); + auto desc = data_mq_->dupeDesc(); + BluetoothAudioSessionReport::OnSessionStarted( + session_type_, stack_iface_, &desc, *audio_config_, latency_modes_); + return ndk::ScopedAStatus::ok(); +} + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h new file mode 100644 index 0000000000..ef51065177 --- /dev/null +++ b/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 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 "BluetoothAudioProvider.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace bluetooth { +namespace audio { + +class HfpSoftwareAudioProvider : public BluetoothAudioProvider { + public: + HfpSoftwareAudioProvider(); + + bool isValid(const SessionType& sessionType) override; + + ndk::ScopedAStatus startSession( + const std::shared_ptr& host_if, + const AudioConfiguration& audio_config, + const std::vector& latency_modes, DataMQDesc* _aidl_return); + + private: + // audio data queue for software encoding + std::unique_ptr data_mq_; + + ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override; +}; + +class HfpSoftwareOutputAudioProvider : public HfpSoftwareAudioProvider { + public: + HfpSoftwareOutputAudioProvider(); +}; + +class HfpSoftwareInputAudioProvider : public HfpSoftwareAudioProvider { + public: + HfpSoftwareInputAudioProvider(); +}; + +} // namespace audio +} // namespace bluetooth +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp index 40cd821989..c1a1b7af84 100644 --- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp +++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp @@ -49,6 +49,7 @@ using aidl::android::hardware::bluetooth::audio::CodecConfiguration; using aidl::android::hardware::bluetooth::audio::CodecId; using aidl::android::hardware::bluetooth::audio::CodecInfo; using aidl::android::hardware::bluetooth::audio::CodecType; +using aidl::android::hardware::bluetooth::audio::HfpConfiguration; using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort; using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider; using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProviderFactory; @@ -92,6 +93,13 @@ static constexpr int8_t a2dp_bits_per_samples[] = {0, 16, 24, 32}; static constexpr ChannelMode a2dp_channel_modes[] = { ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO}; static std::vector latency_modes = {LatencyMode::FREE}; + +// Some valid configs for HFP PCM configuration (software sessions) +static constexpr int32_t hfp_sample_rates_[] = {8000, 16000, 32000}; +static constexpr int8_t hfp_bits_per_samples_[] = {16}; +static constexpr ChannelMode hfp_channel_modes_[] = {ChannelMode::MONO}; +static constexpr int32_t hfp_data_interval_us_[] = {7500}; + // Helpers template @@ -197,7 +205,8 @@ class BluetoothAudioProviderFactoryAidl case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH: case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH: case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH: - case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH: { + case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH: + case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH: { // All software paths are mandatory and must have exact 1 // "PcmParameters" ASSERT_EQ(temp_provider_capabilities_.size(), 1); @@ -258,7 +267,8 @@ class BluetoothAudioProviderFactoryAidl AudioCapabilities::leAudioCapabilities); } } break; - case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH: { + case SessionType::A2DP_SOFTWARE_DECODING_DATAPATH: + case SessionType::HFP_SOFTWARE_DECODING_DATAPATH: { if (!temp_provider_capabilities_.empty()) { ASSERT_EQ(temp_provider_capabilities_.size(), 1); ASSERT_EQ(temp_provider_capabilities_[0].getTag(), @@ -298,7 +308,10 @@ class BluetoothAudioProviderFactoryAidl LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH || session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH || - session_type == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH); + session_type == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH || + session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH || + session_type == SessionType::HFP_SOFTWARE_DECODING_DATAPATH || + session_type == SessionType::HFP_SOFTWARE_ENCODING_DATAPATH); ASSERT_EQ(audio_provider_, nullptr); } } @@ -575,6 +588,8 @@ class BluetoothAudioProviderFactoryAidl SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH, SessionType::A2DP_SOFTWARE_DECODING_DATAPATH, SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH, + SessionType::HFP_SOFTWARE_ENCODING_DATAPATH, + SessionType::HFP_SOFTWARE_DECODING_DATAPATH, }; }; @@ -750,6 +765,137 @@ TEST_P(BluetoothAudioProviderA2dpEncodingSoftwareAidl, } } +/** + * openProvider HFP_SOFTWARE_ENCODING_DATAPATH + */ +class BluetoothAudioProviderHfpSoftwareEncodingAidl + : public BluetoothAudioProviderFactoryAidl { + public: + virtual void SetUp() override { + BluetoothAudioProviderFactoryAidl::SetUp(); + GetProviderCapabilitiesHelper(SessionType::HFP_SOFTWARE_ENCODING_DATAPATH); + OpenProviderHelper(SessionType::HFP_SOFTWARE_ENCODING_DATAPATH); + ASSERT_NE(audio_provider_, nullptr); + } + + virtual void TearDown() override { + audio_port_ = nullptr; + audio_provider_ = nullptr; + BluetoothAudioProviderFactoryAidl::TearDown(); + } + + bool OpenSession(int32_t sample_rate, int8_t bits_per_sample, + ChannelMode channel_mode, int32_t data_interval_us) { + PcmConfiguration pcm_config{ + .sampleRateHz = sample_rate, + .channelMode = channel_mode, + .bitsPerSample = bits_per_sample, + .dataIntervalUs = data_interval_us, + }; + // Checking against provider capability from getProviderCapabilities + // For HFP software, it's + // BluetoothAudioCodecs::GetSoftwarePcmCapabilities(); + DataMQDesc mq_desc; + auto aidl_retval = audio_provider_->startSession( + audio_port_, AudioConfiguration(pcm_config), latency_modes, &mq_desc); + DataMQ data_mq(mq_desc); + + if (!aidl_retval.isOk()) return false; + if (!data_mq.isValid()) return false; + return true; + } +}; + +/** + * Test whether we can open a provider of type + */ +TEST_P(BluetoothAudioProviderHfpSoftwareEncodingAidl, + OpenHfpSoftwareEncodingProvider) {} + +/** + * Test whether each provider of type + * SessionType::HFP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with + * different PCM config + */ +TEST_P(BluetoothAudioProviderHfpSoftwareEncodingAidl, + StartAndEndHfpEncodingSoftwareSessionWithPossiblePcmConfig) { + for (auto sample_rate : hfp_sample_rates_) { + for (auto bits_per_sample : hfp_bits_per_samples_) { + for (auto channel_mode : hfp_channel_modes_) { + for (auto data_interval_us: hfp_data_interval_us_) { + EXPECT_TRUE(OpenSession(sample_rate, bits_per_sample, + channel_mode, data_interval_us)); + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } + } + } + } +} + +/** + * openProvider HFP_SOFTWARE_DECODING_DATAPATH + */ +class BluetoothAudioProviderHfpSoftwareDecodingAidl + : public BluetoothAudioProviderFactoryAidl { + public: + virtual void SetUp() override { + BluetoothAudioProviderFactoryAidl::SetUp(); + GetProviderCapabilitiesHelper(SessionType::HFP_SOFTWARE_DECODING_DATAPATH); + OpenProviderHelper(SessionType::HFP_SOFTWARE_DECODING_DATAPATH); + ASSERT_NE(audio_provider_, nullptr); + } + + virtual void TearDown() override { + audio_port_ = nullptr; + audio_provider_ = nullptr; + BluetoothAudioProviderFactoryAidl::TearDown(); + } + + bool OpenSession(int32_t sample_rate, int8_t bits_per_sample, + ChannelMode channel_mode, int32_t data_interval_us) { + PcmConfiguration pcm_config{ + .sampleRateHz = sample_rate, + .channelMode = channel_mode, + .bitsPerSample = bits_per_sample, + .dataIntervalUs = data_interval_us, + }; + DataMQDesc mq_desc; + auto aidl_retval = audio_provider_->startSession( + audio_port_, AudioConfiguration(pcm_config), latency_modes, &mq_desc); + DataMQ data_mq(mq_desc); + + if (!aidl_retval.isOk()) return false; + if (!data_mq.isValid()) return false; + return true; + } +}; + +/** + * Test whether we can open a provider of type + */ +TEST_P(BluetoothAudioProviderHfpSoftwareDecodingAidl, + OpenHfpSoftwareDecodingProvider) {} + +/** + * Test whether each provider of type + * SessionType::HFP_SOFTWARE_DECODING_DATAPATH can be started and stopped with + * different PCM config + */ +TEST_P(BluetoothAudioProviderHfpSoftwareDecodingAidl, + StartAndEndHfpDecodingSoftwareSessionWithPossiblePcmConfig) { + for (auto sample_rate : hfp_sample_rates_) { + for (auto bits_per_sample : hfp_bits_per_samples_) { + for (auto channel_mode : hfp_channel_modes_) { + for (auto data_interval_us: hfp_data_interval_us_) { + EXPECT_TRUE(OpenSession(sample_rate, bits_per_sample, + channel_mode, data_interval_us)); + EXPECT_TRUE(audio_provider_->endSession().isOk()); + } + } + } + } +} + /** * openProvider A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH */ @@ -1002,6 +1148,62 @@ TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl, } } +/** + * openProvider HFP_HARDWARE_OFFLOAD_DATAPATH + */ +class BluetoothAudioProviderHfpHardwareAidl + : public BluetoothAudioProviderFactoryAidl { + public: + virtual void SetUp() override { + BluetoothAudioProviderFactoryAidl::SetUp(); + OpenProviderHelper(SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH); + // Can open or empty capability + ASSERT_TRUE(temp_provider_capabilities_.empty() || + audio_provider_ != nullptr); + } + + virtual void TearDown() override { + audio_port_ = nullptr; + audio_provider_ = nullptr; + BluetoothAudioProviderFactoryAidl::TearDown(); + } + + bool OpenSession(CodecId codec_id, int connection_handle, bool nrec, + bool controller_codec) { + // Check if can open session with a Hfp configuration + HfpConfiguration hfp_configuration{ + .codecId = codec_id, + .connectionHandle = connection_handle, + .nrec = nrec, + .controllerCodec = controller_codec, + }; + DataMQDesc mq_desc; + auto aidl_retval = audio_provider_->startSession( + audio_port_, AudioConfiguration(hfp_configuration), latency_modes, + &mq_desc); + + // Only check if aidl is ok to start session. + return aidl_retval.isOk(); + } +}; + +/** + * Test whether we can open a provider of type + */ +TEST_P(BluetoothAudioProviderHfpHardwareAidl, OpenHfpHardwareProvider) {} + +/** + * Test whether each provider of type + * SessionType::HFP_SOFTWARE_DECODING_DATAPATH can be started and stopped with + * different HFP config + */ +TEST_P(BluetoothAudioProviderHfpHardwareAidl, + StartAndEndHfpHardwareSessionWithPossiblePcmConfig) { + // Try to open with a sample configuration + EXPECT_TRUE(OpenSession(CodecId::Core::CVSD, 6, false, true)); + EXPECT_TRUE(audio_provider_->endSession().isOk()); +} + /** * openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH */ @@ -2279,6 +2481,29 @@ INSTANTIATE_TEST_SUITE_P(PerInstance, IBluetoothAudioProviderFactory::descriptor)), android::PrintInstanceNameToString); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + BluetoothAudioProviderHfpHardwareAidl); +INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderHfpHardwareAidl, + testing::ValuesIn(android::getAidlHalInstanceNames( + IBluetoothAudioProviderFactory::descriptor)), + android::PrintInstanceNameToString); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + BluetoothAudioProviderHfpSoftwareDecodingAidl); +INSTANTIATE_TEST_SUITE_P(PerInstance, + BluetoothAudioProviderHfpSoftwareDecodingAidl, + testing::ValuesIn(android::getAidlHalInstanceNames( + IBluetoothAudioProviderFactory::descriptor)), + android::PrintInstanceNameToString); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST( + BluetoothAudioProviderHfpSoftwareEncodingAidl); +INSTANTIATE_TEST_SUITE_P(PerInstance, + BluetoothAudioProviderHfpSoftwareEncodingAidl, + testing::ValuesIn(android::getAidlHalInstanceNames( + IBluetoothAudioProviderFactory::descriptor)), + android::PrintInstanceNameToString); + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ABinderProcess_setThreadPoolMaxThreadCount(1); diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp index b4cba49502..6e15b3b93c 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp @@ -41,7 +41,7 @@ namespace bluetooth { namespace audio { static const PcmCapabilities kDefaultSoftwarePcmCapabilities = { - .sampleRateHz = {16000, 24000, 32000, 44100, 48000, 88200, 96000}, + .sampleRateHz = {8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000}, .channelMode = {ChannelMode::MONO, ChannelMode::STEREO}, .bitsPerSample = {16, 24, 32}, .dataIntervalUs = {}, diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp index c283148a38..9dcfc13893 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp @@ -95,6 +95,8 @@ const AudioConfiguration BluetoothAudioSession::GetAudioConfig() { case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(CodecConfiguration{}); + case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH: + return AudioConfiguration(HfpConfiguration{}); case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(LeAudioConfiguration{}); @@ -154,6 +156,7 @@ bool BluetoothAudioSession::IsSessionReady() { session_type_ == SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH || session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH || + session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH || (data_mq_ != nullptr && data_mq_->isValid())); return stack_iface_ != nullptr && is_mq_valid && audio_config_ != nullptr; } @@ -275,6 +278,8 @@ bool BluetoothAudioSession::UpdateAudioConfig( bool is_software_session = (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH || session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::HFP_SOFTWARE_ENCODING_DATAPATH || + session_type_ == SessionType::HFP_SOFTWARE_DECODING_DATAPATH || session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH || session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH || session_type_ == @@ -283,6 +288,8 @@ bool BluetoothAudioSession::UpdateAudioConfig( bool is_offload_a2dp_session = (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH || session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH); + bool is_offload_hfp_session = + session_type_ == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH; bool is_offload_le_audio_unicast_session = (session_type_ == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH || @@ -298,6 +305,9 @@ bool BluetoothAudioSession::UpdateAudioConfig( bool is_a2dp_offload_audio_config = (is_offload_a2dp_session && audio_config_tag == AudioConfiguration::a2dpConfig); + bool is_hfp_offload_audio_config = + (is_offload_hfp_session && + audio_config_tag == AudioConfiguration::hfpConfig); bool is_le_audio_offload_unicast_audio_config = (is_offload_le_audio_unicast_session && audio_config_tag == AudioConfiguration::leAudioConfig); @@ -305,6 +315,7 @@ bool BluetoothAudioSession::UpdateAudioConfig( (is_offload_le_audio_broadcast_session && audio_config_tag == AudioConfiguration::leAudioBroadcastConfig); if (!is_software_audio_config && !is_a2dp_offload_audio_config && + !is_hfp_offload_audio_config && !is_le_audio_offload_unicast_audio_config && !is_le_audio_offload_broadcast_audio_config) { return false; diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h index 7ae0353641..5263222084 100644 --- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h +++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h @@ -84,6 +84,8 @@ class BluetoothAudioSessionControl { case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(CodecConfiguration{}); + case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH: + return AudioConfiguration(HfpConfiguration{}); case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH: case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH: return AudioConfiguration(LeAudioConfiguration{}); diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp index 3d92ee7b1f..a2a5bcb51e 100644 --- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp +++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp @@ -475,6 +475,8 @@ inline AudioConfig_2_1 to_hidl_audio_config_2_1( hidl_audio_config.leAudioCodecConfig(to_hidl_leaudio_broadcast_config_2_1( audio_config.get())); break; + default: + LOG(FATAL) << __func__ << ": unexpected AudioConfiguration"; } return hidl_audio_config; }