mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-02 20:24:19 +00:00
When the framework uses mixers, it rounds up the buffer size to the frame count which is a multiple of 16. In the HIDL implementation, this adjustment was done after the framework thread was already created, and FMQ was created on the first transfer, using adjusted size. In the AIDL implementation, the FMQ is created together with the stream, using the size suggested by the HAL. Bug: 321233946 Test: verify audio playback over S/W A2DP (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f2f9ae08c2ee4e396bbe4b8c7e955bad725ce545) Merged-In: I35a5479bfc87a290aff09d51415381948857a146 Change-Id: I35a5479bfc87a290aff09d51415381948857a146
268 lines
12 KiB
C++
268 lines
12 KiB
C++
/*
|
|
* 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 <algorithm>
|
|
|
|
#define LOG_TAG "AHAL_StreamBluetooth"
|
|
#include <Utils.h>
|
|
#include <android-base/logging.h>
|
|
#include <audio_utils/clock.h>
|
|
|
|
#include "core-impl/StreamBluetooth.h"
|
|
|
|
using aidl::android::hardware::audio::common::SinkMetadata;
|
|
using aidl::android::hardware::audio::common::SourceMetadata;
|
|
using aidl::android::hardware::audio::core::VendorParameter;
|
|
using aidl::android::hardware::bluetooth::audio::ChannelMode;
|
|
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;
|
|
using aidl::android::media::audio::common::AudioFormatType;
|
|
using aidl::android::media::audio::common::AudioOffloadInfo;
|
|
using aidl::android::media::audio::common::MicrophoneDynamicInfo;
|
|
using aidl::android::media::audio::common::MicrophoneInfo;
|
|
using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
|
|
using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
|
|
using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
|
|
using android::bluetooth::audio::aidl::BluetoothStreamState;
|
|
|
|
namespace aidl::android::hardware::audio::core {
|
|
|
|
constexpr int kBluetoothDefaultInputBufferMs = 20;
|
|
constexpr int kBluetoothDefaultOutputBufferMs = 10;
|
|
// constexpr int kBluetoothSpatializerOutputBufferMs = 10;
|
|
constexpr int kBluetoothDefaultRemoteDelayMs = 200;
|
|
|
|
StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
|
|
ModuleBluetooth::BtProfileHandles&& btHandles,
|
|
const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
|
|
const PcmConfiguration& pcmConfig)
|
|
: StreamCommonImpl(context, metadata),
|
|
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(pcmConfig.dataIntervalUs != 0
|
|
? pcmConfig.dataIntervalUs
|
|
: (mIsInput ? kBluetoothDefaultInputBufferMs
|
|
: kBluetoothDefaultOutputBufferMs) *
|
|
1000),
|
|
mBtDeviceProxy(btDeviceProxy) {}
|
|
|
|
::android::status_t StreamBluetooth::init() {
|
|
std::lock_guard guard(mLock);
|
|
if (mBtDeviceProxy == nullptr) {
|
|
// This is a normal situation in VTS tests.
|
|
LOG(INFO) << __func__ << ": no BT HAL proxy, stream is non-functional";
|
|
}
|
|
LOG(INFO) << __func__ << ": preferred data interval (us): " << mPreferredDataIntervalUs;
|
|
return ::android::OK;
|
|
}
|
|
|
|
::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
|
|
usleep(1000);
|
|
return ::android::OK;
|
|
}
|
|
|
|
::android::status_t StreamBluetooth::flush() {
|
|
usleep(1000);
|
|
return ::android::OK;
|
|
}
|
|
|
|
::android::status_t StreamBluetooth::pause() {
|
|
return standby();
|
|
}
|
|
|
|
::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
|
|
size_t* actualFrameCount, int32_t* latencyMs) {
|
|
std::lock_guard guard(mLock);
|
|
if (mBtDeviceProxy == nullptr || mBtDeviceProxy->getState() == BluetoothStreamState::DISABLED) {
|
|
*actualFrameCount = 0;
|
|
*latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
|
|
return ::android::OK;
|
|
}
|
|
*actualFrameCount = 0;
|
|
*latencyMs = 0;
|
|
if (!mBtDeviceProxy->start()) {
|
|
LOG(ERROR) << __func__ << ": state= " << mBtDeviceProxy->getState() << " failed to start";
|
|
return -EIO;
|
|
}
|
|
const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
|
|
const size_t bytesTransferred = mIsInput ? mBtDeviceProxy->readData(buffer, bytesToTransfer)
|
|
: mBtDeviceProxy->writeData(buffer, bytesToTransfer);
|
|
*actualFrameCount = bytesTransferred / 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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
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 (config.format.type != AudioFormatType::PCM) {
|
|
LOG(ERROR) << __func__
|
|
<< ": unexpected stream format type: " << toString(config.format.type);
|
|
return false;
|
|
}
|
|
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;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
|
|
std::lock_guard guard(mLock);
|
|
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 (mBtDeviceProxy != nullptr) mBtDeviceProxy->suspend();
|
|
return ::android::OK;
|
|
}
|
|
|
|
::android::status_t StreamBluetooth::start() {
|
|
std::lock_guard guard(mLock);
|
|
if (mBtDeviceProxy != nullptr) mBtDeviceProxy->start();
|
|
return ::android::OK;
|
|
}
|
|
|
|
void StreamBluetooth::shutdown() {
|
|
std::lock_guard guard(mLock);
|
|
if (mBtDeviceProxy != nullptr) {
|
|
mBtDeviceProxy->stop();
|
|
mBtDeviceProxy = nullptr;
|
|
}
|
|
}
|
|
|
|
ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
|
|
std::lock_guard guard(mLock);
|
|
if (mBtDeviceProxy == nullptr) {
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
bool isOk = true;
|
|
if (isInput(metadata)) {
|
|
isOk = mBtDeviceProxy->updateSinkMetadata(std::get<SinkMetadata>(metadata));
|
|
} else {
|
|
isOk = mBtDeviceProxy->updateSourceMetadata(std::get<SourceMetadata>(metadata));
|
|
}
|
|
return isOk ? ndk::ScopedAStatus::ok()
|
|
: ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
|
}
|
|
|
|
ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
|
|
if (mIsInput) {
|
|
return ndk::ScopedAStatus::ok();
|
|
}
|
|
auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
|
|
bool isEnabled) -> bool {
|
|
if (!isEnabled) {
|
|
if (proxy->suspend()) return proxy->setState(BluetoothStreamState::DISABLED);
|
|
return false;
|
|
}
|
|
return proxy->standby();
|
|
};
|
|
bool hasA2dpParam, enableA2dp;
|
|
auto btA2dp = mBluetoothA2dp.lock();
|
|
hasA2dpParam = btA2dp != nullptr && btA2dp->isEnabled(&enableA2dp).isOk();
|
|
bool hasLeParam, enableLe;
|
|
auto btLe = mBluetoothLe.lock();
|
|
hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
|
|
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);
|
|
}
|
|
}
|
|
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,
|
|
const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
|
|
const PcmConfiguration& pcmConfig)
|
|
: StreamIn(std::move(context), microphones),
|
|
StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles), btDeviceProxy,
|
|
pcmConfig) {}
|
|
|
|
ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
|
|
std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
|
|
LOG(DEBUG) << __func__ << ": not supported";
|
|
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,
|
|
const std::shared_ptr<BluetoothAudioPortAidl>& btDeviceProxy,
|
|
const PcmConfiguration& pcmConfig)
|
|
: StreamOut(std::move(context), offloadInfo),
|
|
StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles), btDeviceProxy,
|
|
pcmConfig) {}
|
|
|
|
} // namespace aidl::android::hardware::audio::core
|