416 lines
17 KiB
C++
416 lines
17 KiB
C++
|
/*
|
||
|
* Copyright 2018 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#define LOG_TAG "BTAudioProviderSessionCodecsDB"
|
||
|
|
||
|
#include "BluetoothAudioSupportedCodecsDB.h"
|
||
|
|
||
|
#include <android-base/logging.h>
|
||
|
|
||
|
namespace android {
|
||
|
namespace bluetooth {
|
||
|
namespace audio {
|
||
|
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::CodecType;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::SampleRate;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
|
||
|
using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
|
||
|
|
||
|
// Default Supported PCM Parameters
|
||
|
static const PcmParameters kDefaultSoftwarePcmCapabilities = {
|
||
|
.sampleRate = static_cast<SampleRate>(
|
||
|
SampleRate::RATE_44100 | SampleRate::RATE_48000 |
|
||
|
SampleRate::RATE_88200 | SampleRate::RATE_96000 |
|
||
|
SampleRate::RATE_16000 | SampleRate::RATE_24000),
|
||
|
.channelMode =
|
||
|
static_cast<ChannelMode>(ChannelMode::MONO | ChannelMode::STEREO),
|
||
|
.bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 |
|
||
|
BitsPerSample::BITS_24 |
|
||
|
BitsPerSample::BITS_32)};
|
||
|
|
||
|
// Default Supported Codecs
|
||
|
// SBC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(MONO|STEREO)
|
||
|
// all blocks | subbands 8 | Loudness
|
||
|
static const SbcParameters kDefaultOffloadSbcCapability = {
|
||
|
.sampleRate = SampleRate::RATE_44100,
|
||
|
.channelMode = static_cast<SbcChannelMode>(SbcChannelMode::MONO |
|
||
|
SbcChannelMode::JOINT_STEREO),
|
||
|
.blockLength = static_cast<SbcBlockLength>(
|
||
|
SbcBlockLength::BLOCKS_4 | SbcBlockLength::BLOCKS_8 |
|
||
|
SbcBlockLength::BLOCKS_12 | SbcBlockLength::BLOCKS_16),
|
||
|
.numSubbands = SbcNumSubbands::SUBBAND_8,
|
||
|
.allocMethod = SbcAllocMethod::ALLOC_MD_L,
|
||
|
.bitsPerSample = BitsPerSample::BITS_16,
|
||
|
.minBitpool = 2,
|
||
|
.maxBitpool = 53};
|
||
|
|
||
|
// AAC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(STEREO)
|
||
|
static const AacParameters kDefaultOffloadAacCapability = {
|
||
|
.objectType = AacObjectType::MPEG2_LC,
|
||
|
.sampleRate = SampleRate::RATE_44100,
|
||
|
.channelMode = ChannelMode::STEREO,
|
||
|
.variableBitRateEnabled = AacVariableBitRate::ENABLED,
|
||
|
.bitsPerSample = BitsPerSample::BITS_16};
|
||
|
|
||
|
// LDAC: mSampleRate:(44100|48000|88200|96000), mBitsPerSample:(16|24|32),
|
||
|
// mChannelMode:(DUAL|STEREO)
|
||
|
static const LdacParameters kDefaultOffloadLdacCapability = {
|
||
|
.sampleRate = static_cast<SampleRate>(
|
||
|
SampleRate::RATE_44100 | SampleRate::RATE_48000 |
|
||
|
SampleRate::RATE_88200 | SampleRate::RATE_96000),
|
||
|
.channelMode = static_cast<LdacChannelMode>(LdacChannelMode::DUAL |
|
||
|
LdacChannelMode::STEREO),
|
||
|
.qualityIndex = LdacQualityIndex::QUALITY_HIGH,
|
||
|
.bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 |
|
||
|
BitsPerSample::BITS_24 |
|
||
|
BitsPerSample::BITS_32)};
|
||
|
|
||
|
// aptX: mSampleRate:(44100|48000), mBitsPerSample:(16), mChannelMode:(STEREO)
|
||
|
static const AptxParameters kDefaultOffloadAptxCapability = {
|
||
|
.sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
|
||
|
SampleRate::RATE_48000),
|
||
|
.channelMode = ChannelMode::STEREO,
|
||
|
.bitsPerSample = BitsPerSample::BITS_16,
|
||
|
};
|
||
|
|
||
|
// aptX HD: mSampleRate:(44100|48000), mBitsPerSample:(24),
|
||
|
// mChannelMode:(STEREO)
|
||
|
static const AptxParameters kDefaultOffloadAptxHdCapability = {
|
||
|
.sampleRate = static_cast<SampleRate>(SampleRate::RATE_44100 |
|
||
|
SampleRate::RATE_48000),
|
||
|
.channelMode = ChannelMode::STEREO,
|
||
|
.bitsPerSample = BitsPerSample::BITS_24,
|
||
|
};
|
||
|
|
||
|
const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
|
||
|
{.codecType = CodecType::SBC, .capabilities = {}},
|
||
|
{.codecType = CodecType::AAC, .capabilities = {}},
|
||
|
{.codecType = CodecType::LDAC, .capabilities = {}},
|
||
|
{.codecType = CodecType::APTX, .capabilities = {}},
|
||
|
{.codecType = CodecType::APTX_HD, .capabilities = {}}};
|
||
|
|
||
|
static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield) {
|
||
|
bool single = false;
|
||
|
uint32_t test_bit = 0x00000001;
|
||
|
while (test_bit <= bitmasks && test_bit <= bitfield) {
|
||
|
if (bitfield & test_bit && bitmasks & test_bit) {
|
||
|
if (single) return false;
|
||
|
single = true;
|
||
|
}
|
||
|
if (test_bit == 0x80000000) break;
|
||
|
test_bit <<= 1;
|
||
|
}
|
||
|
return single;
|
||
|
}
|
||
|
|
||
|
static bool IsOffloadSbcConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific);
|
||
|
static bool IsOffloadAacConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific);
|
||
|
static bool IsOffloadLdacConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific);
|
||
|
static bool IsOffloadAptxConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific);
|
||
|
static bool IsOffloadAptxHdConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific);
|
||
|
|
||
|
static bool IsOffloadSbcConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||
|
if (codec_specific.getDiscriminator() !=
|
||
|
CodecConfiguration::CodecSpecific::hidl_discriminator::sbcConfig) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
const SbcParameters sbc_data = codec_specific.sbcConfig();
|
||
|
if (!IsSingleBit(static_cast<uint32_t>(sbc_data.sampleRate), 0xff) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(sbc_data.channelMode), 0x0f) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(sbc_data.blockLength), 0xf0) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(sbc_data.numSubbands), 0x0c) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(sbc_data.allocMethod), 0x03) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(sbc_data.bitsPerSample), 0x07) ||
|
||
|
sbc_data.minBitpool > sbc_data.maxBitpool) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
} else if ((sbc_data.sampleRate & kDefaultOffloadSbcCapability.sampleRate) &&
|
||
|
(sbc_data.channelMode &
|
||
|
kDefaultOffloadSbcCapability.channelMode) &&
|
||
|
(sbc_data.blockLength &
|
||
|
kDefaultOffloadSbcCapability.blockLength) &&
|
||
|
(sbc_data.numSubbands &
|
||
|
kDefaultOffloadSbcCapability.numSubbands) &&
|
||
|
(sbc_data.allocMethod &
|
||
|
kDefaultOffloadSbcCapability.allocMethod) &&
|
||
|
(sbc_data.bitsPerSample &
|
||
|
kDefaultOffloadSbcCapability.bitsPerSample) &&
|
||
|
(kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool &&
|
||
|
sbc_data.maxBitpool <= kDefaultOffloadSbcCapability.maxBitpool)) {
|
||
|
return true;
|
||
|
}
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Unsupported CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool IsOffloadAacConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||
|
if (codec_specific.getDiscriminator() !=
|
||
|
CodecConfiguration::CodecSpecific::hidl_discriminator::aacConfig) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
const AacParameters aac_data = codec_specific.aacConfig();
|
||
|
if (!IsSingleBit(static_cast<uint32_t>(aac_data.objectType), 0xf0) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(aac_data.sampleRate), 0xff) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(aac_data.channelMode), 0x03) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(aac_data.bitsPerSample), 0x07)) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
} else if ((aac_data.objectType & kDefaultOffloadAacCapability.objectType) &&
|
||
|
(aac_data.sampleRate & kDefaultOffloadAacCapability.sampleRate) &&
|
||
|
(aac_data.channelMode &
|
||
|
kDefaultOffloadAacCapability.channelMode) &&
|
||
|
(aac_data.variableBitRateEnabled == AacVariableBitRate::DISABLED ||
|
||
|
kDefaultOffloadAacCapability.variableBitRateEnabled ==
|
||
|
AacVariableBitRate::ENABLED) &&
|
||
|
(aac_data.bitsPerSample &
|
||
|
kDefaultOffloadAacCapability.bitsPerSample)) {
|
||
|
return true;
|
||
|
}
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Unsupported CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool IsOffloadLdacConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||
|
if (codec_specific.getDiscriminator() !=
|
||
|
CodecConfiguration::CodecSpecific::hidl_discriminator::ldacConfig) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
const LdacParameters ldac_data = codec_specific.ldacConfig();
|
||
|
if (!IsSingleBit(static_cast<uint32_t>(ldac_data.sampleRate), 0xff) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(ldac_data.channelMode), 0x07) ||
|
||
|
(ldac_data.qualityIndex > LdacQualityIndex::QUALITY_LOW &&
|
||
|
ldac_data.qualityIndex != LdacQualityIndex::QUALITY_ABR) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(ldac_data.bitsPerSample), 0x07)) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
} else if ((ldac_data.sampleRate &
|
||
|
kDefaultOffloadLdacCapability.sampleRate) &&
|
||
|
(ldac_data.channelMode &
|
||
|
kDefaultOffloadLdacCapability.channelMode) &&
|
||
|
(ldac_data.bitsPerSample &
|
||
|
kDefaultOffloadLdacCapability.bitsPerSample)) {
|
||
|
return true;
|
||
|
}
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Unsupported CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool IsOffloadAptxConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||
|
if (codec_specific.getDiscriminator() !=
|
||
|
CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
const AptxParameters aptx_data = codec_specific.aptxConfig();
|
||
|
if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
} else if ((aptx_data.sampleRate &
|
||
|
kDefaultOffloadAptxCapability.sampleRate) &&
|
||
|
(aptx_data.channelMode &
|
||
|
kDefaultOffloadAptxCapability.channelMode) &&
|
||
|
(aptx_data.bitsPerSample &
|
||
|
kDefaultOffloadAptxCapability.bitsPerSample)) {
|
||
|
return true;
|
||
|
}
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Unsupported CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static bool IsOffloadAptxHdConfigurationValid(
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific) {
|
||
|
if (codec_specific.getDiscriminator() !=
|
||
|
CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
const AptxParameters aptx_data = codec_specific.aptxConfig();
|
||
|
if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) ||
|
||
|
!IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
} else if ((aptx_data.sampleRate &
|
||
|
kDefaultOffloadAptxHdCapability.sampleRate) &&
|
||
|
(aptx_data.channelMode &
|
||
|
kDefaultOffloadAptxHdCapability.channelMode) &&
|
||
|
(aptx_data.bitsPerSample &
|
||
|
kDefaultOffloadAptxHdCapability.bitsPerSample)) {
|
||
|
return true;
|
||
|
}
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Unsupported CodecSpecific=" << toString(codec_specific);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
std::vector<PcmParameters> GetSoftwarePcmCapabilities() {
|
||
|
return std::vector<PcmParameters>(1, kDefaultSoftwarePcmCapabilities);
|
||
|
}
|
||
|
|
||
|
std::vector<CodecCapabilities> GetOffloadCodecCapabilities(
|
||
|
const SessionType& session_type) {
|
||
|
if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
|
||
|
return std::vector<CodecCapabilities>(0);
|
||
|
}
|
||
|
std::vector<CodecCapabilities> offload_a2dp_codec_capabilities =
|
||
|
kDefaultOffloadA2dpCodecCapabilities;
|
||
|
for (auto& codec_capability : offload_a2dp_codec_capabilities) {
|
||
|
switch (codec_capability.codecType) {
|
||
|
case CodecType::SBC:
|
||
|
codec_capability.capabilities.sbcCapabilities(
|
||
|
kDefaultOffloadSbcCapability);
|
||
|
break;
|
||
|
case CodecType::AAC:
|
||
|
codec_capability.capabilities.aacCapabilities(
|
||
|
kDefaultOffloadAacCapability);
|
||
|
break;
|
||
|
case CodecType::LDAC:
|
||
|
codec_capability.capabilities.ldacCapabilities(
|
||
|
kDefaultOffloadLdacCapability);
|
||
|
break;
|
||
|
case CodecType::APTX:
|
||
|
codec_capability.capabilities.aptxCapabilities(
|
||
|
kDefaultOffloadAptxCapability);
|
||
|
break;
|
||
|
case CodecType::APTX_HD:
|
||
|
codec_capability.capabilities.aptxCapabilities(
|
||
|
kDefaultOffloadAptxHdCapability);
|
||
|
break;
|
||
|
case CodecType::UNKNOWN:
|
||
|
codec_capability = {};
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return offload_a2dp_codec_capabilities;
|
||
|
}
|
||
|
|
||
|
bool IsSoftwarePcmConfigurationValid(const PcmParameters& pcm_config) {
|
||
|
if ((pcm_config.sampleRate != SampleRate::RATE_44100 &&
|
||
|
pcm_config.sampleRate != SampleRate::RATE_48000 &&
|
||
|
pcm_config.sampleRate != SampleRate::RATE_88200 &&
|
||
|
pcm_config.sampleRate != SampleRate::RATE_96000 &&
|
||
|
pcm_config.sampleRate != SampleRate::RATE_16000 &&
|
||
|
pcm_config.sampleRate != SampleRate::RATE_24000) ||
|
||
|
(pcm_config.bitsPerSample != BitsPerSample::BITS_16 &&
|
||
|
pcm_config.bitsPerSample != BitsPerSample::BITS_24 &&
|
||
|
pcm_config.bitsPerSample != BitsPerSample::BITS_32) ||
|
||
|
(pcm_config.channelMode != ChannelMode::MONO &&
|
||
|
pcm_config.channelMode != ChannelMode::STEREO)) {
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Invalid PCM Configuration=" << toString(pcm_config);
|
||
|
return false;
|
||
|
} else if (pcm_config.sampleRate &
|
||
|
kDefaultSoftwarePcmCapabilities.sampleRate &&
|
||
|
pcm_config.bitsPerSample &
|
||
|
kDefaultSoftwarePcmCapabilities.bitsPerSample &&
|
||
|
pcm_config.channelMode &
|
||
|
kDefaultSoftwarePcmCapabilities.channelMode) {
|
||
|
return true;
|
||
|
}
|
||
|
LOG(WARNING) << __func__
|
||
|
<< ": Unsupported PCM Configuration=" << toString(pcm_config);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool IsOffloadCodecConfigurationValid(const SessionType& session_type,
|
||
|
const CodecConfiguration& codec_config) {
|
||
|
if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
|
||
|
LOG(ERROR) << __func__
|
||
|
<< ": Invalid SessionType=" << toString(session_type);
|
||
|
return false;
|
||
|
} else if (codec_config.encodedAudioBitrate < 0x00000001 ||
|
||
|
0x00ffffff < codec_config.encodedAudioBitrate) {
|
||
|
LOG(ERROR) << __func__ << ": Unsupported Codec Configuration="
|
||
|
<< toString(codec_config);
|
||
|
return false;
|
||
|
}
|
||
|
const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config;
|
||
|
switch (codec_config.codecType) {
|
||
|
case CodecType::SBC:
|
||
|
if (IsOffloadSbcConfigurationValid(codec_specific)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
case CodecType::AAC:
|
||
|
if (IsOffloadAacConfigurationValid(codec_specific)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
case CodecType::LDAC:
|
||
|
if (IsOffloadLdacConfigurationValid(codec_specific)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
case CodecType::APTX:
|
||
|
if (IsOffloadAptxConfigurationValid(codec_specific)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
case CodecType::APTX_HD:
|
||
|
if (IsOffloadAptxHdConfigurationValid(codec_specific)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
case CodecType::UNKNOWN:
|
||
|
return false;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
} // namespace audio
|
||
|
} // namespace bluetooth
|
||
|
} // namespace android
|