Codec Extensibility A2DP HAL Reference Implementation

Test: m
Bug: 297037759
Change-Id: I84b32c2ef22da8c3e920e497501b9f16feaf803c
This commit is contained in:
Antoine SOULIER 2023-09-29 19:10:07 +00:00 committed by Henri Chataing
parent 33c4e5a629
commit 4e34d05b7b
14 changed files with 1374 additions and 40 deletions

View file

@ -0,0 +1,73 @@
/*
* 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
namespace aidl::android::hardware::bluetooth::audio {
class A2dpBits {
const uint8_t* cdata_;
uint8_t* data_;
public:
A2dpBits(const std::vector<uint8_t>& vector) : cdata_(vector.data()) {}
A2dpBits(std::vector<uint8_t>& vector)
: cdata_(vector.data()), data_(vector.data()) {}
struct Range {
const int first, len;
constexpr Range(int first, int last)
: first(first), len(last - first + 1) {}
constexpr Range(int index) : first(index), len(1) {}
};
constexpr bool get(int bit) const {
return (cdata_[bit >> 3] >> (7 - (bit & 7))) & 1;
}
constexpr unsigned get(const Range& range) const {
unsigned v(0);
for (int i = 0; i < range.len; i++)
v |= get(range.first + i) << ((range.len - 1) - i);
return v;
}
constexpr void set(int bit, int value = 1) {
uint8_t m = 1 << (7 - (bit & 7));
if (value)
data_[bit >> 3] |= m;
else
data_[bit >> 3] &= ~m;
}
constexpr void set(const Range& range, int value) {
for (int i = 0; i < range.len; i++)
set(range.first + i, (value >> ((range.len - 1) - i)) & 1);
}
constexpr int find_active_bit(const Range& range) const {
unsigned v = get(range);
int i = 0;
for (; i < range.len && ((v >> i) & 1) == 0; i++)
;
return i < range.len && (v ^ (1 << i)) == 0
? range.first + (range.len - 1) - i
: -1;
}
};
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -22,6 +22,10 @@
#include <BluetoothAudioSessionReport.h>
#include <android-base/logging.h>
#include "A2dpOffloadCodecAac.h"
#include "A2dpOffloadCodecFactory.h"
#include "A2dpOffloadCodecSbc.h"
namespace aidl {
namespace android {
namespace hardware {
@ -48,19 +52,44 @@ ndk::ScopedAStatus A2dpOffloadAudioProvider::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::a2dpConfig) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
*_aidl_return = DataMQDesc();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
session_type_, audio_config.get<AudioConfiguration::a2dpConfig>())) {
if (audio_config.getTag() == AudioConfiguration::Tag::a2dp) {
auto a2dp_config = audio_config.get<AudioConfiguration::Tag::a2dp>();
A2dpStatus a2dp_status = A2dpStatus::NOT_SUPPORTED_CODEC_TYPE;
if (a2dp_config.codecId ==
A2dpOffloadCodecSbc::GetInstance()->GetCodecId()) {
SbcParameters sbc_parameters;
a2dp_status = A2dpOffloadCodecSbc::GetInstance()->ParseConfiguration(
a2dp_config.configuration, &sbc_parameters);
} else if (a2dp_config.codecId ==
A2dpOffloadCodecAac::GetInstance()->GetCodecId()) {
AacParameters aac_parameters;
a2dp_status = A2dpOffloadCodecAac::GetInstance()->ParseConfiguration(
a2dp_config.configuration, &aac_parameters);
}
if (a2dp_status != A2dpStatus::OK) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
*_aidl_return = DataMQDesc();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
} else if (audio_config.getTag() == AudioConfiguration::Tag::a2dpConfig) {
if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
session_type_,
audio_config.get<AudioConfiguration::a2dpConfig>())) {
LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
<< audio_config.toString();
*_aidl_return = DataMQDesc();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
} else {
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);
}
@ -73,6 +102,36 @@ ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus A2dpOffloadAudioProvider::parseA2dpConfiguration(
const CodecId& codec_id, const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters, A2dpStatus* _aidl_return) {
auto codec = A2dpOffloadCodecFactory::GetInstance()->GetCodec(codec_id);
if (!codec) {
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
<< " - CodecId=" << codec_id.toString() << " is not found";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
*_aidl_return = codec->ParseConfiguration(configuration, codec_parameters);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus A2dpOffloadAudioProvider::getA2dpConfiguration(
const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
const A2dpConfigurationHint& hint,
std::optional<audio::A2dpConfiguration>* _aidl_return) {
*_aidl_return = std::nullopt;
A2dpConfiguration avdtp_configuration;
if (A2dpOffloadCodecFactory::GetInstance()->GetConfiguration(
remote_a2dp_capabilities, hint, &avdtp_configuration))
*_aidl_return =
std::make_optional<A2dpConfiguration>(std::move(avdtp_configuration));
return ndk::ScopedAStatus::ok();
}
} // namespace audio
} // namespace bluetooth
} // namespace hardware

View file

@ -34,7 +34,16 @@ class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
const std::shared_ptr<IBluetoothAudioPort>& host_if,
const AudioConfiguration& audio_config,
const std::vector<LatencyMode>& latency_modes,
DataMQDesc* _aidl_return);
DataMQDesc* _aidl_return) override;
ndk::ScopedAStatus parseA2dpConfiguration(
const CodecId& codec_id, const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters, A2dpStatus* _aidl_return) override;
ndk::ScopedAStatus getA2dpConfiguration(
const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
const A2dpConfigurationHint& hint,
std::optional<audio::A2dpConfiguration>* _aidl_return) override;
private:
ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;

View file

@ -0,0 +1,47 @@
/*
* 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 <aidl/android/hardware/bluetooth/audio/A2dpStatus.h>
#include <aidl/android/hardware/bluetooth/audio/ChannelMode.h>
#include <aidl/android/hardware/bluetooth/audio/CodecParameters.h>
#include "BluetoothAudioProviderFactory.h"
namespace aidl::android::hardware::bluetooth::audio {
class A2dpOffloadCodec {
protected:
A2dpOffloadCodec(const CodecInfo& info) : info(info) {}
virtual ~A2dpOffloadCodec() {}
public:
const CodecInfo& info;
const CodecId& GetCodecId() const { return info.id; }
virtual A2dpStatus ParseConfiguration(
const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters) const = 0;
virtual bool BuildConfiguration(
const std::vector<uint8_t>& remote_capabilities,
const std::optional<CodecParameters>& hint,
std::vector<uint8_t>* configuration) const = 0;
};
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -0,0 +1,378 @@
/*
* 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.
*/
#include "A2dpOffloadCodecAac.h"
#include "A2dpBits.h"
namespace aidl::android::hardware::bluetooth::audio {
/**
* AAC Local Capabilities
*/
enum : bool {
kEnableObjectTypeMpeg2AacLc = true,
kEnableObjectTypeMpeg4AacLc = true,
};
enum : bool {
kEnableSamplingFrequency44100 = true,
kEnableSamplingFrequency48000 = true,
kEnableSamplingFrequency88200 = false,
kEnableSamplingFrequency96000 = false,
};
enum : bool {
kEnableChannels1 = true,
kEnableChannels2 = true,
};
enum : bool {
kEnableVbrSupported = true,
};
enum : int {
kBitdepth = 24,
};
/**
* AAC Signaling format [A2DP - 4.5]
*/
// clang-format off
constexpr A2dpBits::Range kObjectType ( 0, 6 );
constexpr A2dpBits::Range kDrcEnable ( 7 );
constexpr A2dpBits::Range kSamplingFrequency ( 8, 19 );
constexpr A2dpBits::Range kChannels ( 20, 23 );
constexpr A2dpBits::Range kVbrSupported ( 24 );
constexpr A2dpBits::Range kBitrate ( 25, 47 );
constexpr size_t kCapabilitiesSize = 48/8;
// clang-format on
enum {
kObjectTypeMpeg2AacLc = kObjectType.first,
kObjectTypeMpeg4AacLc,
kObjectTypeMpeg4AacLtp,
kObjectTypeMpeg4AacScalable,
kObjectTypeMpeg4AacHeV1,
kObjectTypeMpeg4AacHeV2,
kObjectTypeMpeg4AacEldV2
};
enum {
kSamplingFrequency8000 = kSamplingFrequency.first,
kSamplingFrequency11025,
kSamplingFrequency12000,
kSamplingFrequency16000,
kSamplingFrequency22050,
kSamplingFrequency24000,
kSamplingFrequency32000,
kSamplingFrequency44100,
kSamplingFrequency48000,
kSamplingFrequency64000,
kSamplingFrequency88200,
kSamplingFrequency96000
};
enum { kChannels1 = kChannels.first, kChannels2, kChannels51, kChannels71 };
/**
* AAC Conversion functions
*/
static AacParameters::ObjectType GetObjectTypeEnum(int object_type) {
switch (object_type) {
case kObjectTypeMpeg2AacLc:
return AacParameters::ObjectType::MPEG2_AAC_LC;
case kObjectTypeMpeg4AacLc:
default:
return AacParameters::ObjectType::MPEG4_AAC_LC;
}
}
static int GetSamplingFrequencyBit(int32_t sampling_frequency) {
switch (sampling_frequency) {
case 8000:
return kSamplingFrequency8000;
case 11025:
return kSamplingFrequency11025;
case 12000:
return kSamplingFrequency12000;
case 16000:
return kSamplingFrequency16000;
case 22050:
return kSamplingFrequency22050;
case 24000:
return kSamplingFrequency24000;
case 32000:
return kSamplingFrequency32000;
case 44100:
return kSamplingFrequency44100;
case 48000:
return kSamplingFrequency48000;
case 64000:
return kSamplingFrequency64000;
case 88200:
return kSamplingFrequency88200;
case 96000:
return kSamplingFrequency96000;
default:
return -1;
}
}
static int32_t GetSamplingFrequencyValue(int sampling_frequency) {
switch (sampling_frequency) {
case kSamplingFrequency8000:
return 8000;
case kSamplingFrequency11025:
return 11025;
case kSamplingFrequency12000:
return 12000;
case kSamplingFrequency16000:
return 16000;
case kSamplingFrequency22050:
return 22050;
case kSamplingFrequency24000:
return 24000;
case kSamplingFrequency32000:
return 32000;
case kSamplingFrequency44100:
return 44100;
case kSamplingFrequency48000:
return 48000;
case kSamplingFrequency64000:
return 64000;
case kSamplingFrequency88200:
return 88200;
case kSamplingFrequency96000:
return 96000;
default:
return 0;
}
}
static int GetChannelsBit(ChannelMode channel_mode) {
switch (channel_mode) {
case ChannelMode::MONO:
return kChannels1;
case ChannelMode::STEREO:
return kChannels2;
default:
return -1;
}
}
static ChannelMode GetChannelModeEnum(int channel_mode) {
switch (channel_mode) {
case kChannels1:
return ChannelMode::MONO;
case kChannels2:
return ChannelMode::STEREO;
default:
return ChannelMode::UNKNOWN;
}
}
/**
* AAC Class implementation
*/
const A2dpOffloadCodecAac* A2dpOffloadCodecAac::GetInstance() {
static A2dpOffloadCodecAac instance;
return &instance;
}
A2dpOffloadCodecAac::A2dpOffloadCodecAac()
: A2dpOffloadCodec(info_),
info_({.id = CodecId(CodecId::A2dp::AAC), .name = "AAC"}) {
info_.transport.set<CodecInfo::Transport::Tag::a2dp>();
auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
/* --- Setup Capabilities --- */
a2dp_info.capabilities.resize(kCapabilitiesSize);
std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0);
auto capabilities = A2dpBits(a2dp_info.capabilities);
capabilities.set(kObjectTypeMpeg2AacLc, kEnableObjectTypeMpeg2AacLc);
capabilities.set(kObjectTypeMpeg4AacLc, kEnableObjectTypeMpeg4AacLc);
capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100);
capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000);
capabilities.set(kSamplingFrequency88200, kEnableSamplingFrequency88200);
capabilities.set(kSamplingFrequency96000, kEnableSamplingFrequency96000);
capabilities.set(kChannels1, kEnableChannels1);
capabilities.set(kChannels2, kEnableChannels2);
capabilities.set(kVbrSupported, kEnableVbrSupported);
/* --- Setup Sampling Frequencies --- */
auto& sampling_frequency = a2dp_info.samplingFrequencyHz;
for (auto v : {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
64000, 88200, 96000})
if (capabilities.get(GetSamplingFrequencyBit(int32_t(v))))
sampling_frequency.push_back(v);
/* --- Setup Channel Modes --- */
auto& channel_modes = a2dp_info.channelMode;
for (auto v : {ChannelMode::MONO, ChannelMode::STEREO})
if (capabilities.get(GetChannelsBit(v))) channel_modes.push_back(v);
/* --- Setup Bitdepth --- */
a2dp_info.bitdepth.push_back(kBitdepth);
}
A2dpStatus A2dpOffloadCodecAac::ParseConfiguration(
const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters, AacParameters* aac_parameters) const {
auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
if (configuration.size() != a2dp_info.capabilities.size())
return A2dpStatus::BAD_LENGTH;
auto config = A2dpBits(configuration);
auto lcaps = A2dpBits(a2dp_info.capabilities);
/* --- Check Object Type --- */
int object_type = config.find_active_bit(kObjectType);
if (object_type < 0) return A2dpStatus::INVALID_OBJECT_TYPE;
if (!lcaps.get(object_type)) return A2dpStatus::NOT_SUPPORTED_OBJECT_TYPE;
/* --- Check Sampling Frequency --- */
int sampling_frequency = config.find_active_bit(kSamplingFrequency);
if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY;
if (!lcaps.get(sampling_frequency))
return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY;
/* --- Check Channels --- */
int channels = config.find_active_bit(kChannels);
if (channels < 0) return A2dpStatus::INVALID_CHANNELS;
if (!lcaps.get(channels)) return A2dpStatus::NOT_SUPPORTED_CHANNELS;
/* --- Check Bitrate --- */
bool vbr = config.get(kVbrSupported);
if (vbr && !lcaps.get(kVbrSupported)) return A2dpStatus::NOT_SUPPORTED_VBR;
int bitrate = config.get(kBitrate);
if (vbr && lcaps.get(kBitrate) && bitrate > lcaps.get(kBitrate))
return A2dpStatus::NOT_SUPPORTED_BIT_RATE;
/* --- Return --- */
codec_parameters->channelMode = GetChannelModeEnum(channels);
codec_parameters->samplingFrequencyHz =
GetSamplingFrequencyValue(sampling_frequency);
codec_parameters->bitdepth = kBitdepth;
codec_parameters->minBitrate = vbr ? 0 : bitrate;
codec_parameters->maxBitrate = bitrate;
if (aac_parameters)
aac_parameters->object_type = GetObjectTypeEnum(object_type);
return A2dpStatus::OK;
}
bool A2dpOffloadCodecAac::BuildConfiguration(
const std::vector<uint8_t>& remote_capabilities,
const std::optional<CodecParameters>& hint,
std::vector<uint8_t>* configuration) const {
auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false;
auto lcaps = A2dpBits(a2dp_info.capabilities);
auto rcaps = A2dpBits(remote_capabilities);
configuration->resize(a2dp_info.capabilities.size());
std::fill(begin(*configuration), end(*configuration), 0);
auto config = A2dpBits(*configuration);
/* --- Select Object Type --- */
if (lcaps.get(kObjectTypeMpeg2AacLc) && rcaps.get(kObjectTypeMpeg2AacLc))
config.set(kObjectTypeMpeg2AacLc);
else if (lcaps.get(kObjectTypeMpeg4AacLc) && rcaps.get(kObjectTypeMpeg4AacLc))
config.set(kObjectTypeMpeg4AacLc);
else
return false;
/* --- Select Sampling Frequency --- */
auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1;
if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint))
config.set(sf_hint);
else if (lcaps.get(kSamplingFrequency96000) &&
rcaps.get(kSamplingFrequency96000))
config.set(kSamplingFrequency96000);
else if (lcaps.get(kSamplingFrequency88200) &&
rcaps.get(kSamplingFrequency88200))
config.set(kSamplingFrequency88200);
else if (lcaps.get(kSamplingFrequency48000) &&
rcaps.get(kSamplingFrequency48000))
config.set(kSamplingFrequency48000);
else if (lcaps.get(kSamplingFrequency44100) &&
rcaps.get(kSamplingFrequency44100))
config.set(kSamplingFrequency44100);
else
return false;
/* --- Select Channels --- */
auto ch_hint = hint ? GetChannelsBit(hint->channelMode) : -1;
if (ch_hint >= 0 && lcaps.get(ch_hint) && rcaps.get(ch_hint))
config.set(ch_hint);
else if (lcaps.get(kChannels2) && rcaps.get(kChannels2))
config.set(kChannels2);
else if (lcaps.get(kChannels1) && rcaps.get(kChannels1))
config.set(kChannels1);
else
return false;
/* --- Select Bitrate --- */
if (!hint || hint->minBitrate == 0)
config.set(kVbrSupported,
lcaps.get(kVbrSupported) && rcaps.get(kVbrSupported));
int32_t bitrate = lcaps.get(kBitrate);
if (hint && hint->maxBitrate > 0 && bitrate)
bitrate = std::min(hint->maxBitrate, bitrate);
else if (hint && hint->maxBitrate > 0)
bitrate = hint->maxBitrate;
config.set(kBitrate, bitrate);
return true;
}
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -0,0 +1,57 @@
/*
* 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 "A2dpOffloadCodec.h"
namespace aidl::android::hardware::bluetooth::audio {
struct AacParameters : public CodecParameters {
enum class ObjectType { MPEG2_AAC_LC, MPEG4_AAC_LC };
ObjectType object_type;
};
class A2dpOffloadCodecAac : public A2dpOffloadCodec {
CodecInfo info_;
A2dpOffloadCodecAac();
A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters,
AacParameters* aac_parameters) const;
public:
static const A2dpOffloadCodecAac* GetInstance();
A2dpStatus ParseConfiguration(
const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters) const override {
return ParseConfiguration(configuration, codec_parameters, nullptr);
}
A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
AacParameters* aac_parameters) const {
return ParseConfiguration(configuration, aac_parameters, aac_parameters);
}
bool BuildConfiguration(const std::vector<uint8_t>& remote_capabilities,
const std::optional<CodecParameters>& hint,
std::vector<uint8_t>* configuration) const override;
};
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -0,0 +1,100 @@
/*
* 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.
*/
#include "A2dpOffloadCodecFactory.h"
#include <algorithm>
#include <cassert>
#include "A2dpOffloadCodecAac.h"
#include "A2dpOffloadCodecSbc.h"
namespace aidl::android::hardware::bluetooth::audio {
/**
* Local Capabilities Configuration
*/
enum : bool {
kEnableAac = true,
kEnableSbc = true,
};
/**
* Class implementation
*/
const A2dpOffloadCodecFactory* A2dpOffloadCodecFactory::GetInstance() {
static A2dpOffloadCodecFactory instance;
return &instance;
}
A2dpOffloadCodecFactory::A2dpOffloadCodecFactory()
: name("Offload"), codecs(ranked_codecs_) {
ranked_codecs_.reserve(kEnableAac + kEnableSbc);
if (kEnableAac) ranked_codecs_.push_back(A2dpOffloadCodecAac::GetInstance());
if (kEnableSbc) ranked_codecs_.push_back(A2dpOffloadCodecSbc::GetInstance());
}
const A2dpOffloadCodec* A2dpOffloadCodecFactory::GetCodec(CodecId id) const {
auto codec = std::find_if(begin(ranked_codecs_), end(ranked_codecs_),
[&](auto c) { return id == c->info.id; });
return codec != end(ranked_codecs_) ? *codec : nullptr;
}
bool A2dpOffloadCodecFactory::GetConfiguration(
const std::vector<A2dpRemoteCapabilities>& remote_capabilities,
const A2dpConfigurationHint& hint, A2dpConfiguration* configuration) const {
decltype(ranked_codecs_) codecs;
codecs.reserve(ranked_codecs_.size());
auto hinted_codec =
std::find_if(begin(ranked_codecs_), end(ranked_codecs_),
[&](auto c) { return hint.codecId == c->info.id; });
if (hinted_codec != end(ranked_codecs_)) codecs.push_back(*hinted_codec);
std::copy_if(begin(ranked_codecs_), end(ranked_codecs_),
std::back_inserter(codecs),
[&](auto c) { return c != *hinted_codec; });
for (auto codec : codecs) {
auto rc =
std::find_if(begin(remote_capabilities), end(remote_capabilities),
[&](auto& rc__) { return codec->info.id == rc__.id; });
if ((rc == end(remote_capabilities)) ||
!codec->BuildConfiguration(rc->capabilities, hint.codecParameters,
&configuration->configuration))
continue;
configuration->id = codec->info.id;
A2dpStatus status = codec->ParseConfiguration(configuration->configuration,
&configuration->parameters);
assert(status == A2dpStatus::OK);
configuration->remoteSeid = rc->seid;
return true;
}
return false;
}
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -0,0 +1,41 @@
/*
* 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 "A2dpOffloadCodec.h"
namespace aidl::android::hardware::bluetooth::audio {
class A2dpOffloadCodecFactory {
std::vector<const A2dpOffloadCodec*> ranked_codecs_;
A2dpOffloadCodecFactory();
public:
const std::string name;
const std::vector<const A2dpOffloadCodec*>& codecs;
static const A2dpOffloadCodecFactory* GetInstance();
const A2dpOffloadCodec* GetCodec(CodecId id) const;
bool GetConfiguration(const std::vector<A2dpRemoteCapabilities>&,
const A2dpConfigurationHint& hint,
A2dpConfiguration* configuration) const;
};
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -0,0 +1,510 @@
/*
* 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.
*/
#include "A2dpOffloadCodecSbc.h"
#include <algorithm>
#include "A2dpBits.h"
namespace aidl::android::hardware::bluetooth::audio {
/**
* SBC Local Capabilities
*/
enum : bool {
kEnableSamplingFrequency44100 = true,
kEnableSamplingFrequency48000 = true,
};
enum : bool {
kEnableChannelModeMono = true,
kEnableChannelModeDualChannel = true,
kEnableChannelModeStereo = true,
kEnableChannelModeJointStereo = true,
};
enum : bool {
kEnableBlockLength4 = true,
kEnableBlockLength8 = true,
kEnableBlockLength12 = true,
kEnableBlockLength16 = true,
};
enum : bool {
kEnableSubbands4 = true,
kEnableSubbands8 = true,
};
enum : bool {
kEnableAllocationMethodSnr = true,
kEnableAllocationMethodLoudness = true,
};
enum : uint8_t {
kDefaultMinimumBitpool = 2,
kDefaultMaximumBitpool = 250,
};
enum : int {
kBitdepth = 16,
};
/**
* SBC Signaling format [A2DP - 4.3]
*/
// clang-format off
constexpr A2dpBits::Range kSamplingFrequency ( 0, 3 );
constexpr A2dpBits::Range kChannelMode ( 4, 7 );
constexpr A2dpBits::Range kBlockLength ( 8, 11 );
constexpr A2dpBits::Range kSubbands ( 12, 13 );
constexpr A2dpBits::Range kAllocationMethod ( 14, 15 );
constexpr A2dpBits::Range kMinimumBitpool ( 16, 23 );
constexpr A2dpBits::Range kMaximumBitpool ( 24, 31 );
constexpr size_t kCapabilitiesSize = 32/8;
// clang-format on
enum {
kSamplingFrequency16000 = kSamplingFrequency.first,
kSamplingFrequency32000,
kSamplingFrequency44100,
kSamplingFrequency48000
};
enum {
kChannelModeMono = kChannelMode.first,
kChannelModeDualChannel,
kChannelModeStereo,
kChannelModeJointStereo
};
enum {
kBlockLength4 = kBlockLength.first,
kBlockLength8,
kBlockLength12,
kBlockLength16
};
enum { kSubbands8 = kSubbands.first, kSubbands4 };
enum {
kAllocationMethodSnr = kAllocationMethod.first,
kAllocationMethodLoudness
};
/**
* SBC Conversion functions
*/
static int GetSamplingFrequencyBit(int32_t sampling_frequency) {
switch (sampling_frequency) {
case 16000:
return kSamplingFrequency16000;
case 32000:
return kSamplingFrequency32000;
case 44100:
return kSamplingFrequency44100;
case 48000:
return kSamplingFrequency48000;
default:
return -1;
}
}
static int32_t GetSamplingFrequencyValue(int sampling_frequency) {
switch (sampling_frequency) {
case kSamplingFrequency16000:
return 16000;
case kSamplingFrequency32000:
return 32000;
case kSamplingFrequency44100:
return 44100;
case kSamplingFrequency48000:
return 48000;
default:
return 0;
}
}
static int GetChannelModeBit(ChannelMode channel_mode) {
switch (channel_mode) {
case ChannelMode::STEREO:
return kChannelModeJointStereo | kChannelModeStereo;
case ChannelMode::DUALMONO:
return kChannelModeDualChannel;
case ChannelMode::MONO:
return kChannelModeMono;
default:
return -1;
}
}
static ChannelMode GetChannelModeEnum(int channel_mode) {
switch (channel_mode) {
case kChannelModeMono:
return ChannelMode::MONO;
case kChannelModeDualChannel:
return ChannelMode::DUALMONO;
case kChannelModeStereo:
case kChannelModeJointStereo:
return ChannelMode::STEREO;
default:
return ChannelMode::UNKNOWN;
}
}
static int32_t GetBlockLengthValue(int block_length) {
switch (block_length) {
case kBlockLength4:
return 4;
case kBlockLength8:
return 8;
case kBlockLength12:
return 12;
case kBlockLength16:
return 16;
default:
return 0;
}
}
static int32_t GetSubbandsValue(int subbands) {
switch (subbands) {
case kSubbands4:
return 4;
case kSubbands8:
return 8;
default:
return 0;
}
}
static SbcParameters::AllocationMethod GetAllocationMethodEnum(
int allocation_method) {
switch (allocation_method) {
case kAllocationMethodSnr:
return SbcParameters::AllocationMethod::SNR;
case kAllocationMethodLoudness:
default:
return SbcParameters::AllocationMethod::LOUDNESS;
}
}
static int32_t GetSamplingFrequencyValue(const A2dpBits& configuration) {
return GetSamplingFrequencyValue(
configuration.find_active_bit(kSamplingFrequency));
}
static int32_t GetBlockLengthValue(const A2dpBits& configuration) {
return GetBlockLengthValue(configuration.find_active_bit(kBlockLength));
}
static int32_t GetSubbandsValue(const A2dpBits& configuration) {
return GetSubbandsValue(configuration.find_active_bit(kSubbands));
}
static int GetFrameSize(const A2dpBits& configuration, int bitpool) {
const int kSbcHeaderSize = 4;
int subbands = GetSubbandsValue(configuration);
int blocks = GetBlockLengthValue(configuration);
unsigned bits =
((4 * subbands) << !configuration.get(kChannelModeMono)) +
((blocks * bitpool) << configuration.get(kChannelModeDualChannel)) +
((configuration.get(kChannelModeJointStereo) ? subbands : 0));
return kSbcHeaderSize + ((bits + 7) >> 3);
}
static int GetBitrate(const A2dpBits& configuration, int bitpool) {
int sampling_frequency = GetSamplingFrequencyValue(configuration);
int subbands = GetSubbandsValue(configuration);
int blocks = GetBlockLengthValue(configuration);
int bits = 8 * GetFrameSize(configuration, bitpool);
return (bits * sampling_frequency) / (blocks * subbands);
}
static uint8_t GetBitpool(const A2dpBits& configuration, int bitrate) {
int bitpool = 0;
for (int i = 128; i; i >>= 1)
if (bitrate > GetBitrate(configuration, bitpool + i)) {
bitpool += i;
}
return std::clamp(bitpool, 2, 250);
}
/**
* SBC Class implementation
*/
const A2dpOffloadCodecSbc* A2dpOffloadCodecSbc::GetInstance() {
static A2dpOffloadCodecSbc instance;
return &instance;
}
A2dpOffloadCodecSbc::A2dpOffloadCodecSbc()
: A2dpOffloadCodec(info_),
info_({.id = CodecId(CodecId::A2dp::SBC), .name = "SBC"}) {
info_.transport.set<CodecInfo::Transport::Tag::a2dp>();
auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
/* --- Setup Capabilities --- */
a2dp_info.capabilities.resize(kCapabilitiesSize);
std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0);
auto capabilities = A2dpBits(a2dp_info.capabilities);
capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100);
capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000);
capabilities.set(kChannelModeMono, kEnableChannelModeMono);
capabilities.set(kChannelModeDualChannel, kEnableChannelModeDualChannel);
capabilities.set(kChannelModeStereo, kEnableChannelModeStereo);
capabilities.set(kChannelModeJointStereo, kEnableChannelModeJointStereo);
capabilities.set(kBlockLength4, kEnableBlockLength4);
capabilities.set(kBlockLength8, kEnableBlockLength8);
capabilities.set(kBlockLength12, kEnableBlockLength12);
capabilities.set(kBlockLength16, kEnableBlockLength16);
capabilities.set(kSubbands4, kEnableSubbands4);
capabilities.set(kSubbands8, kEnableSubbands8);
capabilities.set(kSubbands4, kEnableSubbands4);
capabilities.set(kSubbands8, kEnableSubbands8);
capabilities.set(kAllocationMethodSnr, kEnableAllocationMethodSnr);
capabilities.set(kAllocationMethodLoudness, kEnableAllocationMethodLoudness);
capabilities.set(kMinimumBitpool, kDefaultMinimumBitpool);
capabilities.set(kMaximumBitpool, kDefaultMaximumBitpool);
/* --- Setup Sampling Frequencies --- */
auto& sampling_frequency = a2dp_info.samplingFrequencyHz;
for (auto v : {16000, 32000, 44100, 48000})
if (capabilities.get(GetSamplingFrequencyBit(int32_t(v))))
sampling_frequency.push_back(v);
/* --- Setup Channel Modes --- */
auto& channel_modes = a2dp_info.channelMode;
for (auto v : {ChannelMode::MONO, ChannelMode::DUALMONO, ChannelMode::STEREO})
if (capabilities.get(GetChannelModeBit(v))) channel_modes.push_back(v);
/* --- Setup Bitdepth --- */
a2dp_info.bitdepth.push_back(kBitdepth);
}
A2dpStatus A2dpOffloadCodecSbc::ParseConfiguration(
const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters, SbcParameters* sbc_parameters) const {
auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
if (configuration.size() != a2dp_info.capabilities.size())
return A2dpStatus::BAD_LENGTH;
auto config = A2dpBits(configuration);
auto lcaps = A2dpBits(a2dp_info.capabilities);
/* --- Check Sampling Frequency --- */
int sampling_frequency = config.find_active_bit(kSamplingFrequency);
if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY;
if (!lcaps.get(sampling_frequency))
return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY;
/* --- Check Channel Mode --- */
int channel_mode = config.find_active_bit(kChannelMode);
if (channel_mode < 0) return A2dpStatus::INVALID_CHANNEL_MODE;
if (!lcaps.get(channel_mode)) return A2dpStatus::NOT_SUPPORTED_CHANNEL_MODE;
/* --- Check Block Length --- */
int block_length = config.find_active_bit(kBlockLength);
if (block_length < 0) return A2dpStatus::INVALID_BLOCK_LENGTH;
/* --- Check Subbands --- */
int subbands = config.find_active_bit(kSubbands);
if (subbands < 0) return A2dpStatus::INVALID_SUBBANDS;
if (!lcaps.get(subbands)) return A2dpStatus::NOT_SUPPORTED_SUBBANDS;
/* --- Check Allocation Method --- */
int allocation_method = config.find_active_bit(kAllocationMethod);
if (allocation_method < 0) return A2dpStatus::INVALID_ALLOCATION_METHOD;
if (!lcaps.get(allocation_method))
return A2dpStatus::NOT_SUPPORTED_ALLOCATION_METHOD;
/* --- Check Bitpool --- */
uint8_t min_bitpool = config.get(kMinimumBitpool);
if (min_bitpool < 2 || min_bitpool > 250)
return A2dpStatus::INVALID_MINIMUM_BITPOOL_VALUE;
if (min_bitpool < lcaps.get(kMinimumBitpool))
return A2dpStatus::NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE;
uint8_t max_bitpool = config.get(kMaximumBitpool);
if (max_bitpool < 2 || max_bitpool > 250)
return A2dpStatus::INVALID_MAXIMUM_BITPOOL_VALUE;
if (max_bitpool > lcaps.get(kMaximumBitpool))
return A2dpStatus::NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE;
/* --- Return --- */
codec_parameters->channelMode = GetChannelModeEnum(channel_mode);
codec_parameters->samplingFrequencyHz =
GetSamplingFrequencyValue(sampling_frequency);
codec_parameters->bitdepth = kBitdepth;
codec_parameters->minBitrate = GetBitrate(config, min_bitpool);
codec_parameters->maxBitrate = GetBitrate(config, max_bitpool);
if (sbc_parameters) {
sbc_parameters->block_length = GetBlockLengthValue(block_length);
sbc_parameters->subbands = GetSubbandsValue(subbands);
sbc_parameters->allocation_method =
GetAllocationMethodEnum(allocation_method);
sbc_parameters->min_bitpool = min_bitpool;
sbc_parameters->max_bitpool = max_bitpool;
}
return A2dpStatus::OK;
}
bool A2dpOffloadCodecSbc::BuildConfiguration(
const std::vector<uint8_t>& remote_capabilities,
const std::optional<CodecParameters>& hint,
std::vector<uint8_t>* configuration) const {
auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false;
auto lcaps = A2dpBits(a2dp_info.capabilities);
auto rcaps = A2dpBits(remote_capabilities);
configuration->resize(a2dp_info.capabilities.size());
std::fill(begin(*configuration), end(*configuration), 0);
auto config = A2dpBits(*configuration);
/* --- Select Sampling Frequency --- */
auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1;
if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint))
config.set(sf_hint);
else if (lcaps.get(kSamplingFrequency44100) &&
rcaps.get(kSamplingFrequency44100))
config.set(kSamplingFrequency44100);
else if (lcaps.get(kSamplingFrequency48000) &&
rcaps.get(kSamplingFrequency48000))
config.set(kSamplingFrequency48000);
else
return false;
/* --- Select Channel Mode --- */
auto cm_hint = hint ? GetChannelModeBit(hint->channelMode) : -1;
if (cm_hint >= 0 && lcaps.get(cm_hint) && rcaps.get(cm_hint))
config.set(cm_hint);
else if (lcaps.get(kChannelModeJointStereo) &&
rcaps.get(kChannelModeJointStereo))
config.set(kChannelModeJointStereo);
else if (lcaps.get(kChannelModeStereo) && rcaps.get(kChannelModeStereo))
config.set(kChannelModeStereo);
else if (lcaps.get(kChannelModeDualChannel) &&
rcaps.get(kChannelModeDualChannel))
config.set(kChannelModeDualChannel);
else if (lcaps.get(kChannelModeMono) && rcaps.get(kChannelModeMono))
config.set(kChannelModeMono);
else
return false;
/* --- Select Block Length --- */
if (lcaps.get(kBlockLength16) && rcaps.get(kBlockLength16))
config.set(kBlockLength16);
else if (lcaps.get(kBlockLength12) && rcaps.get(kBlockLength12))
config.set(kBlockLength12);
else if (lcaps.get(kBlockLength8) && rcaps.get(kBlockLength8))
config.set(kBlockLength8);
else if (lcaps.get(kBlockLength4) && rcaps.get(kBlockLength4))
config.set(kBlockLength4);
else
return false;
/* --- Select Subbands --- */
if (lcaps.get(kSubbands8) && rcaps.get(kSubbands8))
config.set(kSubbands8);
else if (lcaps.get(kSubbands4) && rcaps.get(kSubbands4))
config.set(kSubbands4);
else
return false;
/* --- Select Allocation method --- */
if (lcaps.get(kAllocationMethodLoudness) &&
rcaps.get(kAllocationMethodLoudness))
config.set(kAllocationMethodLoudness);
else if (lcaps.get(kAllocationMethodSnr) && rcaps.get(kAllocationMethodSnr))
config.set(kAllocationMethodSnr);
else
return false;
/* --- Select Bitpool --- */
uint8_t min_bitpool = rcaps.get(kMinimumBitpool);
uint8_t max_bitpool = rcaps.get(kMaximumBitpool);
if (min_bitpool < 2 || min_bitpool > 250 || max_bitpool < 2 ||
max_bitpool > 250 || min_bitpool > max_bitpool) {
min_bitpool = 2;
max_bitpool = 250;
}
min_bitpool = std::max(min_bitpool, uint8_t(lcaps.get(kMinimumBitpool)));
max_bitpool = std::max(max_bitpool, uint8_t(lcaps.get(kMaximumBitpool)));
if (hint) {
min_bitpool =
std::max(min_bitpool, GetBitpool(*configuration, hint->minBitrate));
if (hint->maxBitrate && hint->maxBitrate >= hint->minBitrate)
max_bitpool =
std::min(max_bitpool, GetBitpool(*configuration, hint->maxBitrate));
}
config.set(kMinimumBitpool, min_bitpool);
config.set(kMaximumBitpool, max_bitpool);
return true;
}
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -0,0 +1,61 @@
/*
* 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 "A2dpOffloadCodec.h"
namespace aidl::android::hardware::bluetooth::audio {
struct SbcParameters : public CodecParameters {
enum class AllocationMethod { SNR, LOUDNESS };
AllocationMethod allocation_method;
int block_length;
int subbands;
int min_bitpool;
int max_bitpool;
};
class A2dpOffloadCodecSbc : public A2dpOffloadCodec {
CodecInfo info_;
A2dpOffloadCodecSbc();
A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters,
SbcParameters* sbc_parameters) const;
public:
static const A2dpOffloadCodecSbc* GetInstance();
A2dpStatus ParseConfiguration(
const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters) const override {
return ParseConfiguration(configuration, codec_parameters, nullptr);
}
A2dpStatus ParseConfiguration(const std::vector<uint8_t>& configuration,
SbcParameters* sbc_parameters) const {
return ParseConfiguration(configuration, sbc_parameters, sbc_parameters);
}
bool BuildConfiguration(const std::vector<uint8_t>& remote_capabilities,
const std::optional<CodecParameters>& hint,
std::vector<uint8_t>* configuration) const override;
};
} // namespace aidl::android::hardware::bluetooth::audio

View file

@ -18,6 +18,9 @@ cc_library_shared {
"BluetoothAudioProvider.cpp",
"BluetoothAudioProviderFactory.cpp",
"A2dpOffloadAudioProvider.cpp",
"A2dpOffloadCodecAac.cpp",
"A2dpOffloadCodecFactory.cpp",
"A2dpOffloadCodecSbc.cpp",
"A2dpSoftwareAudioProvider.cpp",
"HearingAidAudioProvider.cpp",
"HfpOffloadAudioProvider.cpp",

View file

@ -21,6 +21,8 @@
#include <BluetoothAudioSessionReport.h>
#include <android-base/logging.h>
#include "A2dpOffloadCodecFactory.h"
namespace aidl {
namespace android {
namespace hardware {
@ -165,39 +167,24 @@ ndk::ScopedAStatus BluetoothAudioProvider::setLowLatencyModeAllowed(
}
ndk::ScopedAStatus BluetoothAudioProvider::parseA2dpConfiguration(
const CodecId& codec_id, const std::vector<uint8_t>& configuration,
CodecParameters* codec_parameters, A2dpStatus* _aidl_return) {
if (stack_iface_ == nullptr) {
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
<< " has NO session";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
*_aidl_return = A2dpStatus::OK;
(void)codec_id;
(void)configuration;
(void)codec_parameters;
return ndk::ScopedAStatus::ok();
[[maybe_unused]] const CodecId& codec_id,
[[maybe_unused]] const std::vector<uint8_t>& configuration,
[[maybe_unused]] CodecParameters* codec_parameters,
[[maybe_unused]] A2dpStatus* _aidl_return) {
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
<< " is illegal";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ndk::ScopedAStatus BluetoothAudioProvider::getA2dpConfiguration(
const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
const A2dpConfigurationHint& hint,
std::optional<audio::A2dpConfiguration>* _aidl_return) {
if (stack_iface_ == nullptr) {
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
<< " has NO session";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
[[maybe_unused]] const std::vector<A2dpRemoteCapabilities>&
remote_a2dp_capabilities,
[[maybe_unused]] const A2dpConfigurationHint& hint,
[[maybe_unused]] std::optional<audio::A2dpConfiguration>* _aidl_return) {
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
<< " is illegal";
*_aidl_return = std::nullopt;
(void)remote_a2dp_capabilities;
(void)hint;
return ndk::ScopedAStatus::ok();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
} // namespace audio

View file

@ -22,6 +22,7 @@
#include <android-base/logging.h>
#include "A2dpOffloadAudioProvider.h"
#include "A2dpOffloadCodecFactory.h"
#include "A2dpSoftwareAudioProvider.h"
#include "BluetoothAudioProvider.h"
#include "HearingAidAudioProvider.h"
@ -150,7 +151,14 @@ ndk::ScopedAStatus BluetoothAudioProviderFactory::getProviderInfo(
SessionType session_type, std::optional<ProviderInfo>* _aidl_return) {
*_aidl_return = std::nullopt;
(void)session_type;
if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
auto& provider_info = _aidl_return->emplace();
provider_info.name = A2dpOffloadCodecFactory::GetInstance()->name;
for (auto codec : A2dpOffloadCodecFactory::GetInstance()->codecs)
provider_info.codecInfos.push_back(codec->info);
}
return ndk::ScopedAStatus::ok();
}

View file

@ -304,7 +304,8 @@ bool BluetoothAudioSession::UpdateAudioConfig(
audio_config_tag == AudioConfiguration::pcmConfig);
bool is_a2dp_offload_audio_config =
(is_offload_a2dp_session &&
audio_config_tag == AudioConfiguration::a2dpConfig);
(audio_config_tag == AudioConfiguration::a2dp ||
audio_config_tag == AudioConfiguration::a2dpConfig));
bool is_hfp_offload_audio_config =
(is_offload_hfp_session &&
audio_config_tag == AudioConfiguration::hfpConfig);