mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Merge changes Ic51d603d,Ia50def0d,I22f65b8b,I8ce9f230,Id8455eb1, ... into main am: 3143e6930b am: 1afd920ac6
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2811595 Change-Id: Iacdb9a69a3f63f0b6d157d9f4b34146b50969fba Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -174,4 +174,12 @@ constexpr U makeBitPositionFlagMask(std::initializer_list<E> flags) {
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr int32_t frameCountFromDurationUs(long durationUs, int32_t sampleRateHz) {
|
||||
return (durationUs * sampleRateHz) / 1000000LL;
|
||||
}
|
||||
|
||||
constexpr int32_t frameCountFromDurationMs(int32_t durationMs, int32_t sampleRateHz) {
|
||||
return frameCountFromDurationUs(durationMs * 1000, sampleRateHz);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::common
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <set>
|
||||
|
||||
#define LOG_TAG "AHAL_Module"
|
||||
#include <Utils.h>
|
||||
#include <aidl/android/media/audio/common/AudioInputFlags.h>
|
||||
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
|
||||
#include <android-base/logging.h>
|
||||
@@ -35,6 +34,7 @@
|
||||
#include "core-impl/SoundDose.h"
|
||||
#include "core-impl/utils.h"
|
||||
|
||||
using aidl::android::hardware::audio::common::frameCountFromDurationMs;
|
||||
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
|
||||
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
|
||||
using aidl::android::hardware::audio::common::isValidAudioMode;
|
||||
@@ -202,15 +202,17 @@ ndk::ScopedAStatus Module::createStreamContext(
|
||||
LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
if (in_bufferSizeFrames < kMinimumStreamBufferSizeFrames) {
|
||||
LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
|
||||
<< ", must be at least " << kMinimumStreamBufferSizeFrames;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
auto& configs = getConfig().portConfigs;
|
||||
auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
|
||||
// Since this is a private method, it is assumed that
|
||||
// validity of the portConfigId has already been checked.
|
||||
const int32_t minimumStreamBufferSizeFrames = calculateBufferSizeFrames(
|
||||
getNominalLatencyMs(*portConfigIt), portConfigIt->sampleRate.value().value);
|
||||
if (in_bufferSizeFrames < minimumStreamBufferSizeFrames) {
|
||||
LOG(ERROR) << __func__ << ": insufficient buffer size " << in_bufferSizeFrames
|
||||
<< ", must be at least " << minimumStreamBufferSizeFrames;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
const size_t frameSize =
|
||||
getFrameSizeInBytes(portConfigIt->format.value(), portConfigIt->channelMask.value());
|
||||
if (frameSize == 0) {
|
||||
@@ -238,8 +240,8 @@ ndk::ScopedAStatus Module::createStreamContext(
|
||||
StreamContext temp(
|
||||
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
|
||||
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
|
||||
portConfigIt->portId, portConfigIt->format.value(),
|
||||
portConfigIt->channelMask.value(), portConfigIt->sampleRate.value().value, flags,
|
||||
portConfigIt->format.value(), portConfigIt->channelMask.value(),
|
||||
portConfigIt->sampleRate.value().value, flags, getNominalLatencyMs(*portConfigIt),
|
||||
portConfigIt->ext.get<AudioPortExt::mix>().handle,
|
||||
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
|
||||
asyncCallback, outEventCallback,
|
||||
@@ -359,6 +361,12 @@ std::unique_ptr<Module::Configuration> Module::initializeConfig() {
|
||||
return internal::getConfiguration(getType());
|
||||
}
|
||||
|
||||
int32_t Module::getNominalLatencyMs(const AudioPortConfig&) {
|
||||
// Arbitrary value. Implementations must override this method to provide their actual latency.
|
||||
static constexpr int32_t kLatencyMs = 5;
|
||||
return kLatencyMs;
|
||||
}
|
||||
|
||||
std::vector<AudioRoute*> Module::getAudioRoutesForAudioPortImpl(int32_t portId) {
|
||||
std::vector<AudioRoute*> result;
|
||||
auto& routes = getConfig().routes;
|
||||
@@ -609,32 +617,30 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA
|
||||
|
||||
std::vector<AudioRoute*> routesToMixPorts = getAudioRoutesForAudioPortImpl(templateId);
|
||||
std::set<int32_t> routableMixPortIds = getRoutableAudioPortIds(templateId, &routesToMixPorts);
|
||||
if (hasDynamicProfilesOnly(connectedPort.profiles)) {
|
||||
if (!mDebug.simulateDeviceConnections) {
|
||||
RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
|
||||
} else {
|
||||
auto& connectedProfiles = getConfig().connectedProfiles;
|
||||
if (auto connectedProfilesIt = connectedProfiles.find(templateId);
|
||||
connectedProfilesIt != connectedProfiles.end()) {
|
||||
connectedPort.profiles = connectedProfilesIt->second;
|
||||
}
|
||||
if (!mDebug.simulateDeviceConnections) {
|
||||
// Even if the device port has static profiles, the HAL module might need to update
|
||||
// them, or abort the connection process.
|
||||
RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
|
||||
} else if (hasDynamicProfilesOnly(connectedPort.profiles)) {
|
||||
auto& connectedProfiles = getConfig().connectedProfiles;
|
||||
if (auto connectedProfilesIt = connectedProfiles.find(templateId);
|
||||
connectedProfilesIt != connectedProfiles.end()) {
|
||||
connectedPort.profiles = connectedProfilesIt->second;
|
||||
}
|
||||
if (hasDynamicProfilesOnly(connectedPort.profiles)) {
|
||||
// Possible case 2. Check if all routable mix ports have static profiles.
|
||||
if (auto dynamicMixPortIt = std::find_if(ports.begin(), ports.end(),
|
||||
[&routableMixPortIds](const auto& p) {
|
||||
return routableMixPortIds.count(p.id) >
|
||||
0 &&
|
||||
hasDynamicProfilesOnly(p.profiles);
|
||||
});
|
||||
dynamicMixPortIt != ports.end()) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": connected port only has dynamic profiles after connecting "
|
||||
<< "external device " << connectedPort.toString() << ", and there exist "
|
||||
<< "a routable mix port with dynamic profiles: "
|
||||
<< dynamicMixPortIt->toString();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
}
|
||||
if (hasDynamicProfilesOnly(connectedPort.profiles)) {
|
||||
// Possible case 2. Check if all routable mix ports have static profiles.
|
||||
if (auto dynamicMixPortIt = std::find_if(ports.begin(), ports.end(),
|
||||
[&routableMixPortIds](const auto& p) {
|
||||
return routableMixPortIds.count(p.id) > 0 &&
|
||||
hasDynamicProfilesOnly(p.profiles);
|
||||
});
|
||||
dynamicMixPortIt != ports.end()) {
|
||||
LOG(ERROR) << __func__ << ": connected port only has dynamic profiles after connecting "
|
||||
<< "external device " << connectedPort.toString() << ", and there exist "
|
||||
<< "a routable mix port with dynamic profiles: "
|
||||
<< dynamicMixPortIt->toString();
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,11 +971,21 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
}
|
||||
// Find the highest sample rate among mix port configs.
|
||||
std::map<int32_t, AudioPortConfig*> sampleRates;
|
||||
std::vector<AudioPortConfig*>& mixPortConfigs =
|
||||
sources[0]->ext.getTag() == AudioPortExt::mix ? sources : sinks;
|
||||
for (auto mix : mixPortConfigs) {
|
||||
sampleRates.emplace(mix->sampleRate.value().value, mix);
|
||||
}
|
||||
*_aidl_return = in_requested;
|
||||
_aidl_return->minimumStreamBufferSizeFrames = kMinimumStreamBufferSizeFrames;
|
||||
auto maxSampleRateIt = std::max_element(sampleRates.begin(), sampleRates.end());
|
||||
const int32_t latencyMs = getNominalLatencyMs(*(maxSampleRateIt->second));
|
||||
_aidl_return->minimumStreamBufferSizeFrames =
|
||||
calculateBufferSizeFrames(latencyMs, maxSampleRateIt->first);
|
||||
_aidl_return->latenciesMs.clear();
|
||||
_aidl_return->latenciesMs.insert(_aidl_return->latenciesMs.end(),
|
||||
_aidl_return->sinkPortConfigIds.size(), kLatencyMs);
|
||||
_aidl_return->sinkPortConfigIds.size(), latencyMs);
|
||||
AudioPatch oldPatch{};
|
||||
if (existing == patches.end()) {
|
||||
_aidl_return->id = getConfig().nextPatchId++;
|
||||
@@ -1211,7 +1227,7 @@ ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
|
||||
// Reset master mute if it failed.
|
||||
onMasterMuteChanged(mMasterMute);
|
||||
}
|
||||
return std::move(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
|
||||
@@ -1233,7 +1249,7 @@ ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
|
||||
<< "), error=" << result;
|
||||
onMasterVolumeChanged(mMasterVolume);
|
||||
}
|
||||
return std::move(result);
|
||||
return result;
|
||||
}
|
||||
LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
@@ -1554,11 +1570,6 @@ std::vector<MicrophoneInfo> Module::getMicrophoneInfos() {
|
||||
return result;
|
||||
}
|
||||
|
||||
Module::BtProfileHandles Module::getBtProfileManagerHandles() {
|
||||
return std::make_tuple(std::weak_ptr<IBluetooth>(), std::weak_ptr<IBluetoothA2dp>(),
|
||||
std::weak_ptr<IBluetoothLe>());
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Module::bluetoothParametersUpdated() {
|
||||
return mStreams.bluetoothParametersUpdated();
|
||||
}
|
||||
|
||||
@@ -58,4 +58,12 @@ ndk::ScopedAStatus ModulePrimary::createOutputStream(
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
int32_t ModulePrimary::getNominalLatencyMs(const AudioPortConfig&) {
|
||||
// 85 ms is chosen considering 4096 frames @ 48 kHz. This is the value which allows
|
||||
// the virtual Android device implementation to pass CTS. Hardware implementations
|
||||
// should have significantly lower latency.
|
||||
static constexpr int32_t kLatencyMs = 85;
|
||||
return kLatencyMs;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
||||
@@ -138,7 +138,7 @@ void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
|
||||
reply->status = STATUS_OK;
|
||||
if (isConnected) {
|
||||
reply->observable.frames = mContext->getFrameCount();
|
||||
reply->observable.timeNs = ::android::elapsedRealtimeNano();
|
||||
reply->observable.timeNs = ::android::uptimeNanos();
|
||||
if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
|
||||
return;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply
|
||||
const size_t frameSize = mContext->getFrameSize();
|
||||
size_t actualFrameCount = 0;
|
||||
bool fatal = false;
|
||||
int32_t latency = Module::kLatencyMs;
|
||||
int32_t latency = mContext->getNominalLatencyMs();
|
||||
if (isConnected) {
|
||||
if (::android::status_t status = mDriver->transfer(mDataBuffer.get(), byteCount / frameSize,
|
||||
&actualFrameCount, &latency);
|
||||
@@ -581,7 +581,7 @@ bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* rep
|
||||
const size_t readByteCount = dataMQ->availableToRead();
|
||||
const size_t frameSize = mContext->getFrameSize();
|
||||
bool fatal = false;
|
||||
int32_t latency = Module::kLatencyMs;
|
||||
int32_t latency = mContext->getNominalLatencyMs();
|
||||
if (bool success = readByteCount > 0 ? dataMQ->read(&mDataBuffer[0], readByteCount) : true) {
|
||||
const bool isConnected = mIsConnected;
|
||||
LOG(VERBOSE) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
|
||||
@@ -848,7 +848,7 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
|
||||
}
|
||||
|
||||
StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context)
|
||||
: mChannelCount(getChannelCount(context->getChannelLayout())) {}
|
||||
: mChannelCount(getChannelCount(context->getChannelLayout())), mHwGains(mChannelCount, 0.0f) {}
|
||||
|
||||
ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector<float>* _aidl_return) {
|
||||
*_aidl_return = mHwGains;
|
||||
@@ -979,7 +979,8 @@ ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int3
|
||||
}
|
||||
|
||||
StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context)
|
||||
: mChannelCount(getChannelCount(context->getChannelLayout())) {}
|
||||
: mChannelCount(getChannelCount(context->getChannelLayout())),
|
||||
mHwVolumes(mChannelCount, 0.0f) {}
|
||||
|
||||
ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector<float>* _aidl_return) {
|
||||
*_aidl_return = mHwVolumes;
|
||||
|
||||
@@ -20,9 +20,24 @@
|
||||
#define LOG_TAG "AHAL_AlsaMixer"
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_status.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#include "Mixer.h"
|
||||
|
||||
namespace ndk {
|
||||
|
||||
// This enables use of 'error/expected_utils' for ScopedAStatus.
|
||||
|
||||
inline bool errorIsOk(const ScopedAStatus& s) {
|
||||
return s.isOk();
|
||||
}
|
||||
|
||||
inline std::string errorToString(const ScopedAStatus& s) {
|
||||
return s.getDescription();
|
||||
}
|
||||
|
||||
} // namespace ndk
|
||||
|
||||
namespace aidl::android::hardware::audio::core::alsa {
|
||||
|
||||
// static
|
||||
@@ -93,6 +108,36 @@ Mixer::~Mixer() {
|
||||
}
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::getMasterMute(bool* muted) {
|
||||
return getMixerControlMute(MASTER_SWITCH, muted);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::getMasterVolume(float* volume) {
|
||||
return getMixerControlVolume(MASTER_VOLUME, volume);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::getMicGain(float* gain) {
|
||||
return getMixerControlVolume(MIC_GAIN, gain);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::getMicMute(bool* muted) {
|
||||
return getMixerControlMute(MIC_SWITCH, muted);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::getVolumes(std::vector<float>* volumes) {
|
||||
struct mixer_ctl* mctl;
|
||||
RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
|
||||
std::vector<int> percents;
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to get volume, err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
std::transform(percents.begin(), percents.end(), std::back_inserter(*volumes),
|
||||
[](int percent) -> float { return std::clamp(percent / 100.0f, 0.0f, 1.0f); });
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
|
||||
return setMixerControlMute(MASTER_SWITCH, muted);
|
||||
}
|
||||
@@ -110,35 +155,70 @@ ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
|
||||
if (!isValid()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
auto it = mMixerControls.find(Mixer::HW_VOLUME);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
struct mixer_ctl* mctl;
|
||||
RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
|
||||
std::vector<int> percents;
|
||||
std::transform(
|
||||
volumes.begin(), volumes.end(), std::back_inserter(percents),
|
||||
[](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = setMixerControlPercent(it->second, percents); err != 0) {
|
||||
if (int err = setMixerControlPercent(mctl, percents); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
|
||||
ndk::ScopedAStatus Mixer::findControl(Control ctl, struct mixer_ctl** result) {
|
||||
if (!isValid()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
auto it = mMixerControls.find(ctl);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
if (auto it = mMixerControls.find(ctl); it != mMixerControls.end()) {
|
||||
*result = it->second;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::getMixerControlMute(Control ctl, bool* muted) {
|
||||
struct mixer_ctl* mctl;
|
||||
RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
|
||||
std::vector<int> mutedValues;
|
||||
if (int err = getMixerControlValues(mctl, &mutedValues); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (mutedValues.empty()) {
|
||||
LOG(ERROR) << __func__ << ": got no values for " << ctl;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
*muted = mutedValues[0] != 0;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::getMixerControlVolume(Control ctl, float* volume) {
|
||||
struct mixer_ctl* mctl;
|
||||
RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
|
||||
std::lock_guard l(mMixerAccess);
|
||||
std::vector<int> percents;
|
||||
if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
if (percents.empty()) {
|
||||
LOG(ERROR) << __func__ << ": got no values for " << ctl;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
*volume = std::clamp(percents[0] / 100.0f, 0.0f, 1.0f);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMixerControlMute(Control ctl, bool muted) {
|
||||
struct mixer_ctl* mctl;
|
||||
RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = setMixerControlValue(mctl, muted ? 0 : 1); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
@@ -146,54 +226,72 @@ ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
|
||||
if (!isValid()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
auto it = mMixerControls.find(ctl);
|
||||
if (it == mMixerControls.end()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
struct mixer_ctl* mctl;
|
||||
RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
|
||||
volume = std::clamp(volume, 0.0f, 1.0f);
|
||||
std::lock_guard l(mMixerAccess);
|
||||
if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
|
||||
if (int err = setMixerControlPercent(mctl, std::floor(volume * 100)); err != 0) {
|
||||
LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
int Mixer::getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents) {
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
percents->resize(n);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int valueOrError = mixer_ctl_get_percent(ctl, id); valueOrError >= 0) {
|
||||
(*percents)[id] = valueOrError;
|
||||
} else {
|
||||
return valueOrError;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mixer::getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values) {
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
values->resize(n);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int valueOrError = mixer_ctl_get_value(ctl, id); valueOrError >= 0) {
|
||||
(*values)[id] = valueOrError;
|
||||
} else {
|
||||
return valueOrError;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
|
||||
int ret = 0;
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
|
||||
ret = error;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
|
||||
int ret = 0;
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
|
||||
error != 0) {
|
||||
ret = error;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
|
||||
int ret = 0;
|
||||
const unsigned int n = mixer_ctl_get_num_values(ctl);
|
||||
for (unsigned int id = 0; id < n; id++) {
|
||||
if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
|
||||
ret = error;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core::alsa
|
||||
|
||||
@@ -39,6 +39,11 @@ class Mixer {
|
||||
|
||||
bool isValid() const { return mMixer != nullptr; }
|
||||
|
||||
ndk::ScopedAStatus getMasterMute(bool* muted);
|
||||
ndk::ScopedAStatus getMasterVolume(float* volume);
|
||||
ndk::ScopedAStatus getMicGain(float* gain);
|
||||
ndk::ScopedAStatus getMicMute(bool* muted);
|
||||
ndk::ScopedAStatus getVolumes(std::vector<float>* volumes);
|
||||
ndk::ScopedAStatus setMasterMute(bool muted);
|
||||
ndk::ScopedAStatus setMasterVolume(float volume);
|
||||
ndk::ScopedAStatus setMicGain(float gain);
|
||||
@@ -60,9 +65,16 @@ class Mixer {
|
||||
static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
|
||||
static Controls initializeMixerControls(struct mixer* mixer);
|
||||
|
||||
ndk::ScopedAStatus findControl(Control ctl, struct mixer_ctl** result);
|
||||
ndk::ScopedAStatus getMixerControlMute(Control ctl, bool* muted);
|
||||
ndk::ScopedAStatus getMixerControlVolume(Control ctl, float* volume);
|
||||
ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
|
||||
ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);
|
||||
|
||||
int getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents)
|
||||
REQUIRES(mMixerAccess);
|
||||
int getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values)
|
||||
REQUIRES(mMixerAccess);
|
||||
int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
|
||||
int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
|
||||
REQUIRES(mMixerAccess);
|
||||
|
||||
@@ -119,7 +119,7 @@ StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int rea
|
||||
|
||||
::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) {
|
||||
if (mAlsaDeviceProxies.empty()) {
|
||||
LOG(FATAL) << __func__ << ": no opened devices";
|
||||
LOG(WARNING) << __func__ << ": no opened devices";
|
||||
return ::android::NO_INIT;
|
||||
}
|
||||
// Since the proxy can only count transferred frames since its creation,
|
||||
|
||||
@@ -19,11 +19,25 @@
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <audio_utils/primitives.h>
|
||||
#include <inttypes.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include "BluetoothAudioSessionControl.h"
|
||||
#include "core-impl/DevicePortProxy.h"
|
||||
|
||||
using aidl::android::hardware::audio::common::SinkMetadata;
|
||||
using aidl::android::hardware::audio::common::SourceMetadata;
|
||||
using aidl::android::hardware::bluetooth::audio::AudioConfiguration;
|
||||
using aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
|
||||
using aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
|
||||
using aidl::android::hardware::bluetooth::audio::ChannelMode;
|
||||
using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
|
||||
using aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
|
||||
using aidl::android::hardware::bluetooth::audio::PresentationPosition;
|
||||
using aidl::android::hardware::bluetooth::audio::SessionType;
|
||||
using aidl::android::media::audio::common::AudioDeviceDescription;
|
||||
using aidl::android::media::audio::common::AudioDeviceType;
|
||||
using android::base::StringPrintf;
|
||||
|
||||
namespace android::bluetooth::audio::aidl {
|
||||
|
||||
namespace {
|
||||
@@ -33,20 +47,6 @@ constexpr unsigned int kMaxWaitingTimeMs = 4500;
|
||||
|
||||
} // namespace
|
||||
|
||||
using ::aidl::android::hardware::audio::common::SinkMetadata;
|
||||
using ::aidl::android::hardware::audio::common::SourceMetadata;
|
||||
using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration;
|
||||
using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
|
||||
using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
|
||||
using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
|
||||
using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
|
||||
using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
|
||||
using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
|
||||
using ::aidl::android::hardware::bluetooth::audio::SessionType;
|
||||
using ::aidl::android::media::audio::common::AudioDeviceDescription;
|
||||
using ::aidl::android::media::audio::common::AudioDeviceType;
|
||||
using ::android::base::StringPrintf;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) {
|
||||
switch (state) {
|
||||
case BluetoothStreamState::DISABLED:
|
||||
|
||||
@@ -18,50 +18,56 @@
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "BluetoothAudioSessionControl.h"
|
||||
#include "BluetoothAudioSession.h"
|
||||
#include "core-impl/ModuleBluetooth.h"
|
||||
#include "core-impl/StreamBluetooth.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
using aidl::android::hardware::audio::common::SinkMetadata;
|
||||
using aidl::android::hardware::audio::common::SourceMetadata;
|
||||
using aidl::android::media::audio::common::AudioDeviceDescription;
|
||||
using aidl::android::media::audio::common::AudioDeviceType;
|
||||
using aidl::android::media::audio::common::AudioOffloadInfo;
|
||||
using aidl::android::media::audio::common::AudioPort;
|
||||
using aidl::android::media::audio::common::AudioPortExt;
|
||||
using aidl::android::media::audio::common::MicrophoneInfo;
|
||||
using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
|
||||
using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
|
||||
|
||||
using ::aidl::android::hardware::audio::common::SinkMetadata;
|
||||
using ::aidl::android::hardware::audio::common::SourceMetadata;
|
||||
using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession;
|
||||
using ::aidl::android::media::audio::common::AudioDeviceDescription;
|
||||
using ::aidl::android::media::audio::common::AudioDeviceType;
|
||||
using ::aidl::android::media::audio::common::AudioOffloadInfo;
|
||||
using ::aidl::android::media::audio::common::AudioPort;
|
||||
using ::aidl::android::media::audio::common::AudioPortExt;
|
||||
using ::aidl::android::media::audio::common::MicrophoneInfo;
|
||||
using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
|
||||
using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp(
|
||||
std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
|
||||
if (!mBluetoothA2dp) {
|
||||
auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
|
||||
handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
|
||||
mBluetoothA2dp = handle;
|
||||
}
|
||||
*_aidl_return = mBluetoothA2dp.getInstance();
|
||||
*_aidl_return = getBtA2dp().getInstance();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleBluetooth::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
|
||||
*_aidl_return = getBtLe().getInstance();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ChildInterface<BluetoothA2dp>& ModuleBluetooth::getBtA2dp() {
|
||||
if (!mBluetoothA2dp) {
|
||||
auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
|
||||
handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
|
||||
mBluetoothA2dp = handle;
|
||||
}
|
||||
return mBluetoothA2dp;
|
||||
}
|
||||
|
||||
ChildInterface<BluetoothLe>& ModuleBluetooth::getBtLe() {
|
||||
if (!mBluetoothLe) {
|
||||
auto handle = ndk::SharedRefBase::make<BluetoothLe>();
|
||||
handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
|
||||
mBluetoothLe = handle;
|
||||
}
|
||||
*_aidl_return = mBluetoothLe.getInstance();
|
||||
LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
return mBluetoothLe;
|
||||
}
|
||||
|
||||
Module::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
|
||||
return std::make_tuple(std::weak_ptr<IBluetooth>(), mBluetoothA2dp.getInstance(),
|
||||
mBluetoothLe.getInstance());
|
||||
ModuleBluetooth::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
|
||||
return std::make_tuple(std::weak_ptr<IBluetooth>(), getBtA2dp().getPtr(), getBtLe().getPtr());
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleBluetooth::getMicMute(bool* _aidl_return __unused) {
|
||||
@@ -101,30 +107,35 @@ ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audio
|
||||
if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP) {
|
||||
bool isA2dpEnabled = false;
|
||||
if (!!mBluetoothA2dp) {
|
||||
RETURN_STATUS_IF_ERROR(mBluetoothA2dp.getInstance()->isEnabled(&isA2dpEnabled));
|
||||
RETURN_STATUS_IF_ERROR((*mBluetoothA2dp).isEnabled(&isA2dpEnabled));
|
||||
}
|
||||
LOG(DEBUG) << __func__ << ": isA2dpEnabled: " << isA2dpEnabled;
|
||||
return isA2dpEnabled ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
} else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE) {
|
||||
bool isLeEnabled = false;
|
||||
if (!!mBluetoothLe) {
|
||||
RETURN_STATUS_IF_ERROR(mBluetoothLe.getInstance()->isEnabled(&isLeEnabled));
|
||||
RETURN_STATUS_IF_ERROR((*mBluetoothLe).isEnabled(&isLeEnabled));
|
||||
}
|
||||
LOG(DEBUG) << __func__ << ": isLeEnabled: " << isLeEnabled;
|
||||
return isLeEnabled ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
} else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
|
||||
description.type == AudioDeviceType::OUT_HEARING_AID) {
|
||||
// Hearing aids can use a number of profiles, thus the only way to check
|
||||
// connectivity is to try to talk to the BT HAL.
|
||||
if (!BluetoothAudioSession::IsAidlAvailable()) {
|
||||
if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::
|
||||
IsAidlAvailable()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
std::shared_ptr<BluetoothAudioPortAidl> proxy = std::shared_ptr<BluetoothAudioPortAidl>(
|
||||
std::make_shared<BluetoothAudioPortAidlOut>());
|
||||
if (proxy->registerPort(description)) {
|
||||
LOG(DEBUG) << __func__ << ": registered hearing aid port";
|
||||
proxy->unregisterPort();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
LOG(DEBUG) << __func__ << ": failed to register hearing aid port";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
|
||||
|
||||
@@ -20,52 +20,49 @@
|
||||
#include <android-base/logging.h>
|
||||
#include <audio_utils/clock.h>
|
||||
|
||||
#include "BluetoothAudioSessionControl.h"
|
||||
#include "BluetoothAudioSession.h"
|
||||
#include "core-impl/StreamBluetooth.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
using aidl::android::hardware::audio::common::frameCountFromDurationUs;
|
||||
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::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;
|
||||
|
||||
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::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;
|
||||
|
||||
size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) {
|
||||
return (durationUs * sampleRate) / 1000000;
|
||||
}
|
||||
|
||||
// pcm configuration params are not really used by the module
|
||||
StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
|
||||
Module::BtProfileHandles&& btHandles)
|
||||
ModuleBluetooth::BtProfileHandles&& btHandles)
|
||||
: StreamCommonImpl(context, metadata),
|
||||
mSampleRate(getContext().getSampleRate()),
|
||||
mChannelLayout(getContext().getChannelLayout()),
|
||||
mFormat(getContext().getFormat()),
|
||||
mFrameSizeBytes(getContext().getFrameSize()),
|
||||
mIsInput(isInput(metadata)),
|
||||
mBluetoothA2dp(std::move(std::get<Module::BtInterface::BTA2DP>(btHandles))),
|
||||
mBluetoothLe(std::move(std::get<Module::BtInterface::BTLE>(btHandles))) {
|
||||
mBluetoothA2dp(std::move(std::get<ModuleBluetooth::BtInterface::BTA2DP>(btHandles))),
|
||||
mBluetoothLe(std::move(std::get<ModuleBluetooth::BtInterface::BTLE>(btHandles))) {
|
||||
mPreferredDataIntervalUs =
|
||||
mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
|
||||
mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
|
||||
(mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs) * 1000;
|
||||
mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
|
||||
mIsInitialized = false;
|
||||
mIsReadyToClose = false;
|
||||
}
|
||||
@@ -226,7 +223,7 @@ bool StreamBluetooth::checkConfigParams(
|
||||
if (config.dataIntervalUs > 0) {
|
||||
mPreferredDataIntervalUs =
|
||||
std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
|
||||
mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
|
||||
mPreferredFrameCount = frameCountFromDurationUs(mPreferredDataIntervalUs, mSampleRate);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -318,7 +315,7 @@ ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
|
||||
|
||||
StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
Module::BtProfileHandles&& btProfileHandles)
|
||||
ModuleBluetooth::BtProfileHandles&& btProfileHandles)
|
||||
: StreamIn(std::move(context), microphones),
|
||||
StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
|
||||
|
||||
@@ -331,7 +328,7 @@ ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
|
||||
StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
|
||||
const SourceMetadata& sourceMetadata,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
Module::BtProfileHandles&& btProfileHandles)
|
||||
ModuleBluetooth::BtProfileHandles&& btProfileHandles)
|
||||
: StreamOut(std::move(context), offloadInfo),
|
||||
StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ class Bluetooth : public BnBluetooth {
|
||||
class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler {
|
||||
public:
|
||||
BluetoothA2dp() = default;
|
||||
ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus setEnabled(bool in_enabled) override;
|
||||
ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus reconfigureOffload(
|
||||
@@ -61,9 +61,9 @@ class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler {
|
||||
class BluetoothLe : public BnBluetoothLe, public ParamChangeHandler {
|
||||
public:
|
||||
BluetoothLe() = default;
|
||||
ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus isEnabled(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus setEnabled(bool in_enabled) override;
|
||||
ndk::ScopedAStatus supportsOffloadReconfiguration(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus reconfigureOffload(
|
||||
|
||||
@@ -40,6 +40,7 @@ struct ChildInterface : private std::pair<std::shared_ptr<C>, ndk::SpAIBinder> {
|
||||
explicit operator bool() const { return !!this->first; }
|
||||
C& operator*() const { return *(this->first); }
|
||||
C* operator->() const { return this->first; }
|
||||
std::shared_ptr<C> getPtr() { return this->first; }
|
||||
// Use 'getInstance' when returning the interface instance.
|
||||
std::shared_ptr<C> getInstance() {
|
||||
(void)getBinder();
|
||||
|
||||
@@ -25,11 +25,10 @@
|
||||
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/PresentationPosition.h>
|
||||
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
|
||||
#include <aidl/android/media/audio/common/AudioDeviceDescription.h>
|
||||
|
||||
#include "BluetoothAudioSessionControl.h"
|
||||
|
||||
namespace android::bluetooth::audio::aidl {
|
||||
|
||||
enum class BluetoothStreamState : uint8_t {
|
||||
@@ -239,4 +238,4 @@ class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl {
|
||||
size_t readData(void* buffer, size_t bytes) const override;
|
||||
};
|
||||
|
||||
} // namespace android::bluetooth::audio::aidl
|
||||
} // namespace android::bluetooth::audio::aidl
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
#include <Utils.h>
|
||||
#include <aidl/android/hardware/audio/core/BnModule.h>
|
||||
|
||||
#include "core-impl/ChildInterface.h"
|
||||
@@ -45,13 +46,6 @@ class Module : public BnModule {
|
||||
int32_t nextPatchId = 1;
|
||||
};
|
||||
enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH };
|
||||
enum BtInterface : int { BTCONF, BTA2DP, BTLE };
|
||||
typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
|
||||
std::weak_ptr<IBluetoothLe>>
|
||||
BtProfileHandles;
|
||||
|
||||
// This value is used by default for all AudioPatches and reported by all streams.
|
||||
static constexpr int32_t kLatencyMs = 10;
|
||||
|
||||
static std::shared_ptr<Module> createInstance(Type type) {
|
||||
return createInstance(type, std::make_unique<Configuration>());
|
||||
@@ -145,8 +139,6 @@ class Module : public BnModule {
|
||||
ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
|
||||
|
||||
// This value is used for all AudioPatches.
|
||||
static constexpr int32_t kMinimumStreamBufferSizeFrames = 256;
|
||||
// The maximum stream buffer size is 1 GiB = 2 ** 30 bytes;
|
||||
static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30;
|
||||
|
||||
@@ -207,8 +199,19 @@ class Module : public BnModule {
|
||||
virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume);
|
||||
virtual std::vector<::aidl::android::media::audio::common::MicrophoneInfo> getMicrophoneInfos();
|
||||
virtual std::unique_ptr<Configuration> initializeConfig();
|
||||
virtual int32_t getNominalLatencyMs(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
|
||||
|
||||
// Utility and helper functions accessible to subclasses.
|
||||
static int32_t calculateBufferSizeFrames(int32_t latencyMs, int32_t sampleRateHz) {
|
||||
const int32_t rawSizeFrames =
|
||||
aidl::android::hardware::audio::common::frameCountFromDurationMs(latencyMs,
|
||||
sampleRateHz);
|
||||
int32_t powerOf2 = 1;
|
||||
while (powerOf2 < rawSizeFrames) powerOf2 <<= 1;
|
||||
return powerOf2;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus bluetoothParametersUpdated();
|
||||
void cleanUpPatch(int32_t patchId);
|
||||
ndk::ScopedAStatus createStreamContext(
|
||||
@@ -222,7 +225,6 @@ class Module : public BnModule {
|
||||
ndk::ScopedAStatus findPortIdForNewStream(
|
||||
int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
|
||||
std::vector<AudioRoute*> getAudioRoutesForAudioPortImpl(int32_t portId);
|
||||
virtual BtProfileHandles getBtProfileManagerHandles();
|
||||
Configuration& getConfig();
|
||||
const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
|
||||
bool getMasterMute() const { return mMasterMute; }
|
||||
|
||||
@@ -23,11 +23,18 @@ namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class ModuleBluetooth final : public Module {
|
||||
public:
|
||||
enum BtInterface : int { BTSCO, BTA2DP, BTLE };
|
||||
typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
|
||||
std::weak_ptr<IBluetoothLe>>
|
||||
BtProfileHandles;
|
||||
|
||||
ModuleBluetooth(std::unique_ptr<Configuration>&& config)
|
||||
: Module(Type::BLUETOOTH, std::move(config)) {}
|
||||
|
||||
private:
|
||||
BtProfileHandles getBtProfileManagerHandles() override;
|
||||
ChildInterface<BluetoothA2dp>& getBtA2dp();
|
||||
ChildInterface<BluetoothLe>& getBtLe();
|
||||
BtProfileHandles getBtProfileManagerHandles();
|
||||
|
||||
ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
|
||||
ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
|
||||
@@ -50,8 +57,8 @@ class ModuleBluetooth final : public Module {
|
||||
ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
|
||||
ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
|
||||
|
||||
ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
|
||||
ChildInterface<IBluetoothLe> mBluetoothLe;
|
||||
ChildInterface<BluetoothA2dp> mBluetoothA2dp;
|
||||
ChildInterface<BluetoothLe> mBluetoothLe;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
||||
@@ -39,6 +39,8 @@ class ModulePrimary final : public Module {
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) override;
|
||||
int32_t getNominalLatencyMs(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
|
||||
|
||||
private:
|
||||
ChildInterface<ITelephony> mTelephony;
|
||||
|
||||
@@ -50,6 +50,9 @@ class ModuleRemoteSubmix : public Module {
|
||||
override;
|
||||
ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
|
||||
ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
|
||||
int32_t getNominalLatencyMs(
|
||||
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;
|
||||
// TODO(b/307586684): Report proper minimum stream buffer size by overriding 'setAudioPatch'.
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
||||
@@ -81,11 +81,10 @@ class StreamContext {
|
||||
|
||||
StreamContext() = default;
|
||||
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
|
||||
int portId,
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
|
||||
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
|
||||
int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
|
||||
int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
|
||||
int32_t nominalLatencyMs, int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
|
||||
@@ -93,51 +92,17 @@ class StreamContext {
|
||||
: mCommandMQ(std::move(commandMQ)),
|
||||
mInternalCommandCookie(std::rand()),
|
||||
mReplyMQ(std::move(replyMQ)),
|
||||
mPortId(portId),
|
||||
mFormat(format),
|
||||
mChannelLayout(channelLayout),
|
||||
mSampleRate(sampleRate),
|
||||
mFlags(flags),
|
||||
mNominalLatencyMs(nominalLatencyMs),
|
||||
mMixPortHandle(mixPortHandle),
|
||||
mDataMQ(std::move(dataMQ)),
|
||||
mAsyncCallback(asyncCallback),
|
||||
mOutEventCallback(outEventCallback),
|
||||
mStreamDataProcessor(streamDataProcessor),
|
||||
mDebugParameters(debugParameters) {}
|
||||
StreamContext(StreamContext&& other)
|
||||
: mCommandMQ(std::move(other.mCommandMQ)),
|
||||
mInternalCommandCookie(other.mInternalCommandCookie),
|
||||
mReplyMQ(std::move(other.mReplyMQ)),
|
||||
mPortId(other.mPortId),
|
||||
mFormat(other.mFormat),
|
||||
mChannelLayout(other.mChannelLayout),
|
||||
mSampleRate(other.mSampleRate),
|
||||
mFlags(std::move(other.mFlags)),
|
||||
mMixPortHandle(other.mMixPortHandle),
|
||||
mDataMQ(std::move(other.mDataMQ)),
|
||||
mAsyncCallback(std::move(other.mAsyncCallback)),
|
||||
mOutEventCallback(std::move(other.mOutEventCallback)),
|
||||
mStreamDataProcessor(std::move(other.mStreamDataProcessor)),
|
||||
mDebugParameters(std::move(other.mDebugParameters)),
|
||||
mFrameCount(other.mFrameCount) {}
|
||||
StreamContext& operator=(StreamContext&& other) {
|
||||
mCommandMQ = std::move(other.mCommandMQ);
|
||||
mInternalCommandCookie = other.mInternalCommandCookie;
|
||||
mReplyMQ = std::move(other.mReplyMQ);
|
||||
mPortId = std::move(other.mPortId);
|
||||
mFormat = std::move(other.mFormat);
|
||||
mChannelLayout = std::move(other.mChannelLayout);
|
||||
mSampleRate = other.mSampleRate;
|
||||
mFlags = std::move(other.mFlags);
|
||||
mMixPortHandle = other.mMixPortHandle;
|
||||
mDataMQ = std::move(other.mDataMQ);
|
||||
mAsyncCallback = std::move(other.mAsyncCallback);
|
||||
mOutEventCallback = std::move(other.mOutEventCallback);
|
||||
mStreamDataProcessor = std::move(other.mStreamDataProcessor);
|
||||
mDebugParameters = std::move(other.mDebugParameters);
|
||||
mFrameCount = other.mFrameCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void fillDescriptor(StreamDescriptor* desc);
|
||||
std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
|
||||
@@ -156,6 +121,7 @@ class StreamContext {
|
||||
size_t getFrameSize() const;
|
||||
int getInternalCommandCookie() const { return mInternalCommandCookie; }
|
||||
int32_t getMixPortHandle() const { return mMixPortHandle; }
|
||||
int32_t getNominalLatencyMs() const { return mNominalLatencyMs; }
|
||||
std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
|
||||
return mOutEventCallback;
|
||||
}
|
||||
@@ -163,7 +129,6 @@ class StreamContext {
|
||||
return mStreamDataProcessor;
|
||||
}
|
||||
void startStreamDataProcessor();
|
||||
int getPortId() const { return mPortId; }
|
||||
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
|
||||
int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
|
||||
int getSampleRate() const { return mSampleRate; }
|
||||
@@ -176,14 +141,15 @@ class StreamContext {
|
||||
long getFrameCount() const { return mFrameCount; }
|
||||
|
||||
private:
|
||||
// Fields are non const to allow move assignment.
|
||||
std::unique_ptr<CommandMQ> mCommandMQ;
|
||||
int mInternalCommandCookie; // The value used to confirm that the command was posted internally
|
||||
std::unique_ptr<ReplyMQ> mReplyMQ;
|
||||
int mPortId;
|
||||
::aidl::android::media::audio::common::AudioFormatDescription mFormat;
|
||||
::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
|
||||
int mSampleRate;
|
||||
::aidl::android::media::audio::common::AudioIoFlags mFlags;
|
||||
int32_t mNominalLatencyMs;
|
||||
int32_t mMixPortHandle;
|
||||
std::unique_ptr<DataMQ> mDataMQ;
|
||||
std::shared_ptr<IStreamCallback> mAsyncCallback;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <aidl/android/hardware/audio/core/IBluetoothLe.h>
|
||||
|
||||
#include "core-impl/DevicePortProxy.h"
|
||||
#include "core-impl/Module.h"
|
||||
#include "core-impl/ModuleBluetooth.h"
|
||||
#include "core-impl/Stream.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
@@ -32,7 +32,7 @@ namespace aidl::android::hardware::audio::core {
|
||||
class StreamBluetooth : public StreamCommonImpl {
|
||||
public:
|
||||
StreamBluetooth(StreamContext* context, const Metadata& metadata,
|
||||
Module::BtProfileHandles&& btHandles);
|
||||
ModuleBluetooth::BtProfileHandles&& btHandles);
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init() override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode) override;
|
||||
@@ -80,7 +80,7 @@ class StreamInBluetooth final : public StreamIn, public StreamBluetooth {
|
||||
StreamContext&& context,
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
Module::BtProfileHandles&& btHandles);
|
||||
ModuleBluetooth::BtProfileHandles&& btHandles);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
@@ -97,7 +97,7 @@ class StreamOutBluetooth final : public StreamOut, public StreamBluetooth {
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
Module::BtProfileHandles&& btHandles);
|
||||
ModuleBluetooth::BtProfileHandles&& btHandles);
|
||||
|
||||
private:
|
||||
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
|
||||
|
||||
@@ -27,10 +27,13 @@ class StreamPrimary : public StreamAlsa {
|
||||
public:
|
||||
StreamPrimary(StreamContext* context, const Metadata& metadata);
|
||||
|
||||
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) override;
|
||||
|
||||
protected:
|
||||
std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
|
||||
|
||||
const bool mIsInput;
|
||||
const bool mIsAsynchronous;
|
||||
};
|
||||
|
||||
class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
|
||||
|
||||
@@ -46,7 +46,7 @@ class StreamRemoteSubmix : public StreamCommonImpl {
|
||||
ndk::ScopedAStatus prepareToClose() override;
|
||||
|
||||
private:
|
||||
size_t getPipeSizeInFrames();
|
||||
long getDelayInUsForFrameCount(size_t frameCount);
|
||||
size_t getStreamPipeSizeInFrames();
|
||||
::android::status_t outWrite(void* buffer, size_t frameCount, size_t* actualFrameCount);
|
||||
::android::status_t inRead(void* buffer, size_t frameCount, size_t* actualFrameCount);
|
||||
|
||||
@@ -14,11 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <chrono>
|
||||
|
||||
#define LOG_TAG "AHAL_StreamPrimary"
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <audio_utils/clock.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#include "PrimaryMixer.h"
|
||||
@@ -37,10 +38,34 @@ using android::base::GetBoolProperty;
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
|
||||
: StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {
|
||||
: StreamAlsa(context, metadata, 3 /*readWriteRetries*/),
|
||||
mIsAsynchronous(!!getContext().getAsyncCallback()) {
|
||||
context->startStreamDataProcessor();
|
||||
}
|
||||
|
||||
::android::status_t StreamPrimary::transfer(void* buffer, size_t frameCount,
|
||||
size_t* actualFrameCount, int32_t* latencyMs) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
if (auto status = StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs);
|
||||
status != ::android::OK) {
|
||||
return status;
|
||||
}
|
||||
// This is a workaround for the emulator implementation which has a host-side buffer
|
||||
// and this can result in reading faster than real time.
|
||||
if (mIsInput && !mIsAsynchronous) {
|
||||
auto recordDurationUs = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - start);
|
||||
const long projectedVsObservedOffsetUs =
|
||||
*actualFrameCount * MICROS_PER_SECOND / mContext.getSampleRate() -
|
||||
recordDurationUs.count();
|
||||
if (projectedVsObservedOffsetUs > 0) {
|
||||
LOG(VERBOSE) << __func__ << ": sleeping for " << projectedVsObservedOffsetUs << " us";
|
||||
usleep(projectedVsObservedOffsetUs);
|
||||
}
|
||||
}
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
|
||||
static const std::vector<alsa::DeviceProfile> kBuiltInSource{
|
||||
alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
|
||||
@@ -66,7 +91,8 @@ bool StreamInPrimary::useStubStream(const AudioDevice& device) {
|
||||
GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
|
||||
return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
|
||||
device.type.type == AudioDeviceType::IN_FM_TUNER ||
|
||||
device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
|
||||
device.type.connection == AudioDeviceDescription::CONNECTION_BUS ||
|
||||
(device.type.type == AudioDeviceType::IN_DEVICE && device.type.connection.empty());
|
||||
}
|
||||
|
||||
StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
|
||||
@@ -101,6 +127,11 @@ ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return)
|
||||
if (isStubStream()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
float gain;
|
||||
RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getMicGain(&gain));
|
||||
_aidl_return->resize(0);
|
||||
_aidl_return->resize(mChannelCount, gain);
|
||||
RETURN_STATUS_IF_ERROR(setHwGainImpl(*_aidl_return));
|
||||
return getHwGainImpl(_aidl_return);
|
||||
}
|
||||
|
||||
@@ -132,7 +163,8 @@ bool StreamOutPrimary::useStubStream(const AudioDevice& device) {
|
||||
static const bool kSimulateOutput =
|
||||
GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
|
||||
return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
|
||||
device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
|
||||
device.type.connection == AudioDeviceDescription::CONNECTION_BUS ||
|
||||
(device.type.type == AudioDeviceType::OUT_DEVICE && device.type.connection.empty());
|
||||
}
|
||||
|
||||
StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
|
||||
@@ -167,6 +199,9 @@ ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_retur
|
||||
if (isStubStream()) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(primary::PrimaryMixer::getInstance().getVolumes(_aidl_return));
|
||||
_aidl_return->resize(mChannelCount);
|
||||
RETURN_STATUS_IF_ERROR(setHwVolumeImpl(*_aidl_return));
|
||||
return getHwVolumeImpl(_aidl_return);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <android-base/logging.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#include "SubmixRoute.h"
|
||||
#include "core-impl/ModuleRemoteSubmix.h"
|
||||
#include "core-impl/StreamRemoteSubmix.h"
|
||||
|
||||
@@ -106,4 +107,12 @@ ndk::ScopedAStatus ModuleRemoteSubmix::onMasterVolumeChanged(float __unused) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
int32_t ModuleRemoteSubmix::getNominalLatencyMs(const AudioPortConfig&) {
|
||||
// See the note on kDefaultPipePeriodCount.
|
||||
static constexpr int32_t kMaxLatencyMs =
|
||||
(r_submix::kDefaultPipeSizeInFrames * 1000) / r_submix::kDefaultSampleRateHz;
|
||||
static constexpr int32_t kMinLatencyMs = kMaxLatencyMs / r_submix::kDefaultPipePeriodCount;
|
||||
return (kMaxLatencyMs + kMinLatencyMs) / 2;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#define LOG_TAG "AHAL_StreamRemoteSubmix"
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "core-impl/StreamRemoteSubmix.h"
|
||||
|
||||
using aidl::android::hardware::audio::common::SinkMetadata;
|
||||
@@ -158,27 +156,8 @@ void StreamRemoteSubmix::shutdown() {
|
||||
|
||||
::android::status_t StreamRemoteSubmix::transfer(void* buffer, size_t frameCount,
|
||||
size_t* actualFrameCount, int32_t* latencyMs) {
|
||||
*latencyMs = (getStreamPipeSizeInFrames() * MILLIS_PER_SECOND) / mStreamConfig.sampleRate;
|
||||
*latencyMs = getDelayInUsForFrameCount(getStreamPipeSizeInFrames()) / 1000;
|
||||
LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms";
|
||||
|
||||
sp<MonoPipe> sink = mCurrentRoute->getSink();
|
||||
if (sink != nullptr) {
|
||||
if (sink->isShutdown()) {
|
||||
sink.clear();
|
||||
LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the transfer.";
|
||||
// the pipe has already been shutdown, this buffer will be lost but we must simulate
|
||||
// timing so we don't drain the output faster than realtime
|
||||
const size_t delayUs = static_cast<size_t>(
|
||||
std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
|
||||
usleep(delayUs);
|
||||
|
||||
*actualFrameCount = frameCount;
|
||||
return ::android::OK;
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": transfer without a pipe!";
|
||||
return ::android::UNEXPECTED_NULL;
|
||||
}
|
||||
mCurrentRoute->exitStandby(mIsInput);
|
||||
return (mIsInput ? inRead(buffer, frameCount, actualFrameCount)
|
||||
: outWrite(buffer, frameCount, actualFrameCount));
|
||||
@@ -202,6 +181,10 @@ void StreamRemoteSubmix::shutdown() {
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
long StreamRemoteSubmix::getDelayInUsForFrameCount(size_t frameCount) {
|
||||
return frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate;
|
||||
}
|
||||
|
||||
// Calculate the maximum size of the pipe buffer in frames for the specified stream.
|
||||
size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
auto pipeConfig = mCurrentRoute->mPipeConfig;
|
||||
@@ -215,11 +198,11 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
if (sink != nullptr) {
|
||||
if (sink->isShutdown()) {
|
||||
sink.clear();
|
||||
LOG(VERBOSE) << __func__ << ": pipe shutdown, ignoring the write.";
|
||||
const auto delayUs = getDelayInUsForFrameCount(frameCount);
|
||||
LOG(DEBUG) << __func__ << ": pipe shutdown, ignoring the write, sleeping for "
|
||||
<< delayUs << " us";
|
||||
// the pipe has already been shutdown, this buffer will be lost but we must
|
||||
// simulate timing so we don't drain the output faster than realtime
|
||||
const size_t delayUs = static_cast<size_t>(
|
||||
std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
|
||||
usleep(delayUs);
|
||||
*actualFrameCount = frameCount;
|
||||
return ::android::OK;
|
||||
@@ -229,17 +212,18 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
return ::android::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
const size_t availableToWrite = sink->availableToWrite();
|
||||
const bool shouldBlockWrite = mCurrentRoute->shouldBlockWrite();
|
||||
size_t availableToWrite = sink->availableToWrite();
|
||||
// NOTE: sink has been checked above and sink and source life cycles are synchronized
|
||||
sp<MonoPipeReader> source = mCurrentRoute->getSource();
|
||||
// If the write to the sink should be blocked, flush enough frames from the pipe to make space
|
||||
// to write the most recent data.
|
||||
if (!mCurrentRoute->shouldBlockWrite() && availableToWrite < frameCount) {
|
||||
if (!shouldBlockWrite && availableToWrite < frameCount) {
|
||||
static uint8_t flushBuffer[64];
|
||||
const size_t flushBufferSizeFrames = sizeof(flushBuffer) / mStreamConfig.frameSize;
|
||||
size_t framesToFlushFromSource = frameCount - availableToWrite;
|
||||
LOG(VERBOSE) << __func__ << ": flushing " << framesToFlushFromSource
|
||||
<< " frames from the pipe to avoid blocking";
|
||||
LOG(DEBUG) << __func__ << ": flushing " << framesToFlushFromSource
|
||||
<< " frames from the pipe to avoid blocking";
|
||||
while (framesToFlushFromSource) {
|
||||
const size_t flushSize = std::min(framesToFlushFromSource, flushBufferSizeFrames);
|
||||
framesToFlushFromSource -= flushSize;
|
||||
@@ -247,7 +231,12 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
source->read(flushBuffer, flushSize);
|
||||
}
|
||||
}
|
||||
availableToWrite = sink->availableToWrite();
|
||||
|
||||
if (!shouldBlockWrite && frameCount > availableToWrite) {
|
||||
// Truncate the request to avoid blocking.
|
||||
frameCount = availableToWrite;
|
||||
}
|
||||
ssize_t writtenFrames = sink->write(buffer, frameCount);
|
||||
if (writtenFrames < 0) {
|
||||
if (writtenFrames == (ssize_t)::android::NEGOTIATE) {
|
||||
@@ -261,7 +250,6 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
writtenFrames = sink->write(buffer, frameCount);
|
||||
}
|
||||
}
|
||||
sink.clear();
|
||||
|
||||
if (writtenFrames < 0) {
|
||||
LOG(ERROR) << __func__ << ": failed writing to pipe with " << writtenFrames;
|
||||
@@ -286,8 +274,9 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
} else {
|
||||
LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
|
||||
}
|
||||
const size_t delayUs = static_cast<size_t>(
|
||||
std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
|
||||
const auto delayUs = getDelayInUsForFrameCount(frameCount);
|
||||
LOG(DEBUG) << __func__ << ": no source, ignoring the read, sleeping for " << delayUs
|
||||
<< " us";
|
||||
usleep(delayUs);
|
||||
memset(buffer, 0, mStreamConfig.frameSize * frameCount);
|
||||
*actualFrameCount = frameCount;
|
||||
@@ -296,7 +285,7 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
|
||||
// read the data from the pipe
|
||||
int attempts = 0;
|
||||
const size_t delayUs = static_cast<size_t>(std::roundf(kReadAttemptSleepUs));
|
||||
const long delayUs = kReadAttemptSleepUs;
|
||||
char* buff = (char*)buffer;
|
||||
size_t remainingFrames = frameCount;
|
||||
int availableToRead = source->availableToRead();
|
||||
@@ -313,11 +302,12 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
buff += framesRead * mStreamConfig.frameSize;
|
||||
availableToRead -= framesRead;
|
||||
LOG(VERBOSE) << __func__ << ": (attempts = " << attempts << ") got " << framesRead
|
||||
<< " frames, remaining=" << remainingFrames;
|
||||
<< " frames, remaining =" << remainingFrames;
|
||||
} else {
|
||||
attempts++;
|
||||
LOG(WARNING) << __func__ << ": read returned " << framesRead
|
||||
<< " , read failure attempts = " << attempts;
|
||||
<< " , read failure attempts = " << attempts << ", sleeping for "
|
||||
<< delayUs << " us";
|
||||
usleep(delayUs);
|
||||
}
|
||||
}
|
||||
@@ -337,18 +327,18 @@ size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
|
||||
// compute how much we need to sleep after reading the data by comparing the wall clock with
|
||||
// the projected time at which we should return.
|
||||
// wall clock after reading from the pipe
|
||||
auto recordDurationUs = std::chrono::steady_clock::now() - mCurrentRoute->getRecordStartTime();
|
||||
auto recordDurationUs = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - mCurrentRoute->getRecordStartTime());
|
||||
|
||||
// readCounterFrames contains the number of frames that have been read since the beginning of
|
||||
// recording (including this call): it's converted to usec and compared to how long we've been
|
||||
// recording for, which gives us how long we must wait to sync the projected recording time, and
|
||||
// the observed recording time.
|
||||
const int projectedVsObservedOffsetUs =
|
||||
std::roundf((readCounterFrames * MICROS_PER_SECOND / mStreamConfig.sampleRate) -
|
||||
recordDurationUs.count());
|
||||
const long projectedVsObservedOffsetUs =
|
||||
getDelayInUsForFrameCount(readCounterFrames) - recordDurationUs.count();
|
||||
|
||||
LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count()
|
||||
<< " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds";
|
||||
<< " us, will wait: " << projectedVsObservedOffsetUs << " us";
|
||||
if (projectedVsObservedOffsetUs > 0) {
|
||||
usleep(projectedVsObservedOffsetUs);
|
||||
}
|
||||
|
||||
@@ -14,16 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <audio_utils/clock.h>
|
||||
|
||||
#include <media/nbaio/MonoPipe.h>
|
||||
#include <media/nbaio/MonoPipeReader.h>
|
||||
|
||||
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
|
||||
|
||||
#include "core-impl/Stream.h"
|
||||
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
|
||||
|
||||
using aidl::android::media::audio::common::AudioChannelLayout;
|
||||
using aidl::android::media::audio::common::AudioFormatDescription;
|
||||
@@ -36,9 +39,13 @@ using ::android::sp;
|
||||
namespace aidl::android::hardware::audio::core::r_submix {
|
||||
|
||||
static constexpr int kDefaultSampleRateHz = 48000;
|
||||
// Size at default sample rate
|
||||
// NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe().
|
||||
static constexpr int kDefaultPipeSizeInFrames = (1024 * 4);
|
||||
// Value used to divide the MonoPipe buffer into segments that are written to the source and
|
||||
// read from the sink. The maximum latency of the device is the size of the MonoPipe's buffer
|
||||
// the minimum latency is the MonoPipe buffer size divided by this value.
|
||||
static constexpr int kDefaultPipePeriodCount = 4;
|
||||
// Size at the default sample rate
|
||||
// NOTE: This value will be rounded up to the nearest power of 2 by MonoPipe.
|
||||
static constexpr int kDefaultPipeSizeInFrames = 1024 * kDefaultPipePeriodCount;
|
||||
|
||||
// Configuration of the audio stream.
|
||||
struct AudioConfig {
|
||||
|
||||
@@ -94,7 +94,7 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||
}
|
||||
|
||||
::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) {
|
||||
int32_t*) {
|
||||
if (!mIsInitialized) {
|
||||
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
|
||||
}
|
||||
@@ -117,7 +117,6 @@ StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
|
||||
}
|
||||
}
|
||||
*actualFrameCount = frameCount;
|
||||
*latencyMs = Module::kLatencyMs;
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,20 +67,7 @@ std::optional<AudioOffloadInfo> ModuleConfig::generateOffloadInfoIfNeeded(
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioPort>
|
||||
ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
|
||||
const std::string& connection) {
|
||||
return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
|
||||
}
|
||||
|
||||
// static
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
|
||||
const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
|
||||
return getAudioPortsForDeviceTypes(
|
||||
ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
|
||||
AudioDeviceType::IN_MICROPHONE_BACK});
|
||||
}
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioPort>
|
||||
ModuleConfig::getAudioPortsForDeviceTypes(
|
||||
const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
|
||||
@@ -100,6 +87,14 @@ ModuleConfig::getAudioPortsForDeviceTypes(
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
|
||||
const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
|
||||
return getAudioPortsForDeviceTypes(
|
||||
ports, std::vector<AudioDeviceType>{AudioDeviceType::IN_MICROPHONE,
|
||||
AudioDeviceType::IN_MICROPHONE_BACK});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto findById(const std::vector<T>& v, int32_t id) {
|
||||
return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
|
||||
@@ -119,10 +114,7 @@ ModuleConfig::ModuleConfig(IModule* module) {
|
||||
} else {
|
||||
mAttachedSinkDevicePorts.insert(port.id);
|
||||
}
|
||||
} else if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_VIRTUAL
|
||||
// The "virtual" connection is used for remote submix which is a dynamic
|
||||
// device but it can be connected and used w/o external hardware.
|
||||
&& port.profiles.empty()) {
|
||||
} else {
|
||||
mExternalDevicePorts.insert(port.id);
|
||||
}
|
||||
}
|
||||
@@ -141,6 +133,12 @@ std::vector<AudioPort> ModuleConfig::getAttachedDevicePorts() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioPort>
|
||||
ModuleConfig::getAudioPortsForDeviceTypes(const std::vector<AudioDeviceType>& deviceTypes,
|
||||
const std::string& connection) const {
|
||||
return getAudioPortsForDeviceTypes(mPorts, deviceTypes, connection);
|
||||
}
|
||||
|
||||
std::vector<AudioPort> ModuleConfig::getConnectedExternalDevicePorts() const {
|
||||
std::vector<AudioPort> result;
|
||||
std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
|
||||
@@ -229,6 +227,16 @@ std::vector<AudioPort> ModuleConfig::getMmapInMixPorts(bool connectedOnly, bool
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<AudioPort> ModuleConfig::getRemoteSubmixPorts(bool isInput, bool singlePort) const {
|
||||
AudioDeviceType deviceType = isInput ? AudioDeviceType::IN_SUBMIX : AudioDeviceType::OUT_SUBMIX;
|
||||
auto ports = getAudioPortsForDeviceTypes(std::vector<AudioDeviceType>{deviceType},
|
||||
AudioDeviceDescription::CONNECTION_VIRTUAL);
|
||||
if (singlePort) {
|
||||
if (!ports.empty()) ports.resize(1);
|
||||
}
|
||||
return ports;
|
||||
}
|
||||
|
||||
std::vector<AudioPort> ModuleConfig::getConnectedDevicesPortsForMixPort(
|
||||
bool isInput, const AudioPortConfig& mixPortConfig) const {
|
||||
const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
|
||||
@@ -281,19 +289,29 @@ std::optional<AudioPort> ModuleConfig::getSourceMixPortForConnectedDevice() cons
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<AudioPort> ModuleConfig::getRoutableMixPortsForDevicePort(const AudioPort& port) const {
|
||||
std::set<int32_t> portIds;
|
||||
for (const auto& route : mRoutes) {
|
||||
if (port.id == route.sinkPortId) {
|
||||
portIds.insert(route.sourcePortIds.begin(), route.sourcePortIds.end());
|
||||
} else if (auto it = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
|
||||
port.id);
|
||||
it != route.sourcePortIds.end()) {
|
||||
portIds.insert(route.sinkPortId);
|
||||
}
|
||||
}
|
||||
std::vector<AudioPort> ModuleConfig::getRoutableDevicePortsForMixPort(const AudioPort& port,
|
||||
bool connectedOnly) const {
|
||||
std::set<int32_t> portIds = findRoutablePortIds(port.id);
|
||||
const bool isInput = port.flags.getTag() == AudioIoFlags::input;
|
||||
return findMixPorts(isInput, false /*connectedOnly*/, false /*singlePort*/,
|
||||
std::set<int32_t> devicePortIds;
|
||||
if (connectedOnly) {
|
||||
devicePortIds = isInput ? getConnectedSourceDevicePorts() : getConnectedSinkDevicePorts();
|
||||
} else {
|
||||
devicePortIds = portIds;
|
||||
}
|
||||
std::vector<AudioPort> result;
|
||||
std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
|
||||
return port.ext.getTag() == AudioPortExt::Tag::device && portIds.count(port.id) > 0 &&
|
||||
devicePortIds.count(port.id) > 0;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<AudioPort> ModuleConfig::getRoutableMixPortsForDevicePort(const AudioPort& port,
|
||||
bool connectedOnly) const {
|
||||
std::set<int32_t> portIds = findRoutablePortIds(port.id);
|
||||
const bool isInput = port.flags.getTag() == AudioIoFlags::input;
|
||||
return findMixPorts(isInput, connectedOnly, false /*singlePort*/,
|
||||
[&portIds](const AudioPort& p) { return portIds.count(p.id) > 0; });
|
||||
}
|
||||
|
||||
@@ -470,6 +488,20 @@ std::vector<AudioPort> ModuleConfig::findMixPorts(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<int32_t> ModuleConfig::findRoutablePortIds(int32_t portId) const {
|
||||
std::set<int32_t> portIds;
|
||||
for (const auto& route : mRoutes) {
|
||||
if (portId == route.sinkPortId) {
|
||||
portIds.insert(route.sourcePortIds.begin(), route.sourcePortIds.end());
|
||||
} else if (auto it = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
|
||||
portId);
|
||||
it != route.sourcePortIds.end()) {
|
||||
portIds.insert(route.sinkPortId);
|
||||
}
|
||||
}
|
||||
return portIds;
|
||||
}
|
||||
|
||||
std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
|
||||
const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
|
||||
std::vector<AudioPortConfig> result;
|
||||
|
||||
@@ -38,9 +38,6 @@ class ModuleConfig {
|
||||
generateOffloadInfoIfNeeded(
|
||||
const aidl::android::media::audio::common::AudioPortConfig& portConfig);
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
|
||||
const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
|
||||
const std::string& connection = "");
|
||||
static std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
|
||||
const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
|
||||
const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
|
||||
@@ -53,6 +50,9 @@ class ModuleConfig {
|
||||
std::string getError() const { return mStatus.getMessage(); }
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getAudioPortsForDeviceTypes(
|
||||
const std::vector<aidl::android::media::audio::common::AudioDeviceType>& deviceTypes,
|
||||
const std::string& connection = "") const;
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getConnectedExternalDevicePorts()
|
||||
const;
|
||||
std::set<int32_t> getConnectedSinkDevicePorts() const;
|
||||
@@ -85,6 +85,8 @@ class ModuleConfig {
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getMmapInMixPorts(
|
||||
bool connectedOnly /*Permanently attached and connected external devices*/,
|
||||
bool singlePort) const;
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getRemoteSubmixPorts(
|
||||
bool isInput, bool singlePort) const;
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getConnectedDevicesPortsForMixPort(
|
||||
bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
|
||||
@@ -103,8 +105,12 @@ class ModuleConfig {
|
||||
std::optional<aidl::android::media::audio::common::AudioPort>
|
||||
getSourceMixPortForConnectedDevice() const;
|
||||
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getRoutableDevicePortsForMixPort(
|
||||
const aidl::android::media::audio::common::AudioPort& port,
|
||||
bool connectedOnly /*Permanently attached and connected external devices*/) const;
|
||||
std::vector<aidl::android::media::audio::common::AudioPort> getRoutableMixPortsForDevicePort(
|
||||
const aidl::android::media::audio::common::AudioPort& port) const;
|
||||
const aidl::android::media::audio::common::AudioPort& port,
|
||||
bool connectedOnly /*Permanently attached and connected external devices*/) const;
|
||||
|
||||
std::optional<SrcSinkPair> getNonRoutableSrcSinkPair(bool isInput) const;
|
||||
std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
|
||||
@@ -176,6 +182,7 @@ class ModuleConfig {
|
||||
bool isInput, bool connectedOnly, bool singlePort,
|
||||
const std::function<bool(const aidl::android::media::audio::common::AudioPort&)>& pred)
|
||||
const;
|
||||
std::set<int32_t> findRoutablePortIds(int32_t portId) const;
|
||||
std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
|
||||
const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
|
||||
bool singleProfile) const;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <iostream>
|
||||
|
||||
#include <android/binder_auto_utils.h>
|
||||
#include <gtest/gtest.h>
|
||||
@@ -93,4 +92,4 @@ inline ::testing::AssertionResult assertResult(const char* exp_expr, const char*
|
||||
if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \
|
||||
GTEST_SKIP() << "Skip data path for offload"; \
|
||||
} \
|
||||
})
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user