Merge changes from topic "HFP-SCO-management" into main

* changes:
  Add VTS for HFP sessions
  Add HFP to BluetoothAudioSession
  Add HFP default implementation
  Add HFP AIDL design
This commit is contained in:
Alice Kuo
2023-12-07 16:20:16 +00:00
committed by Gerrit Code Review
17 changed files with 671 additions and 4 deletions

View File

@@ -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;
}

View File

@@ -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 <name>-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;
}

View File

@@ -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,
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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,
}

View File

@@ -20,6 +20,8 @@ cc_library_shared {
"A2dpOffloadAudioProvider.cpp",
"A2dpSoftwareAudioProvider.cpp",
"HearingAidAudioProvider.cpp",
"HfpOffloadAudioProvider.cpp",
"HfpSoftwareAudioProvider.cpp",
"LeAudioOffloadAudioProvider.cpp",
"LeAudioSoftwareAudioProvider.cpp",
"service.cpp",

View File

@@ -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<A2dpOffloadDecodingAudioProvider>();
break;
case SessionType::HFP_SOFTWARE_ENCODING_DATAPATH:
provider = ndk::SharedRefBase::make<HfpSoftwareOutputAudioProvider>();
break;
case SessionType::HFP_SOFTWARE_DECODING_DATAPATH:
provider = ndk::SharedRefBase::make<HfpSoftwareInputAudioProvider>();
break;
case SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH:
provider = ndk::SharedRefBase::make<HfpOffloadAudioProvider>();
break;
default:
provider = nullptr;
break;

View File

@@ -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 <BluetoothAudioCodecs.h>
#include <BluetoothAudioSessionReport.h>
#include <android-base/logging.h>
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<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
const std::vector<LatencyMode>& 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

View File

@@ -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<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
private:
ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
};
} // namespace audio
} // namespace bluetooth
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -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 <BluetoothAudioCodecs.h>
#include <BluetoothAudioSessionReport.h>
#include <android-base/logging.h>
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<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
const std::vector<LatencyMode>& 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<AudioConfiguration::pcmConfig>();
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<int>(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<DataMQ> 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

View File

@@ -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<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return);
private:
// audio data queue for software encoding
std::unique_ptr<DataMQ> 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

View File

@@ -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<LatencyMode> 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 <typename T>
@@ -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);

View File

@@ -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 = {},

View File

@@ -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;

View File

@@ -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{});

View File

@@ -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<AudioConfiguration::leAudioBroadcastConfig>()));
break;
default:
LOG(FATAL) << __func__ << ": unexpected AudioConfiguration";
}
return hidl_audio_config;
}