mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Merge changes Iddb1bff9,I5bf8da2f,I62a422d9,If68c995d,If1f34679, ... into udc-qpr-dev
* changes: audio: Allow Module subclasses to customize stream creation audio: Refactor streams implementation audio: Propagate errors from Driver::setConnectedDevices audio: Enable use of 'expected_utils' for ScopedAStatus audio: Pass flags and I/O handle to StreamContext audio: Facilitate extension of Module class by vendors
This commit is contained in:
committed by
Android (Google) Code Review
commit
e2194e22ec
@@ -29,6 +29,21 @@
|
||||
#include <aidl/android/media/audio/common/AudioMode.h>
|
||||
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
|
||||
#include <aidl/android/media/audio/common/PcmType.h>
|
||||
#include <android/binder_auto_utils.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::common {
|
||||
|
||||
|
||||
@@ -18,19 +18,18 @@
|
||||
#include <set>
|
||||
|
||||
#define LOG_TAG "AHAL_Module"
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_ibinder_platform.h>
|
||||
|
||||
#include <Utils.h>
|
||||
#include <aidl/android/media/audio/common/AudioInputFlags.h>
|
||||
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_ibinder_platform.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#include "core-impl/Bluetooth.h"
|
||||
#include "core-impl/Module.h"
|
||||
#include "core-impl/ModuleUsb.h"
|
||||
#include "core-impl/SoundDose.h"
|
||||
#include "core-impl/StreamStub.h"
|
||||
#include "core-impl/StreamUsb.h"
|
||||
#include "core-impl/Telephony.h"
|
||||
#include "core-impl/utils.h"
|
||||
|
||||
@@ -119,30 +118,6 @@ std::shared_ptr<Module> Module::createInstance(Type type) {
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
StreamIn::CreateInstance Module::getStreamInCreator(Type type) {
|
||||
switch (type) {
|
||||
case Type::USB:
|
||||
return StreamInUsb::createInstance;
|
||||
case Type::DEFAULT:
|
||||
case Type::R_SUBMIX:
|
||||
default:
|
||||
return StreamInStub::createInstance;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
StreamOut::CreateInstance Module::getStreamOutCreator(Type type) {
|
||||
switch (type) {
|
||||
case Type::USB:
|
||||
return StreamOutUsb::createInstance;
|
||||
case Type::DEFAULT:
|
||||
case Type::R_SUBMIX:
|
||||
default:
|
||||
return StreamOutStub::createInstance;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, Module::Type t) {
|
||||
switch (t) {
|
||||
case Module::Type::DEFAULT:
|
||||
@@ -207,7 +182,8 @@ ndk::ScopedAStatus Module::createStreamContext(
|
||||
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
|
||||
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
|
||||
portConfigIt->format.value(), portConfigIt->channelMask.value(),
|
||||
portConfigIt->sampleRate.value().value,
|
||||
portConfigIt->sampleRate.value().value, flags,
|
||||
portConfigIt->ext.get<AudioPortExt::mix>().handle,
|
||||
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
|
||||
asyncCallback, outEventCallback, params);
|
||||
if (temp.isValid()) {
|
||||
@@ -339,30 +315,61 @@ void Module::registerPatch(const AudioPatch& patch) {
|
||||
do_insert(patch.sinkPortConfigIds);
|
||||
}
|
||||
|
||||
void Module::updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch) {
|
||||
ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatch,
|
||||
const AudioPatch& newPatch) {
|
||||
// Streams from the old patch need to be disconnected, streams from the new
|
||||
// patch need to be connected. If the stream belongs to both patches, no need
|
||||
// to update it.
|
||||
std::set<int32_t> idsToDisconnect, idsToConnect;
|
||||
auto maybeFailure = ndk::ScopedAStatus::ok();
|
||||
std::set<int32_t> idsToDisconnect, idsToConnect, idsToDisconnectOnFailure;
|
||||
idsToDisconnect.insert(oldPatch.sourcePortConfigIds.begin(),
|
||||
oldPatch.sourcePortConfigIds.end());
|
||||
idsToDisconnect.insert(oldPatch.sinkPortConfigIds.begin(), oldPatch.sinkPortConfigIds.end());
|
||||
idsToConnect.insert(newPatch.sourcePortConfigIds.begin(), newPatch.sourcePortConfigIds.end());
|
||||
idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
|
||||
std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
|
||||
if (idsToConnect.count(portConfigId) == 0) {
|
||||
LOG(DEBUG) << "The stream on port config id " << portConfigId << " is not connected";
|
||||
mStreams.setStreamIsConnected(portConfigId, {});
|
||||
if (idsToConnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
|
||||
if (auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); status.isOk()) {
|
||||
LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
|
||||
<< portConfigId << " has been disconnected";
|
||||
} else {
|
||||
// Disconnection is tricky to roll back, just register a failure.
|
||||
maybeFailure = std::move(status);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!maybeFailure.isOk()) return maybeFailure;
|
||||
std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
|
||||
if (idsToDisconnect.count(portConfigId) == 0) {
|
||||
if (idsToDisconnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
|
||||
const auto connectedDevices = findConnectedDevices(portConfigId);
|
||||
LOG(DEBUG) << "The stream on port config id " << portConfigId
|
||||
<< " is connected to: " << ::android::internal::ToString(connectedDevices);
|
||||
mStreams.setStreamIsConnected(portConfigId, connectedDevices);
|
||||
if (connectedDevices.empty()) {
|
||||
// This is important as workers use the vector size to derive the connection status.
|
||||
LOG(FATAL) << "updateStreamsConnectedState: No connected devices found for port "
|
||||
"config id "
|
||||
<< portConfigId;
|
||||
}
|
||||
if (auto status = mStreams.setStreamConnectedDevices(portConfigId, connectedDevices);
|
||||
status.isOk()) {
|
||||
LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
|
||||
<< portConfigId << " has been connected to: "
|
||||
<< ::android::internal::ToString(connectedDevices);
|
||||
} else {
|
||||
maybeFailure = std::move(status);
|
||||
idsToDisconnectOnFailure.insert(portConfigId);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!maybeFailure.isOk()) {
|
||||
LOG(WARNING) << __func__ << ": Due to a failure, disconnecting streams on port config ids "
|
||||
<< ::android::internal::ToString(idsToDisconnectOnFailure);
|
||||
std::for_each(idsToDisconnectOnFailure.begin(), idsToDisconnectOnFailure.end(),
|
||||
[&](const auto& portConfigId) {
|
||||
auto status = mStreams.setStreamConnectedDevices(portConfigId, {});
|
||||
(void)status.isOk(); // Can't do much about a failure here.
|
||||
});
|
||||
return maybeFailure;
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Module::setModuleDebug(
|
||||
@@ -469,10 +476,7 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA
|
||||
}
|
||||
|
||||
if (!mDebug.simulateDeviceConnections) {
|
||||
if (ndk::ScopedAStatus status = populateConnectedDevicePort(&connectedPort);
|
||||
!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(populateConnectedDevicePort(&connectedPort));
|
||||
} else {
|
||||
auto& connectedProfiles = getConfig().connectedProfiles;
|
||||
if (auto connectedProfilesIt = connectedProfiles.find(templateId);
|
||||
@@ -647,34 +651,26 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar
|
||||
LOG(DEBUG) << __func__ << ": port config id " << in_args.portConfigId << ", buffer size "
|
||||
<< in_args.bufferSizeFrames << " frames";
|
||||
AudioPort* port = nullptr;
|
||||
if (auto status = findPortIdForNewStream(in_args.portConfigId, &port); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port));
|
||||
if (port->flags.getTag() != AudioIoFlags::Tag::input) {
|
||||
LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
|
||||
<< " does not correspond to an input mix port";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
StreamContext context;
|
||||
if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, nullptr,
|
||||
nullptr, &context);
|
||||
!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
|
||||
nullptr, nullptr, &context));
|
||||
context.fillDescriptor(&_aidl_return->desc);
|
||||
std::shared_ptr<StreamIn> stream;
|
||||
ndk::ScopedAStatus status = getStreamInCreator(mType)(in_args.sinkMetadata, std::move(context),
|
||||
mConfig->microphones, &stream);
|
||||
if (!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(createInputStream(in_args.sinkMetadata, std::move(context),
|
||||
mConfig->microphones, &stream));
|
||||
StreamWrapper streamWrapper(stream);
|
||||
if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
|
||||
RETURN_STATUS_IF_ERROR(
|
||||
streamWrapper.setConnectedDevices(findConnectedDevices(in_args.portConfigId)));
|
||||
}
|
||||
AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
|
||||
ANDROID_PRIORITY_AUDIO);
|
||||
auto patchIt = mPatches.find(in_args.portConfigId);
|
||||
if (patchIt != mPatches.end()) {
|
||||
streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
|
||||
}
|
||||
mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
|
||||
_aidl_return->stream = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
@@ -686,9 +682,7 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_
|
||||
<< (in_args.offloadInfo.has_value()) << ", buffer size " << in_args.bufferSizeFrames
|
||||
<< " frames";
|
||||
AudioPort* port = nullptr;
|
||||
if (auto status = findPortIdForNewStream(in_args.portConfigId, &port); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(findPortIdForNewStream(in_args.portConfigId, &port));
|
||||
if (port->flags.getTag() != AudioIoFlags::Tag::output) {
|
||||
LOG(ERROR) << __func__ << ": port config id " << in_args.portConfigId
|
||||
<< " does not correspond to an output mix port";
|
||||
@@ -709,26 +703,20 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
StreamContext context;
|
||||
if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
|
||||
isNonBlocking ? in_args.callback : nullptr,
|
||||
in_args.eventCallback, &context);
|
||||
!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
|
||||
isNonBlocking ? in_args.callback : nullptr,
|
||||
in_args.eventCallback, &context));
|
||||
context.fillDescriptor(&_aidl_return->desc);
|
||||
std::shared_ptr<StreamOut> stream;
|
||||
ndk::ScopedAStatus status = getStreamOutCreator(mType)(
|
||||
in_args.sourceMetadata, std::move(context), in_args.offloadInfo, &stream);
|
||||
if (!status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(createOutputStream(in_args.sourceMetadata, std::move(context),
|
||||
in_args.offloadInfo, &stream));
|
||||
StreamWrapper streamWrapper(stream);
|
||||
if (auto patchIt = mPatches.find(in_args.portConfigId); patchIt != mPatches.end()) {
|
||||
RETURN_STATUS_IF_ERROR(
|
||||
streamWrapper.setConnectedDevices(findConnectedDevices(in_args.portConfigId)));
|
||||
}
|
||||
AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
|
||||
ANDROID_PRIORITY_AUDIO);
|
||||
auto patchIt = mPatches.find(in_args.portConfigId);
|
||||
if (patchIt != mPatches.end()) {
|
||||
streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
|
||||
}
|
||||
mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
|
||||
_aidl_return->stream = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
@@ -796,10 +784,7 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto status = checkAudioPatchEndpointsMatch(sources, sinks); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
RETURN_STATUS_IF_ERROR(checkAudioPatchEndpointsMatch(sources, sinks));
|
||||
|
||||
auto& patches = getConfig().patches;
|
||||
auto existing = patches.end();
|
||||
@@ -834,13 +819,20 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa
|
||||
if (existing == patches.end()) {
|
||||
_aidl_return->id = getConfig().nextPatchId++;
|
||||
patches.push_back(*_aidl_return);
|
||||
existing = patches.begin() + (patches.size() - 1);
|
||||
} else {
|
||||
oldPatch = *existing;
|
||||
*existing = *_aidl_return;
|
||||
}
|
||||
registerPatch(*existing);
|
||||
updateStreamsConnectedState(oldPatch, *_aidl_return);
|
||||
patchesBackup = mPatches;
|
||||
registerPatch(*_aidl_return);
|
||||
if (auto status = updateStreamsConnectedState(oldPatch, *_aidl_return); !status.isOk()) {
|
||||
mPatches = std::move(*patchesBackup);
|
||||
if (existing == patches.end()) {
|
||||
patches.pop_back();
|
||||
} else {
|
||||
*existing = oldPatch;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
LOG(DEBUG) << __func__ << ": " << (oldPatch.id == 0 ? "created" : "updated") << " patch "
|
||||
<< _aidl_return->toString();
|
||||
@@ -992,8 +984,12 @@ ndk::ScopedAStatus Module::resetAudioPatch(int32_t in_patchId) {
|
||||
auto& patches = getConfig().patches;
|
||||
auto patchIt = findById<AudioPatch>(patches, in_patchId);
|
||||
if (patchIt != patches.end()) {
|
||||
auto patchesBackup = mPatches;
|
||||
cleanUpPatch(patchIt->id);
|
||||
updateStreamsConnectedState(*patchIt, AudioPatch{});
|
||||
if (auto status = updateStreamsConnectedState(*patchIt, AudioPatch{}); !status.isOk()) {
|
||||
mPatches = std::move(patchesBackup);
|
||||
return status;
|
||||
}
|
||||
patches.erase(patchIt);
|
||||
LOG(DEBUG) << __func__ << ": erased patch " << in_patchId;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
@@ -1325,6 +1321,22 @@ bool Module::isMmapSupported() {
|
||||
return mIsMmapSupported.value();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Module::createInputStream(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
|
||||
microphones);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Module::createOutputStream(const SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) {
|
||||
return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) {
|
||||
LOG(VERBOSE) << __func__ << ": do nothing and return ok";
|
||||
return ndk::ScopedAStatus::ok();
|
||||
|
||||
@@ -152,6 +152,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
|
||||
case Tag::halReservedExit:
|
||||
if (const int32_t cookie = command.get<Tag::halReservedExit>();
|
||||
cookie == mInternalCommandCookie) {
|
||||
mDriver->shutdown();
|
||||
setClosed();
|
||||
// This is an internal command, no need to reply.
|
||||
return Status::EXIT;
|
||||
@@ -364,6 +365,7 @@ StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
|
||||
case Tag::halReservedExit:
|
||||
if (const int32_t cookie = command.get<Tag::halReservedExit>();
|
||||
cookie == mInternalCommandCookie) {
|
||||
mDriver->shutdown();
|
||||
setClosed();
|
||||
// This is an internal command, no need to reply.
|
||||
return Status::EXIT;
|
||||
@@ -567,8 +569,7 @@ bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* rep
|
||||
return !fatal;
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
StreamCommonImpl<Metadata>::~StreamCommonImpl() {
|
||||
StreamCommonImpl::~StreamCommonImpl() {
|
||||
if (!isClosed()) {
|
||||
LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
|
||||
stopWorker();
|
||||
@@ -576,19 +577,16 @@ StreamCommonImpl<Metadata>::~StreamCommonImpl() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
void StreamCommonImpl<Metadata>::createStreamCommon(
|
||||
ndk::ScopedAStatus StreamCommonImpl::initInstance(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) {
|
||||
if (mCommon != nullptr) {
|
||||
LOG(FATAL) << __func__ << ": attempting to create the common interface twice";
|
||||
}
|
||||
mCommon = ndk::SharedRefBase::make<StreamCommon>(delegate);
|
||||
mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
|
||||
mCommonBinder = mCommon->asBinder();
|
||||
AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
|
||||
return mWorker->start() ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::getStreamCommon(
|
||||
ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon(
|
||||
std::shared_ptr<IStreamCommon>* _aidl_return) {
|
||||
if (mCommon == nullptr) {
|
||||
LOG(FATAL) << __func__ << ": the common interface was not created";
|
||||
@@ -598,30 +596,26 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::getStreamCommon(
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateHwAvSyncId(int32_t in_hwAvSyncId) {
|
||||
ndk::ScopedAStatus StreamCommonImpl::updateHwAvSyncId(int32_t in_hwAvSyncId) {
|
||||
LOG(DEBUG) << __func__ << ": id " << in_hwAvSyncId;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::getVendorParameters(
|
||||
ndk::ScopedAStatus StreamCommonImpl::getVendorParameters(
|
||||
const std::vector<std::string>& in_ids, std::vector<VendorParameter>* _aidl_return) {
|
||||
LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
|
||||
(void)_aidl_return;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::setVendorParameters(
|
||||
ndk::ScopedAStatus StreamCommonImpl::setVendorParameters(
|
||||
const std::vector<VendorParameter>& in_parameters, bool in_async) {
|
||||
LOG(DEBUG) << __func__ << ": parameters count " << in_parameters.size()
|
||||
<< ", async: " << in_async;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::addEffect(
|
||||
ndk::ScopedAStatus StreamCommonImpl::addEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
|
||||
if (in_effect == nullptr) {
|
||||
LOG(DEBUG) << __func__ << ": null effect";
|
||||
@@ -631,8 +625,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::addEffect(
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::removeEffect(
|
||||
ndk::ScopedAStatus StreamCommonImpl::removeEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
|
||||
if (in_effect == nullptr) {
|
||||
LOG(DEBUG) << __func__ << ": null effect";
|
||||
@@ -642,8 +635,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::removeEffect(
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::close() {
|
||||
ndk::ScopedAStatus StreamCommonImpl::close() {
|
||||
LOG(DEBUG) << __func__;
|
||||
if (!isClosed()) {
|
||||
stopWorker();
|
||||
@@ -659,8 +651,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::close() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::prepareToClose() {
|
||||
ndk::ScopedAStatus StreamCommonImpl::prepareToClose() {
|
||||
LOG(DEBUG) << __func__;
|
||||
if (!isClosed()) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
@@ -669,8 +660,7 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::prepareToClose() {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
void StreamCommonImpl<Metadata>::stopWorker() {
|
||||
void StreamCommonImpl::stopWorker() {
|
||||
if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
|
||||
LOG(DEBUG) << __func__ << ": asking the worker to exit...";
|
||||
auto cmd = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::halReservedExit>(
|
||||
@@ -686,10 +676,12 @@ void StreamCommonImpl<Metadata>::stopWorker() {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Metadata>
|
||||
ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateMetadata(const Metadata& metadata) {
|
||||
ndk::ScopedAStatus StreamCommonImpl::updateMetadataCommon(const Metadata& metadata) {
|
||||
LOG(DEBUG) << __func__;
|
||||
if (!isClosed()) {
|
||||
if (metadata.index() != mMetadata.index()) {
|
||||
LOG(FATAL) << __func__ << ": changing metadata variant is not allowed";
|
||||
}
|
||||
mMetadata = metadata;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
@@ -697,12 +689,10 @@ ndk::ScopedAStatus StreamCommonImpl<Metadata>::updateMetadata(const Metadata& me
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamIn::initInstance(const std::shared_ptr<StreamIn>& stream) {
|
||||
if (auto status = stream->init(); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
stream->createStreamCommon(stream);
|
||||
ndk::ScopedAStatus StreamCommonImpl::setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
mWorker->setIsConnected(!devices.empty());
|
||||
mConnectedDevices = devices;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
@@ -716,12 +706,8 @@ static std::map<AudioDevice, std::string> transformMicrophones(
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext&& context,
|
||||
const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker,
|
||||
const std::vector<MicrophoneInfo>& microphones)
|
||||
: StreamCommonImpl<SinkMetadata>(sinkMetadata, std::move(context), createDriver, createWorker),
|
||||
mMicrophones(transformMicrophones(microphones)) {
|
||||
StreamIn::StreamIn(const std::vector<MicrophoneInfo>& microphones)
|
||||
: mMicrophones(transformMicrophones(microphones)) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
|
||||
@@ -729,9 +715,9 @@ ndk::ScopedAStatus StreamIn::getActiveMicrophones(
|
||||
std::vector<MicrophoneDynamicInfo>* _aidl_return) {
|
||||
std::vector<MicrophoneDynamicInfo> result;
|
||||
std::vector<MicrophoneDynamicInfo::ChannelMapping> channelMapping{
|
||||
getChannelCount(mContext.getChannelLayout()),
|
||||
getChannelCount(getContext().getChannelLayout()),
|
||||
MicrophoneDynamicInfo::ChannelMapping::DIRECT};
|
||||
for (auto it = mConnectedDevices.begin(); it != mConnectedDevices.end(); ++it) {
|
||||
for (auto it = getConnectedDevices().begin(); it != getConnectedDevices().end(); ++it) {
|
||||
if (auto micIt = mMicrophones.find(*it); micIt != mMicrophones.end()) {
|
||||
MicrophoneDynamicInfo dynMic;
|
||||
dynMic.id = micIt->second;
|
||||
@@ -777,22 +763,8 @@ ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamOut::initInstance(const std::shared_ptr<StreamOut>& stream) {
|
||||
if (auto status = stream->init(); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
stream->createStreamCommon(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: StreamCommonImpl<SourceMetadata>(sourceMetadata, std::move(context), createDriver,
|
||||
createWorker),
|
||||
mOffloadInfo(offloadInfo) {
|
||||
StreamOut::StreamOut(const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: mOffloadInfo(offloadInfo) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,33 +31,34 @@ using aidl::android::media::audio::common::MicrophoneInfo;
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
DriverStub::DriverStub(const StreamContext& context, bool isInput)
|
||||
: mFrameSizeBytes(context.getFrameSize()),
|
||||
StreamStub::StreamStub(const Metadata& metadata, StreamContext&& context)
|
||||
: StreamCommonImpl(metadata, std::move(context)),
|
||||
mFrameSizeBytes(context.getFrameSize()),
|
||||
mSampleRate(context.getSampleRate()),
|
||||
mIsAsynchronous(!!context.getAsyncCallback()),
|
||||
mIsInput(isInput) {}
|
||||
mIsInput(isInput(metadata)) {}
|
||||
|
||||
::android::status_t DriverStub::init() {
|
||||
::android::status_t StreamStub::init() {
|
||||
usleep(500);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::drain(StreamDescriptor::DrainMode) {
|
||||
::android::status_t StreamStub::drain(StreamDescriptor::DrainMode) {
|
||||
usleep(500);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::flush() {
|
||||
::android::status_t StreamStub::flush() {
|
||||
usleep(500);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::pause() {
|
||||
::android::status_t StreamStub::pause() {
|
||||
usleep(500);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
::android::status_t StreamStub::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) {
|
||||
static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
|
||||
static constexpr float kScaleFactor = .8f;
|
||||
@@ -79,69 +80,19 @@ DriverStub::DriverStub(const StreamContext& context, bool isInput)
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::standby() {
|
||||
::android::status_t StreamStub::standby() {
|
||||
usleep(500);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverStub::setConnectedDevices(
|
||||
const std::vector<AudioDevice>& connectedDevices __unused) {
|
||||
usleep(500);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
std::shared_ptr<StreamIn> stream =
|
||||
ndk::SharedRefBase::make<StreamInStub>(sinkMetadata, std::move(context), microphones);
|
||||
if (auto status = initInstance(stream); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
void StreamStub::shutdown() {}
|
||||
|
||||
StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context,
|
||||
const std::vector<MicrophoneInfo>& microphones)
|
||||
: StreamIn(
|
||||
sinkMetadata, std::move(context),
|
||||
[](const StreamContext& ctx) -> DriverInterface* {
|
||||
return new DriverStub(ctx, true /*isInput*/);
|
||||
},
|
||||
[](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
// The default worker implementation is used.
|
||||
return new StreamInWorker(ctx, driver);
|
||||
},
|
||||
microphones) {}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) {
|
||||
std::shared_ptr<StreamOut> stream = ndk::SharedRefBase::make<StreamOutStub>(
|
||||
sourceMetadata, std::move(context), offloadInfo);
|
||||
if (auto status = initInstance(stream); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
: StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}
|
||||
|
||||
StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: StreamOut(
|
||||
sourceMetadata, std::move(context),
|
||||
[](const StreamContext& ctx) -> DriverInterface* {
|
||||
return new DriverStub(ctx, false /*isInput*/);
|
||||
},
|
||||
[](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
// The default worker implementation is used.
|
||||
return new StreamOutWorker(ctx, driver);
|
||||
},
|
||||
offloadInfo) {}
|
||||
: StreamStub(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
||||
@@ -33,39 +33,13 @@ class Module : public BnModule {
|
||||
static constexpr int32_t kLatencyMs = 10;
|
||||
enum Type : int { DEFAULT, R_SUBMIX, USB };
|
||||
|
||||
static std::shared_ptr<Module> createInstance(Type type);
|
||||
|
||||
explicit Module(Type type) : mType(type) {}
|
||||
|
||||
static std::shared_ptr<Module> createInstance(Type type);
|
||||
static StreamIn::CreateInstance getStreamInCreator(Type type);
|
||||
static StreamOut::CreateInstance getStreamOutCreator(Type type);
|
||||
|
||||
private:
|
||||
struct VendorDebug {
|
||||
static const std::string kForceTransientBurstName;
|
||||
static const std::string kForceSynchronousDrainName;
|
||||
bool forceTransientBurst = false;
|
||||
bool forceSynchronousDrain = false;
|
||||
};
|
||||
// Helper used for interfaces that require a persistent instance. We hold them via a strong
|
||||
// pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
|
||||
template <class C>
|
||||
struct ChildInterface : private std::pair<std::shared_ptr<C>, ndk::SpAIBinder> {
|
||||
ChildInterface() {}
|
||||
ChildInterface& operator=(const std::shared_ptr<C>& c) {
|
||||
return operator=(std::shared_ptr<C>(c));
|
||||
}
|
||||
ChildInterface& operator=(std::shared_ptr<C>&& c) {
|
||||
this->first = std::move(c);
|
||||
this->second = this->first->asBinder();
|
||||
AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL,
|
||||
ANDROID_PRIORITY_AUDIO);
|
||||
return *this;
|
||||
}
|
||||
explicit operator bool() const { return !!this->first; }
|
||||
C& operator*() const { return *(this->first); }
|
||||
C* operator->() const { return this->first; }
|
||||
std::shared_ptr<C> getPtr() const { return this->first; }
|
||||
};
|
||||
protected:
|
||||
// The vendor extension done via inheritance can override interface methods and augment
|
||||
// a call to the base implementation.
|
||||
|
||||
ndk::ScopedAStatus setModuleDebug(
|
||||
const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
|
||||
@@ -146,29 +120,46 @@ class Module : public BnModule {
|
||||
ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
|
||||
|
||||
void cleanUpPatch(int32_t patchId);
|
||||
ndk::ScopedAStatus createStreamContext(
|
||||
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
::aidl::android::hardware::audio::core::StreamContext* out_context);
|
||||
std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices(
|
||||
int32_t portConfigId);
|
||||
std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
|
||||
ndk::ScopedAStatus findPortIdForNewStream(
|
||||
int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
|
||||
internal::Configuration& getConfig();
|
||||
template <typename C>
|
||||
std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
|
||||
void registerPatch(const AudioPatch& patch);
|
||||
void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch);
|
||||
bool isMmapSupported();
|
||||
|
||||
// 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;
|
||||
|
||||
private:
|
||||
struct VendorDebug {
|
||||
static const std::string kForceTransientBurstName;
|
||||
static const std::string kForceSynchronousDrainName;
|
||||
bool forceTransientBurst = false;
|
||||
bool forceSynchronousDrain = false;
|
||||
};
|
||||
// Helper used for interfaces that require a persistent instance. We hold them via a strong
|
||||
// pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
|
||||
template <class C>
|
||||
struct ChildInterface : private std::pair<std::shared_ptr<C>, ndk::SpAIBinder> {
|
||||
ChildInterface() {}
|
||||
ChildInterface& operator=(const std::shared_ptr<C>& c) {
|
||||
return operator=(std::shared_ptr<C>(c));
|
||||
}
|
||||
ChildInterface& operator=(std::shared_ptr<C>&& c) {
|
||||
this->first = std::move(c);
|
||||
this->second = this->first->asBinder();
|
||||
AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL,
|
||||
ANDROID_PRIORITY_AUDIO);
|
||||
return *this;
|
||||
}
|
||||
explicit operator bool() const { return !!this->first; }
|
||||
C& operator*() const { return *(this->first); }
|
||||
C* operator->() const { return this->first; }
|
||||
std::shared_ptr<C> getPtr() const { return this->first; }
|
||||
};
|
||||
// ids of device ports created at runtime via 'connectExternalDevice'.
|
||||
// Also stores a list of ids of mix ports with dynamic profiles that were populated from
|
||||
// the connected port. This list can be empty, thus an int->int multimap can't be used.
|
||||
using ConnectedDevicePorts = std::map<int32_t, std::vector<int32_t>>;
|
||||
// Maps port ids and port config ids to patch ids.
|
||||
// Multimap because both ports and configs can be used by multiple patches.
|
||||
using Patches = std::multimap<int32_t, int32_t>;
|
||||
|
||||
const Type mType;
|
||||
std::unique_ptr<internal::Configuration> mConfig;
|
||||
ModuleDebug mDebug;
|
||||
@@ -177,19 +168,29 @@ class Module : public BnModule {
|
||||
ChildInterface<IBluetooth> mBluetooth;
|
||||
ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
|
||||
ChildInterface<IBluetoothLe> mBluetoothLe;
|
||||
// ids of device ports created at runtime via 'connectExternalDevice'.
|
||||
// Also stores ids of mix ports with dynamic profiles which got populated from the connected
|
||||
// port.
|
||||
std::map<int32_t, std::vector<int32_t>> mConnectedDevicePorts;
|
||||
ConnectedDevicePorts mConnectedDevicePorts;
|
||||
Streams mStreams;
|
||||
// Maps port ids and port config ids to patch ids.
|
||||
// Multimap because both ports and configs can be used by multiple patches.
|
||||
std::multimap<int32_t, int32_t> mPatches;
|
||||
Patches mPatches;
|
||||
bool mMicMute = false;
|
||||
bool mMasterMute = false;
|
||||
float mMasterVolume = 1.0f;
|
||||
ChildInterface<sounddose::ISoundDose> mSoundDose;
|
||||
std::optional<bool> mIsMmapSupported;
|
||||
|
||||
protected:
|
||||
// The following virtual functions are intended for vendor extension via inheritance.
|
||||
|
||||
virtual ndk::ScopedAStatus createInputStream(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result);
|
||||
virtual ndk::ScopedAStatus createOutputStream(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result);
|
||||
// If the module is unable to populate the connected device port correctly, the returned error
|
||||
// code must correspond to the errors of `IModule.connectedExternalDevice` method.
|
||||
virtual ndk::ScopedAStatus populateConnectedDevicePort(
|
||||
@@ -204,8 +205,31 @@ class Module : public BnModule {
|
||||
virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute);
|
||||
virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume);
|
||||
|
||||
bool mMasterMute = false;
|
||||
float mMasterVolume = 1.0f;
|
||||
// Utility and helper functions accessible to subclasses.
|
||||
void cleanUpPatch(int32_t patchId);
|
||||
ndk::ScopedAStatus createStreamContext(
|
||||
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
::aidl::android::hardware::audio::core::StreamContext* out_context);
|
||||
std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices(
|
||||
int32_t portConfigId);
|
||||
std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
|
||||
ndk::ScopedAStatus findPortIdForNewStream(
|
||||
int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
|
||||
internal::Configuration& getConfig();
|
||||
const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
|
||||
bool getMasterMute() const { return mMasterMute; }
|
||||
bool getMasterVolume() const { return mMasterVolume; }
|
||||
bool getMicMute() const { return mMicMute; }
|
||||
const Patches& getPatches() const { return mPatches; }
|
||||
const Streams& getStreams() const { return mStreams; }
|
||||
bool isMmapSupported();
|
||||
template <typename C>
|
||||
std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
|
||||
void registerPatch(const AudioPatch& patch);
|
||||
ndk::ScopedAStatus updateStreamsConnectedState(const AudioPatch& oldPatch,
|
||||
const AudioPatch& newPatch);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::core
|
||||
|
||||
@@ -32,6 +32,17 @@ class ModuleUsb : public Module {
|
||||
ndk::ScopedAStatus setMicMute(bool in_mute) override;
|
||||
|
||||
// Module interfaces
|
||||
ndk::ScopedAStatus createInputStream(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) override;
|
||||
ndk::ScopedAStatus createOutputStream(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) override;
|
||||
ndk::ScopedAStatus populateConnectedDevicePort(
|
||||
::aidl::android::media::audio::common::AudioPort* audioPort) override;
|
||||
ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <variant>
|
||||
|
||||
#include <StreamWorker.h>
|
||||
#include <Utils.h>
|
||||
#include <aidl/android/hardware/audio/common/SinkMetadata.h>
|
||||
#include <aidl/android/hardware/audio/common/SourceMetadata.h>
|
||||
#include <aidl/android/hardware/audio/core/BnStreamCommon.h>
|
||||
@@ -34,8 +35,10 @@
|
||||
#include <aidl/android/hardware/audio/core/IStreamOutEventCallback.h>
|
||||
#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
|
||||
#include <aidl/android/media/audio/common/AudioDevice.h>
|
||||
#include <aidl/android/media/audio/common/AudioIoFlags.h>
|
||||
#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
|
||||
#include <aidl/android/media/audio/common/MicrophoneInfo.h>
|
||||
#include <error/expected_utils.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
#include <system/thread_defs.h>
|
||||
#include <utils/Errors.h>
|
||||
@@ -77,7 +80,8 @@ class StreamContext {
|
||||
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
|
||||
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
|
||||
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
|
||||
int sampleRate, std::unique_ptr<DataMQ> dataMQ,
|
||||
int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
|
||||
int32_t mixPortHandle, std::unique_ptr<DataMQ> dataMQ,
|
||||
std::shared_ptr<IStreamCallback> asyncCallback,
|
||||
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
|
||||
DebugParameters debugParameters)
|
||||
@@ -87,6 +91,8 @@ class StreamContext {
|
||||
mFormat(format),
|
||||
mChannelLayout(channelLayout),
|
||||
mSampleRate(sampleRate),
|
||||
mFlags(flags),
|
||||
mMixPortHandle(mixPortHandle),
|
||||
mDataMQ(std::move(dataMQ)),
|
||||
mAsyncCallback(asyncCallback),
|
||||
mOutEventCallback(outEventCallback),
|
||||
@@ -98,6 +104,8 @@ class StreamContext {
|
||||
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)),
|
||||
@@ -109,6 +117,8 @@ class StreamContext {
|
||||
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);
|
||||
@@ -126,10 +136,12 @@ class StreamContext {
|
||||
::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
|
||||
return mFormat;
|
||||
}
|
||||
::aidl::android::media::audio::common::AudioIoFlags getFlags() const { return mFlags; }
|
||||
bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; }
|
||||
bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
|
||||
size_t getFrameSize() const;
|
||||
int getInternalCommandCookie() const { return mInternalCommandCookie; }
|
||||
int32_t getMixPortHandle() const { return mMixPortHandle; }
|
||||
std::shared_ptr<IStreamOutEventCallback> getOutEventCallback() const {
|
||||
return mOutEventCallback;
|
||||
}
|
||||
@@ -146,14 +158,16 @@ class StreamContext {
|
||||
::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 mMixPortHandle;
|
||||
std::unique_ptr<DataMQ> mDataMQ;
|
||||
std::shared_ptr<IStreamCallback> mAsyncCallback;
|
||||
std::shared_ptr<IStreamOutEventCallback> mOutEventCallback; // Only used by output streams
|
||||
DebugParameters mDebugParameters;
|
||||
};
|
||||
|
||||
// This interface provides operations of the stream which are executed on the worker thread.
|
||||
struct DriverInterface {
|
||||
using CreateInstance = std::function<DriverInterface*(const StreamContext&)>;
|
||||
virtual ~DriverInterface() = default;
|
||||
// All the methods below are called on the worker thread.
|
||||
virtual ::android::status_t init() = 0; // This function is only called once.
|
||||
@@ -163,11 +177,7 @@ struct DriverInterface {
|
||||
virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) = 0;
|
||||
virtual ::android::status_t standby() = 0;
|
||||
// The method below is called from a thread of the Binder pool. Access to data shared with other
|
||||
// methods of this interface must be done in a thread-safe manner.
|
||||
virtual ::android::status_t setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>&
|
||||
connectedDevices) = 0;
|
||||
virtual void shutdown() = 0; // This function is only called once.
|
||||
};
|
||||
|
||||
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
|
||||
@@ -284,14 +294,20 @@ class StreamOutWorkerLogic : public StreamWorkerCommonLogic {
|
||||
};
|
||||
using StreamOutWorker = StreamWorkerImpl<StreamOutWorkerLogic>;
|
||||
|
||||
// This provides a C++ interface with methods of the IStreamCommon Binder interface,
|
||||
// but intentionally does not inherit from it. This is needed to avoid inheriting
|
||||
// StreamIn and StreamOut from two Binder interface classes, as these parts of the class
|
||||
// will be reference counted separately.
|
||||
//
|
||||
// The implementation of these common methods is in the StreamCommonImpl template class.
|
||||
// This interface provides operations of the stream which are executed on a Binder pool thread.
|
||||
// These methods originate both from the AIDL interface and its implementation.
|
||||
struct StreamCommonInterface {
|
||||
using ConnectedDevices = std::vector<::aidl::android::media::audio::common::AudioDevice>;
|
||||
using Metadata =
|
||||
std::variant<::aidl::android::hardware::audio::common::SinkMetadata /*IStreamIn*/,
|
||||
::aidl::android::hardware::audio::common::SourceMetadata /*IStreamOut*/>;
|
||||
|
||||
static constexpr bool isInput(const Metadata& metadata) { return metadata.index() == 0; }
|
||||
|
||||
virtual ~StreamCommonInterface() = default;
|
||||
// Methods below originate from the 'IStreamCommon' interface.
|
||||
// This is semantically equivalent to inheriting from 'IStreamCommon' with a benefit
|
||||
// that concrete stream implementations can inherit both from this interface and IStreamIn/Out.
|
||||
virtual ndk::ScopedAStatus close() = 0;
|
||||
virtual ndk::ScopedAStatus prepareToClose() = 0;
|
||||
virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0;
|
||||
@@ -305,11 +321,30 @@ struct StreamCommonInterface {
|
||||
virtual ndk::ScopedAStatus removeEffect(
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
|
||||
in_effect) = 0;
|
||||
// Methods below are common for both 'IStreamIn' and 'IStreamOut'. Note that
|
||||
// 'updateMetadata' in them uses an individual structure which is wrapped here.
|
||||
// The 'Common' suffix is added to distinguish them from the methods from 'IStreamIn/Out'.
|
||||
virtual ndk::ScopedAStatus getStreamCommonCommon(
|
||||
std::shared_ptr<IStreamCommon>* _aidl_return) = 0;
|
||||
virtual ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) = 0;
|
||||
// Methods below are called by implementation of 'IModule', 'IStreamIn' and 'IStreamOut'.
|
||||
virtual ndk::ScopedAStatus initInstance(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) = 0;
|
||||
virtual const StreamContext& getContext() const = 0;
|
||||
virtual bool isClosed() const = 0;
|
||||
virtual const ConnectedDevices& getConnectedDevices() const = 0;
|
||||
virtual ndk::ScopedAStatus setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0;
|
||||
};
|
||||
|
||||
class StreamCommon : public BnStreamCommon {
|
||||
// This is equivalent to automatically generated 'IStreamCommonDelegator' but uses
|
||||
// a weak pointer to avoid creating a reference loop. The loop will occur because
|
||||
// 'IStreamIn/Out.getStreamCommon' must return the same instance every time, thus
|
||||
// the stream implementation must hold a strong pointer to an instance of 'IStreamCommon'.
|
||||
// Also, we use 'StreamCommonInterface' here instead of 'IStreamCommon'.
|
||||
class StreamCommonDelegator : public BnStreamCommon {
|
||||
public:
|
||||
explicit StreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate)
|
||||
explicit StreamCommonDelegator(const std::shared_ptr<StreamCommonInterface>& delegate)
|
||||
: mDelegate(delegate) {}
|
||||
|
||||
private:
|
||||
@@ -360,9 +395,20 @@ class StreamCommon : public BnStreamCommon {
|
||||
std::weak_ptr<StreamCommonInterface> mDelegate;
|
||||
};
|
||||
|
||||
template <class Metadata>
|
||||
class StreamCommonImpl : public StreamCommonInterface {
|
||||
// The implementation of DriverInterface must be provided by each concrete stream implementation.
|
||||
class StreamCommonImpl : virtual public StreamCommonInterface, virtual public DriverInterface {
|
||||
public:
|
||||
StreamCommonImpl(const Metadata& metadata, StreamContext&& context,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker)
|
||||
: mMetadata(metadata),
|
||||
mContext(std::move(context)),
|
||||
mWorker(createWorker(mContext, this)) {}
|
||||
StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
|
||||
: StreamCommonImpl(
|
||||
metadata, std::move(context),
|
||||
isInput(metadata) ? getDefaultInWorkerCreator() : getDefaultOutWorkerCreator()) {}
|
||||
~StreamCommonImpl();
|
||||
|
||||
ndk::ScopedAStatus close() override;
|
||||
ndk::ScopedAStatus prepareToClose() override;
|
||||
ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
|
||||
@@ -377,46 +423,50 @@ class StreamCommonImpl : public StreamCommonInterface {
|
||||
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
|
||||
override;
|
||||
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return);
|
||||
ndk::ScopedAStatus init() {
|
||||
return mWorker->start() ? ndk::ScopedAStatus::ok()
|
||||
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
|
||||
}
|
||||
bool isClosed() const { return mWorker->isClosed(); }
|
||||
void setIsConnected(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
mWorker->setIsConnected(!devices.empty());
|
||||
mConnectedDevices = devices;
|
||||
mDriver->setConnectedDevices(devices);
|
||||
}
|
||||
ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
|
||||
ndk::ScopedAStatus getStreamCommonCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override;
|
||||
ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
|
||||
|
||||
ndk::ScopedAStatus initInstance(
|
||||
const std::shared_ptr<StreamCommonInterface>& delegate) override;
|
||||
const StreamContext& getContext() const override { return mContext; }
|
||||
bool isClosed() const override { return mWorker->isClosed(); }
|
||||
const ConnectedDevices& getConnectedDevices() const override { return mConnectedDevices; }
|
||||
ndk::ScopedAStatus setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
|
||||
override;
|
||||
|
||||
protected:
|
||||
StreamCommonImpl(const Metadata& metadata, StreamContext&& context,
|
||||
const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker)
|
||||
: mMetadata(metadata),
|
||||
mContext(std::move(context)),
|
||||
mDriver(createDriver(mContext)),
|
||||
mWorker(createWorker(mContext, mDriver.get())) {}
|
||||
~StreamCommonImpl();
|
||||
void stopWorker();
|
||||
void createStreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate);
|
||||
static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() {
|
||||
return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
return new StreamInWorker(ctx, driver);
|
||||
};
|
||||
}
|
||||
static StreamWorkerInterface::CreateInstance getDefaultOutWorkerCreator() {
|
||||
return [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
return new StreamOutWorker(ctx, driver);
|
||||
};
|
||||
}
|
||||
|
||||
void stopWorker();
|
||||
|
||||
std::shared_ptr<StreamCommon> mCommon;
|
||||
ndk::SpAIBinder mCommonBinder;
|
||||
Metadata mMetadata;
|
||||
StreamContext mContext;
|
||||
std::unique_ptr<DriverInterface> mDriver;
|
||||
std::unique_ptr<StreamWorkerInterface> mWorker;
|
||||
std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices;
|
||||
std::shared_ptr<StreamCommonDelegator> mCommon;
|
||||
ndk::SpAIBinder mCommonBinder;
|
||||
ConnectedDevices mConnectedDevices;
|
||||
};
|
||||
|
||||
class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>,
|
||||
public BnStreamIn {
|
||||
// Note: 'StreamIn/Out' can not be used on their own. Instead, they must be used for defining
|
||||
// concrete input/output stream implementations.
|
||||
class StreamIn : virtual public StreamCommonInterface, public BnStreamIn {
|
||||
protected:
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>::
|
||||
getStreamCommon(_aidl_return);
|
||||
return getStreamCommonCommon(_aidl_return);
|
||||
}
|
||||
ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
|
||||
in_sinkMetadata) override {
|
||||
return updateMetadataCommon(in_sinkMetadata);
|
||||
}
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
@@ -425,49 +475,26 @@ class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::commo
|
||||
ndk::ScopedAStatus setMicrophoneDirection(MicrophoneDirection in_direction) override;
|
||||
ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override;
|
||||
ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
|
||||
ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
|
||||
in_sinkMetadata) override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata>::
|
||||
updateMetadata(in_sinkMetadata);
|
||||
}
|
||||
ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
|
||||
|
||||
protected:
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
static ndk::ScopedAStatus initInstance(const std::shared_ptr<StreamIn>& stream);
|
||||
|
||||
StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context, const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
void createStreamCommon(const std::shared_ptr<StreamIn>& myPtr) {
|
||||
StreamCommonImpl<
|
||||
::aidl::android::hardware::audio::common::SinkMetadata>::createStreamCommon(myPtr);
|
||||
}
|
||||
explicit StreamIn(
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
|
||||
const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
|
||||
|
||||
public:
|
||||
using CreateInstance = std::function<ndk::ScopedAStatus(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result)>;
|
||||
};
|
||||
|
||||
class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>,
|
||||
public BnStreamOut {
|
||||
class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
|
||||
protected:
|
||||
ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>::
|
||||
getStreamCommon(_aidl_return);
|
||||
return getStreamCommonCommon(_aidl_return);
|
||||
}
|
||||
ndk::ScopedAStatus updateMetadata(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
|
||||
override {
|
||||
return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>::
|
||||
updateMetadata(in_sourceMetadata);
|
||||
return updateMetadataCommon(in_sourceMetadata);
|
||||
}
|
||||
ndk::ScopedAStatus updateOffloadMetadata(
|
||||
const ::aidl::android::hardware::audio::common::AudioOffloadMetadata&
|
||||
@@ -492,34 +519,27 @@ class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::comm
|
||||
override;
|
||||
ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override;
|
||||
|
||||
void createStreamCommon(const std::shared_ptr<StreamOut>& myPtr) {
|
||||
StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>::
|
||||
createStreamCommon(myPtr);
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class ndk::SharedRefBase;
|
||||
|
||||
static ndk::ScopedAStatus initInstance(const std::shared_ptr<StreamOut>& stream);
|
||||
|
||||
StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context, const DriverInterface::CreateInstance& createDriver,
|
||||
const StreamWorkerInterface::CreateInstance& createWorker,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
explicit StreamOut(const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
|
||||
std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
|
||||
|
||||
public:
|
||||
using CreateInstance = std::function<ndk::ScopedAStatus(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result)>;
|
||||
};
|
||||
|
||||
// The recommended way to create a stream instance.
|
||||
// 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or
|
||||
// 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'.
|
||||
template <class StreamImpl, class StreamInOrOut, class... Args>
|
||||
ndk::ScopedAStatus createStreamInstance(std::shared_ptr<StreamInOrOut>* result, Args&&... args) {
|
||||
std::shared_ptr<StreamInOrOut> stream =
|
||||
::ndk::SharedRefBase::make<StreamImpl>(std::forward<Args>(args)...);
|
||||
RETURN_STATUS_IF_ERROR(stream->initInstance(stream));
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
class StreamWrapper {
|
||||
public:
|
||||
explicit StreamWrapper(const std::shared_ptr<StreamIn>& streamIn)
|
||||
@@ -528,25 +548,18 @@ class StreamWrapper {
|
||||
: mStream(streamOut), mStreamBinder(streamOut->asBinder()) {}
|
||||
ndk::SpAIBinder getBinder() const { return mStreamBinder; }
|
||||
bool isStreamOpen() const {
|
||||
return std::visit(
|
||||
[](auto&& ws) -> bool {
|
||||
auto s = ws.lock();
|
||||
return s && !s->isClosed();
|
||||
},
|
||||
mStream);
|
||||
auto s = mStream.lock();
|
||||
return s && !s->isClosed();
|
||||
}
|
||||
void setStreamIsConnected(
|
||||
ndk::ScopedAStatus setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
std::visit(
|
||||
[&](auto&& ws) {
|
||||
auto s = ws.lock();
|
||||
if (s) s->setIsConnected(devices);
|
||||
},
|
||||
mStream);
|
||||
auto s = mStream.lock();
|
||||
if (s) return s->setConnectedDevices(devices);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
private:
|
||||
std::variant<std::weak_ptr<StreamIn>, std::weak_ptr<StreamOut>> mStream;
|
||||
std::weak_ptr<StreamCommonInterface> mStream;
|
||||
ndk::SpAIBinder mStreamBinder;
|
||||
};
|
||||
|
||||
@@ -564,12 +577,13 @@ class Streams {
|
||||
mStreams.insert(std::pair{portConfigId, sw});
|
||||
mStreams.insert(std::pair{portId, std::move(sw)});
|
||||
}
|
||||
void setStreamIsConnected(
|
||||
ndk::ScopedAStatus setStreamConnectedDevices(
|
||||
int32_t portConfigId,
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
|
||||
if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
|
||||
it->second.setStreamIsConnected(devices);
|
||||
return it->second.setConnectedDevices(devices);
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class DriverStub : public DriverInterface {
|
||||
class StreamStub : public StreamCommonImpl {
|
||||
public:
|
||||
DriverStub(const StreamContext& context, bool isInput);
|
||||
StreamStub(const Metadata& metadata, StreamContext&& context);
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init() override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode) override;
|
||||
::android::status_t flush() override;
|
||||
@@ -30,10 +31,7 @@ class DriverStub : public DriverInterface {
|
||||
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) override;
|
||||
::android::status_t standby() override;
|
||||
// Note: called on a different thread.
|
||||
::android::status_t setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices)
|
||||
override;
|
||||
void shutdown() override;
|
||||
|
||||
private:
|
||||
const size_t mFrameSizeBytes;
|
||||
@@ -42,15 +40,8 @@ class DriverStub : public DriverInterface {
|
||||
const bool mIsInput;
|
||||
};
|
||||
|
||||
class StreamInStub final : public StreamIn {
|
||||
class StreamInStub final : public StreamStub, public StreamIn {
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result);
|
||||
|
||||
private:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInStub(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
@@ -58,16 +49,8 @@ class StreamInStub final : public StreamIn {
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
};
|
||||
|
||||
class StreamOutStub final : public StreamOut {
|
||||
class StreamOutStub final : public StreamStub, public StreamOut {
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result);
|
||||
|
||||
private:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutStub(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
|
||||
@@ -30,9 +30,10 @@ extern "C" {
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
class DriverUsb : public DriverInterface {
|
||||
class StreamUsb : public StreamCommonImpl {
|
||||
public:
|
||||
DriverUsb(const StreamContext& context, bool isInput);
|
||||
StreamUsb(const Metadata& metadata, StreamContext&& context);
|
||||
// Methods of 'DriverInterface'.
|
||||
::android::status_t init() override;
|
||||
::android::status_t drain(StreamDescriptor::DrainMode) override;
|
||||
::android::status_t flush() override;
|
||||
@@ -40,62 +41,47 @@ class DriverUsb : public DriverInterface {
|
||||
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) override;
|
||||
::android::status_t standby() override;
|
||||
// Note: called on a different thread.
|
||||
::android::status_t setConnectedDevices(
|
||||
const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices)
|
||||
override;
|
||||
void shutdown() override;
|
||||
|
||||
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
|
||||
const ConnectedDevices& getConnectedDevices() const override;
|
||||
ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
|
||||
|
||||
private:
|
||||
::android::status_t exitStandby();
|
||||
|
||||
std::mutex mLock;
|
||||
mutable std::mutex mLock;
|
||||
|
||||
const size_t mFrameSizeBytes;
|
||||
std::optional<struct pcm_config> mConfig;
|
||||
const bool mIsInput;
|
||||
// Cached device addresses for connected devices.
|
||||
std::vector<::aidl::android::media::audio::common::AudioDeviceAddress> mConnectedDevices
|
||||
GUARDED_BY(mLock);
|
||||
std::vector<std::shared_ptr<alsa_device_proxy>> mAlsaDeviceProxies GUARDED_BY(mLock);
|
||||
bool mIsStandby = true;
|
||||
};
|
||||
|
||||
class StreamInUsb final : public StreamIn {
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
|
||||
class StreamInUsb final : public StreamUsb, public StreamIn {
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result);
|
||||
|
||||
private:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamInUsb(
|
||||
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
|
||||
};
|
||||
|
||||
class StreamOutUsb final : public StreamOut {
|
||||
public:
|
||||
static ndk::ScopedAStatus createInstance(
|
||||
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result);
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus getActiveMicrophones(
|
||||
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
|
||||
override;
|
||||
};
|
||||
|
||||
class StreamOutUsb final : public StreamUsb, public StreamOut {
|
||||
public:
|
||||
friend class ndk::SharedRefBase;
|
||||
StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
|
||||
offloadInfo);
|
||||
|
||||
private:
|
||||
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
|
||||
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
|
||||
|
||||
|
||||
@@ -25,22 +25,27 @@
|
||||
#include "UsbAlsaMixerControl.h"
|
||||
#include "UsbAlsaUtils.h"
|
||||
#include "core-impl/ModuleUsb.h"
|
||||
#include "core-impl/StreamUsb.h"
|
||||
|
||||
extern "C" {
|
||||
#include "alsa_device_profile.h"
|
||||
}
|
||||
|
||||
using aidl::android::hardware::audio::common::isUsbInputDeviceType;
|
||||
using aidl::android::hardware::audio::common::SinkMetadata;
|
||||
using aidl::android::hardware::audio::common::SourceMetadata;
|
||||
using aidl::android::media::audio::common::AudioChannelLayout;
|
||||
using aidl::android::media::audio::common::AudioDeviceAddress;
|
||||
using aidl::android::media::audio::common::AudioDeviceDescription;
|
||||
using aidl::android::media::audio::common::AudioDeviceType;
|
||||
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::AudioPort;
|
||||
using aidl::android::media::audio::common::AudioPortConfig;
|
||||
using aidl::android::media::audio::common::AudioPortExt;
|
||||
using aidl::android::media::audio::common::AudioProfile;
|
||||
using aidl::android::media::audio::common::MicrophoneInfo;
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
@@ -97,6 +102,25 @@ ndk::ScopedAStatus ModuleUsb::setMicMute(bool in_mute __unused) {
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleUsb::createInputStream(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
return createStreamInstance<StreamInUsb>(result, sinkMetadata, std::move(context), microphones);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) {
|
||||
if (offloadInfo.has_value()) {
|
||||
LOG(ERROR) << __func__ << ": offload is not supported";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
return createStreamInstance<StreamOutUsb>(result, sourceMetadata, std::move(context),
|
||||
offloadInfo);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) {
|
||||
if (audioPort->ext.getTag() != AudioPortExt::Tag::device) {
|
||||
LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a device port";
|
||||
@@ -175,8 +199,8 @@ void ModuleUsb::onExternalDeviceConnectionChanged(
|
||||
return;
|
||||
}
|
||||
const int card = address.get<AudioDeviceAddress::alsa>()[0];
|
||||
usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(card, mMasterMute,
|
||||
mMasterVolume, connected);
|
||||
usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(card, getMasterMute(),
|
||||
getMasterVolume(), connected);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus ModuleUsb::onMasterMuteChanged(bool mute) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <Utils.h>
|
||||
#include <error/expected_utils.h>
|
||||
|
||||
#include "UsbAlsaMixerControl.h"
|
||||
#include "UsbAlsaUtils.h"
|
||||
@@ -42,10 +43,12 @@ using android::status_t;
|
||||
|
||||
namespace aidl::android::hardware::audio::core {
|
||||
|
||||
DriverUsb::DriverUsb(const StreamContext& context, bool isInput)
|
||||
: mFrameSizeBytes(context.getFrameSize()), mIsInput(isInput) {
|
||||
StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
|
||||
: StreamCommonImpl(metadata, std::move(context)),
|
||||
mFrameSizeBytes(context.getFrameSize()),
|
||||
mIsInput(isInput(metadata)) {
|
||||
struct pcm_config config;
|
||||
config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
|
||||
config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), mIsInput);
|
||||
if (config.channels == 0) {
|
||||
LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
|
||||
return;
|
||||
@@ -63,48 +66,50 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput)
|
||||
mConfig = config;
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::init() {
|
||||
::android::status_t StreamUsb::init() {
|
||||
return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::setConnectedDevices(
|
||||
const StreamCommonInterface::ConnectedDevices& StreamUsb::getConnectedDevices() const {
|
||||
std::lock_guard guard(mLock);
|
||||
return mConnectedDevices;
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamUsb::setConnectedDevices(
|
||||
const std::vector<AudioDevice>& connectedDevices) {
|
||||
if (mIsInput && connectedDevices.size() > 1) {
|
||||
LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
|
||||
<< ") for input stream";
|
||||
return ::android::BAD_VALUE;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
for (const auto& connectedDevice : connectedDevices) {
|
||||
if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) {
|
||||
LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
|
||||
return ::android::BAD_VALUE;
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
}
|
||||
std::lock_guard guard(mLock);
|
||||
mAlsaDeviceProxies.clear();
|
||||
mConnectedDevices.clear();
|
||||
for (const auto& connectedDevice : connectedDevices) {
|
||||
mConnectedDevices.push_back(connectedDevice.address);
|
||||
}
|
||||
return ::android::OK;
|
||||
RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::drain(StreamDescriptor::DrainMode) {
|
||||
::android::status_t StreamUsb::drain(StreamDescriptor::DrainMode) {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::flush() {
|
||||
::android::status_t StreamUsb::flush() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::pause() {
|
||||
::android::status_t StreamUsb::pause() {
|
||||
usleep(1000);
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
|
||||
int32_t* latencyMs) {
|
||||
{
|
||||
std::lock_guard guard(mLock);
|
||||
@@ -139,7 +144,7 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput)
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::standby() {
|
||||
::android::status_t StreamUsb::standby() {
|
||||
if (!mIsStandby) {
|
||||
std::lock_guard guard(mLock);
|
||||
mAlsaDeviceProxies.clear();
|
||||
@@ -148,11 +153,15 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput)
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
::android::status_t DriverUsb::exitStandby() {
|
||||
void StreamUsb::shutdown() {}
|
||||
|
||||
::android::status_t StreamUsb::exitStandby() {
|
||||
std::vector<AudioDeviceAddress> connectedDevices;
|
||||
{
|
||||
std::lock_guard guard(mLock);
|
||||
connectedDevices = mConnectedDevices;
|
||||
std::transform(mConnectedDevices.begin(), mConnectedDevices.end(),
|
||||
std::back_inserter(connectedDevices),
|
||||
[](const auto& device) { return device.address; });
|
||||
}
|
||||
std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
|
||||
for (const auto& device : connectedDevices) {
|
||||
@@ -196,32 +205,9 @@ DriverUsb::DriverUsb(const StreamContext& context, bool isInput)
|
||||
return ::android::OK;
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata,
|
||||
StreamContext&& context,
|
||||
const std::vector<MicrophoneInfo>& microphones,
|
||||
std::shared_ptr<StreamIn>* result) {
|
||||
std::shared_ptr<StreamIn> stream =
|
||||
ndk::SharedRefBase::make<StreamInUsb>(sinkMetadata, std::move(context), microphones);
|
||||
if (auto status = initInstance(stream); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
|
||||
const std::vector<MicrophoneInfo>& microphones)
|
||||
: StreamIn(
|
||||
sinkMetadata, std::move(context),
|
||||
[](const StreamContext& ctx) -> DriverInterface* {
|
||||
return new DriverUsb(ctx, true /*isInput*/);
|
||||
},
|
||||
[](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
// The default worker implementation is used.
|
||||
return new StreamInWorker(ctx, driver);
|
||||
},
|
||||
microphones) {}
|
||||
: StreamUsb(sinkMetadata, std::move(context)), StreamIn(microphones) {}
|
||||
|
||||
ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
|
||||
std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
|
||||
@@ -229,37 +215,10 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
// static
|
||||
ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMetadata,
|
||||
StreamContext&& context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo,
|
||||
std::shared_ptr<StreamOut>* result) {
|
||||
if (offloadInfo.has_value()) {
|
||||
LOG(ERROR) << __func__ << ": offload is not supported";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
|
||||
}
|
||||
std::shared_ptr<StreamOut> stream =
|
||||
ndk::SharedRefBase::make<StreamOutUsb>(sourceMetadata, std::move(context), offloadInfo);
|
||||
if (auto status = initInstance(stream); !status.isOk()) {
|
||||
return status;
|
||||
}
|
||||
*result = std::move(stream);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
|
||||
const std::optional<AudioOffloadInfo>& offloadInfo)
|
||||
: StreamOut(
|
||||
sourceMetadata, std::move(context),
|
||||
[](const StreamContext& ctx) -> DriverInterface* {
|
||||
return new DriverUsb(ctx, false /*isInput*/);
|
||||
},
|
||||
[](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
|
||||
// The default worker implementation is used.
|
||||
return new StreamOutWorker(ctx, driver);
|
||||
},
|
||||
offloadInfo) {
|
||||
mChannelCount = getChannelCount(mContext.getChannelLayout());
|
||||
: StreamUsb(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {
|
||||
mChannelCount = getChannelCount(getContext().getChannelLayout());
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
|
||||
@@ -268,7 +227,7 @@ ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channelVolumes) {
|
||||
for (const auto& device : mConnectedDevices) {
|
||||
for (const auto& device : getConnectedDevices()) {
|
||||
if (device.address.getTag() != AudioDeviceAddress::alsa) {
|
||||
LOG(DEBUG) << __func__ << ": skip as the device address is not alsa";
|
||||
continue;
|
||||
|
||||
@@ -2763,6 +2763,7 @@ TEST_P(AudioStreamIn, ActiveMicrophones) {
|
||||
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
|
||||
std::vector<MicrophoneDynamicInfo> activeMics;
|
||||
EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
|
||||
EXPECT_FALSE(activeMics.empty());
|
||||
for (const auto& mic : activeMics) {
|
||||
EXPECT_NE(micInfos.end(),
|
||||
std::find_if(micInfos.begin(), micInfos.end(),
|
||||
|
||||
Reference in New Issue
Block a user