audio: Fix BT AIDL HAL module implementation
In order to align with legacy behavior, when opening a stream,
the module must suggest the current configuration of the BT session.
For that to work, the BT device proxy must be opened prior
to creating a stream, code moved to ModuleBluetooth.
Fix minor inconsistencies and bugs found during testing.
Bug: 301213930
Bug: 316027906
Test: atest pts-bot
Change-Id: I04ddaf73be82f872a3f32a789563c3cbd648eb61
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
index 0cee7f4..a73af1b 100644
--- a/audio/aidl/default/bluetooth/StreamBluetooth.cpp
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "AHAL_StreamBluetooth"
+#include <algorithm>
+#define LOG_TAG "AHAL_StreamBluetooth"
#include <Utils.h>
#include <android-base/logging.h>
#include <audio_utils/clock.h>
@@ -31,6 +32,7 @@
using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
using aidl::android::hardware::bluetooth::audio::PresentationPosition;
using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfigBase;
using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioDeviceAddress;
using aidl::android::media::audio::common::AudioFormatDescription;
@@ -48,51 +50,33 @@
constexpr int kBluetoothDefaultInputBufferMs = 20;
constexpr int kBluetoothDefaultOutputBufferMs = 10;
// constexpr int kBluetoothSpatializerOutputBufferMs = 10;
+constexpr int kBluetoothDefaultRemoteDelayMs = 200;
-// pcm configuration params are not really used by the module
StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
- ModuleBluetooth::BtProfileHandles&& btHandles)
+ ModuleBluetooth::BtProfileHandles&& btHandles,
+ const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+ const PcmConfiguration& pcmConfig)
: StreamCommonImpl(context, metadata),
- mSampleRate(getContext().getSampleRate()),
- mChannelLayout(getContext().getChannelLayout()),
- mFormat(getContext().getFormat()),
mFrameSizeBytes(getContext().getFrameSize()),
mIsInput(isInput(metadata)),
mBluetoothA2dp(std::move(std::get<ModuleBluetooth::BtInterface::BTA2DP>(btHandles))),
- mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))) {
- mPreferredDataIntervalUs =
- (mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs) * 1000;
- mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
- mIsInitialized = false;
- mIsReadyToClose = false;
-}
+ mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))),
+ mPreferredDataIntervalUs(pcmConfig.dataIntervalUs != 0
+ ? pcmConfig.dataIntervalUs
+ : (mIsInput ? kBluetoothDefaultInputBufferMs
+ : kBluetoothDefaultOutputBufferMs) *
+ 1000),
+ mPreferredFrameCount(
+ frameCountFromDurationUs(mPreferredDataIntervalUs, pcmConfig.sampleRateHz)),
+ mBtDeviceProxy(btDeviceProxy) {}
::android::status_t StreamBluetooth::init() {
- return ::android::OK; // defering this till we get AudioDeviceDescription
-}
-
-const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
std::lock_guard guard(mLock);
- return StreamCommonImpl::getConnectedDevices();
-}
-
-ndk::ScopedAStatus StreamBluetooth::setConnectedDevices(
- const std::vector<AudioDevice>& connectedDevices) {
- if (mIsInput && connectedDevices.size() > 1) {
- LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
- << ") for input stream";
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ if (mBtDeviceProxy == nullptr) {
+ // This is a normal situation in VTS tests.
+ LOG(INFO) << __func__ << ": no BT HAL proxy, stream is non-functional";
}
- for (const auto& connectedDevice : connectedDevices) {
- if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) {
- LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
- }
- }
- std::lock_guard guard(mLock);
- RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
- mIsInitialized = false; // updated connected device list, need initialization
- return ndk::ScopedAStatus::ok();
+ return ::android::OK;
}
::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
@@ -112,167 +96,111 @@
::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
size_t* actualFrameCount, int32_t* latencyMs) {
std::lock_guard guard(mLock);
- if (!mIsInitialized || mIsReadyToClose) {
- // 'setConnectedDevices' has been called or stream is ready to close, so no transfers
+ if (mBtDeviceProxy == nullptr || mBtDeviceProxy->getState() == BluetoothStreamState::DISABLED) {
*actualFrameCount = 0;
*latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
return ::android::OK;
}
*actualFrameCount = 0;
*latencyMs = 0;
- for (auto proxy : mBtDeviceProxies) {
- if (!proxy->start()) {
- LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start ";
- return -EIO;
- }
- const size_t fc = std::min(frameCount, mPreferredFrameCount);
- const size_t bytesToTransfer = fc * mFrameSizeBytes;
- if (mIsInput) {
- const size_t totalRead = proxy->readData(buffer, bytesToTransfer);
- *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
- } else {
- const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer);
- *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
- }
- PresentationPosition presentation_position;
- if (!proxy->getPresentationPosition(presentation_position)) {
- LOG(ERROR) << __func__ << ": getPresentationPosition returned error ";
- return ::android::UNKNOWN_ERROR;
- }
- *latencyMs =
- std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
- NANOS_PER_MILLISECOND));
+ if (!mBtDeviceProxy->start()) {
+ LOG(ERROR) << __func__ << ": state= " << mBtDeviceProxy->getState() << " failed to start";
+ return -EIO;
}
+ const size_t fc = std::min(frameCount, mPreferredFrameCount);
+ const size_t bytesToTransfer = fc * mFrameSizeBytes;
+ if (mIsInput) {
+ const size_t totalRead = mBtDeviceProxy->readData(buffer, bytesToTransfer);
+ *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
+ } else {
+ const size_t totalWrite = mBtDeviceProxy->writeData(buffer, bytesToTransfer);
+ *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
+ }
+ PresentationPosition presentation_position;
+ if (!mBtDeviceProxy->getPresentationPosition(presentation_position)) {
+ presentation_position.remoteDeviceAudioDelayNanos =
+ kBluetoothDefaultRemoteDelayMs * NANOS_PER_MILLISECOND;
+ LOG(WARNING) << __func__ << ": getPresentationPosition failed, latency info is unavailable";
+ }
+ // TODO(b/317117580): incorporate logic from
+ // packages/modules/Bluetooth/system/audio_bluetooth_hw/stream_apis.cc
+ // out_calculate_feeding_delay_ms / in_calculate_starving_delay_ms
+ *latencyMs = std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
+ NANOS_PER_MILLISECOND));
return ::android::OK;
}
-::android::status_t StreamBluetooth::initialize() {
- if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
- LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available";
- return ::android::UNKNOWN_ERROR;
- }
- if (StreamCommonImpl::getConnectedDevices().empty()) {
- LOG(ERROR) << __func__ << ", has no connected devices";
- return ::android::NO_INIT;
- }
- // unregister older proxies (if any)
- for (auto proxy : mBtDeviceProxies) {
- proxy->stop();
- proxy->unregisterPort();
- }
- mBtDeviceProxies.clear();
- for (auto it = StreamCommonImpl::getConnectedDevices().begin();
- it != StreamCommonImpl::getConnectedDevices().end(); ++it) {
- std::shared_ptr<BluetoothAudioPortAidl> proxy =
- mIsInput ? std::shared_ptr<BluetoothAudioPortAidl>(
- std::make_shared<BluetoothAudioPortAidlIn>())
- : std::shared_ptr<BluetoothAudioPortAidl>(
- std::make_shared<BluetoothAudioPortAidlOut>());
- if (proxy->registerPort(it->type)) {
- LOG(ERROR) << __func__ << ": cannot init HAL";
- return ::android::UNKNOWN_ERROR;
- }
- PcmConfiguration config;
- if (!proxy->loadAudioConfig(&config)) {
- LOG(ERROR) << __func__ << ": state=" << proxy->getState()
- << " failed to get audio config";
- return ::android::UNKNOWN_ERROR;
- }
- // TODO: Ensure minimum duration for spatialized output?
- // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
- if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) {
- proxy->forcePcmStereoToMono(true);
- config.channelMode = ChannelMode::STEREO;
- LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
- }
- if (!checkConfigParams(config)) {
- LOG(ERROR) << __func__ << " checkConfigParams failed";
- return ::android::UNKNOWN_ERROR;
- }
- mBtDeviceProxies.push_back(std::move(proxy));
- }
- mIsInitialized = true;
- return ::android::OK;
-}
-
-bool StreamBluetooth::checkConfigParams(
- ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) {
- if ((int)mSampleRate != config.sampleRateHz) {
- LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate
- << " hal val = " << config.sampleRateHz;
+// static
+bool StreamBluetooth::checkConfigParams(const PcmConfiguration& pcmConfig,
+ const AudioConfigBase& config) {
+ if ((int)config.sampleRate != pcmConfig.sampleRateHz) {
+ LOG(ERROR) << __func__ << ": sample rate mismatch, stream value=" << config.sampleRate
+ << ", BT HAL value=" << pcmConfig.sampleRateHz;
return false;
}
- auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout);
- if ((config.channelMode == ChannelMode::MONO && channelCount != 1) ||
- (config.channelMode == ChannelMode::STEREO && channelCount != 2)) {
- LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount
- << " hal val = " << toString(config.channelMode);
+ const auto channelCount =
+ aidl::android::hardware::audio::common::getChannelCount(config.channelMask);
+ if ((pcmConfig.channelMode == ChannelMode::MONO && channelCount != 1) ||
+ (pcmConfig.channelMode == ChannelMode::STEREO && channelCount != 2)) {
+ LOG(ERROR) << __func__ << ": Channel count mismatch, stream value=" << channelCount
+ << ", BT HAL value=" << toString(pcmConfig.channelMode);
return false;
}
- if (mFormat.type != AudioFormatType::PCM) {
- LOG(ERROR) << __func__ << ": unexpected format type "
- << aidl::android::media::audio::common::toString(mFormat.type);
+ if (config.format.type != AudioFormatType::PCM) {
+ LOG(ERROR) << __func__
+ << ": unexpected stream format type: " << toString(config.format.type);
return false;
}
- int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8;
- if (bps != config.bitsPerSample) {
- LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps
- << " hal val = " << config.bitsPerSample;
+ const int8_t bitsPerSample =
+ aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(config.format.pcm) * 8;
+ if (bitsPerSample != pcmConfig.bitsPerSample) {
+ LOG(ERROR) << __func__ << ": bits per sample mismatch, stream value=" << bitsPerSample
+ << ", BT HAL value=" << pcmConfig.bitsPerSample;
return false;
}
- if (config.dataIntervalUs > 0) {
- mPreferredDataIntervalUs =
- std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
- mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
- }
return true;
}
ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
std::lock_guard guard(mLock);
- mIsReadyToClose = true;
+ if (mBtDeviceProxy != nullptr) {
+ if (mBtDeviceProxy->getState() != BluetoothStreamState::DISABLED) {
+ mBtDeviceProxy->stop();
+ }
+ }
return ndk::ScopedAStatus::ok();
}
::android::status_t StreamBluetooth::standby() {
std::lock_guard guard(mLock);
- if (!mIsInitialized) {
- if (auto status = initialize(); status != ::android::OK) return status;
- }
- for (auto proxy : mBtDeviceProxies) {
- if (!proxy->suspend()) {
- LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by ";
- return -EIO;
- }
- }
+ if (mBtDeviceProxy != nullptr) mBtDeviceProxy->suspend();
return ::android::OK;
}
::android::status_t StreamBluetooth::start() {
std::lock_guard guard(mLock);
- if (!mIsInitialized) return initialize();
+ if (mBtDeviceProxy != nullptr) mBtDeviceProxy->start();
return ::android::OK;
}
void StreamBluetooth::shutdown() {
std::lock_guard guard(mLock);
- for (auto proxy : mBtDeviceProxies) {
- proxy->stop();
- proxy->unregisterPort();
+ if (mBtDeviceProxy != nullptr) {
+ mBtDeviceProxy->stop();
+ mBtDeviceProxy = nullptr;
}
- mBtDeviceProxies.clear();
}
ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
std::lock_guard guard(mLock);
- if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ if (mBtDeviceProxy == nullptr) {
+ return ndk::ScopedAStatus::ok();
+ }
bool isOk = true;
if (isInput(metadata)) {
- isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get<SinkMetadata>(metadata));
+ isOk = mBtDeviceProxy->updateSinkMetadata(std::get<SinkMetadata>(metadata));
} else {
- for (auto proxy : mBtDeviceProxies) {
- if (!proxy->updateSourceMetadata(std::get<SourceMetadata>(metadata))) isOk = false;
- }
+ isOk = mBtDeviceProxy->updateSourceMetadata(std::get<SourceMetadata>(metadata));
}
return isOk ? ndk::ScopedAStatus::ok()
: ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
@@ -280,7 +208,6 @@
ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
if (mIsInput) {
- LOG(WARNING) << __func__ << ": not handled";
return ndk::ScopedAStatus::ok();
}
auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
@@ -297,15 +224,10 @@
bool hasLeParam, enableLe;
auto btLe = mBluetoothLe.lock();
hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
- std::unique_lock lock(mLock);
- ::android::base::ScopedLockAssertion lock_assertion(mLock);
- if (!mIsInitialized) {
- LOG(WARNING) << __func__ << ": init not done";
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
- for (auto proxy : mBtDeviceProxies) {
- if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) ||
- (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) {
+ std::lock_guard guard(mLock);
+ if (mBtDeviceProxy != nullptr) {
+ if ((hasA2dpParam && mBtDeviceProxy->isA2dp() && !applyParam(mBtDeviceProxy, enableA2dp)) ||
+ (hasLeParam && mBtDeviceProxy->isLeAudio() && !applyParam(mBtDeviceProxy, enableLe))) {
LOG(DEBUG) << __func__ << ": applyParam failed";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
@@ -313,11 +235,20 @@
return ndk::ScopedAStatus::ok();
}
+// static
+int32_t StreamInBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+ if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultInputBufferMs * 1000LL;
+ return dataIntervalUs / 1000LL;
+}
+
StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones,
- ModuleBluetooth::BtProfileHandles&& btProfileHandles)
+ ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+ const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+ const PcmConfiguration& pcmConfig)
: StreamIn(std::move(context), microphones),
- StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
+ StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles), btDeviceProxy,
+ pcmConfig) {}
ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
@@ -325,11 +256,20 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+// static
+int32_t StreamOutBluetooth::getNominalLatencyMs(size_t dataIntervalUs) {
+ if (dataIntervalUs == 0) dataIntervalUs = kBluetoothDefaultOutputBufferMs * 1000LL;
+ return dataIntervalUs / 1000LL;
+}
+
StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo,
- ModuleBluetooth::BtProfileHandles&& btProfileHandles)
+ ModuleBluetooth::BtProfileHandles&& btProfileHandles,
+ const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
+ const PcmConfiguration& pcmConfig)
: StreamOut(std::move(context), offloadInfo),
- StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
+ StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles), btDeviceProxy,
+ pcmConfig) {}
} // namespace aidl::android::hardware::audio::core