audio: Refactor streams implementation
Simplify the experience of implementing stream variants.
Stream class now exposes two interfaces: DriverInterface
and StreamCommonInterface, which represent the two
aspects of its usage: via the FMQ on the worker thread,
and via IStreamCommon Binder interface.
Input/output streams now inherit the concrete stream
variant, and implement interface methods specific for
IStreamIn and IStreamOut.
Added DriverInterface::shutdown method which is called
on the worker thread prior to the exit.
Bug: 282568751
Test: atest VtsHalAudioCoreTargetTest
Change-Id: I5bf8da2f22b27f0e284a41fc30b920d87ac2936c
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 77b0601..73f1293 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -152,6 +152,7 @@
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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
}
}
-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 @@
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 @@
}
} // 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 @@
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 @@
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__;
}
diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp
index 2467320..289afa1 100644
--- a/audio/aidl/default/StreamStub.cpp
+++ b/audio/aidl/default/StreamStub.cpp
@@ -31,33 +31,34 @@
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,16 +80,12 @@
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;
-}
+void StreamStub::shutdown() {}
// static
ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata,
@@ -97,7 +94,7 @@
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()) {
+ if (auto status = stream->initInstance(stream); !status.isOk()) {
return status;
}
*result = std::move(stream);
@@ -106,16 +103,7 @@
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) {}
+ : StreamStub(sinkMetadata, std::move(context)), StreamIn(microphones) {}
// static
ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMetadata,
@@ -124,7 +112,7 @@
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()) {
+ if (auto status = stream->initInstance(stream); !status.isOk()) {
return status;
}
*result = std::move(stream);
@@ -133,15 +121,6 @@
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
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 826b0f1ec..ff5b5a0 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -164,8 +164,8 @@
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.
@@ -175,11 +175,7 @@
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 {
@@ -296,14 +292,20 @@
};
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;
@@ -317,11 +319,30 @@
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:
@@ -372,9 +393,20 @@
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;
@@ -389,46 +421,50 @@
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(); }
+ 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) {
- mWorker->setIsConnected(!devices.empty());
- mConnectedDevices = devices;
- return ndk::ScopedAStatus::fromStatus(mDriver->setConnectedDevices(devices));
- }
- ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
+ 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);
+ };
+ }
- std::shared_ptr<StreamCommon> mCommon;
- ndk::SpAIBinder mCommonBinder;
+ void stopWorker();
+
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)
@@ -437,27 +473,13 @@
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;
@@ -469,17 +491,15 @@
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&
@@ -504,21 +524,10 @@
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;
@@ -540,26 +549,18 @@
: 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();
}
ndk::ScopedAStatus setConnectedDevices(
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
- return std::visit(
- [&](auto&& ws) {
- auto s = ws.lock();
- if (s) return s->setConnectedDevices(devices);
- return ndk::ScopedAStatus::ok();
- },
- 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;
};
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index 436e610..def98b7 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -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 @@
::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,7 +40,7 @@
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,
@@ -58,7 +56,7 @@
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,
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 05d889a..24ea8be 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -30,9 +30,10 @@
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,27 +41,25 @@
::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 {
+class StreamInUsb final : public StreamUsb, public StreamIn {
ndk::ScopedAStatus getActiveMicrophones(
std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
override;
@@ -80,7 +79,7 @@
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
};
-class StreamOutUsb final : public StreamOut {
+class StreamOutUsb final : public StreamUsb, public StreamOut {
public:
static ndk::ScopedAStatus createInstance(
const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index d2ee484..fcac5df 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -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 @@
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 @@
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::INVALID_OPERATION;
+ 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 @@
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 @@
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) {
@@ -203,7 +212,7 @@
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()) {
+ if (auto status = stream->initInstance(stream); !status.isOk()) {
return status;
}
*result = std::move(stream);
@@ -212,16 +221,7 @@
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) {
@@ -240,7 +240,7 @@
}
std::shared_ptr<StreamOut> stream =
ndk::SharedRefBase::make<StreamOutUsb>(sourceMetadata, std::move(context), offloadInfo);
- if (auto status = initInstance(stream); !status.isOk()) {
+ if (auto status = stream->initInstance(stream); !status.isOk()) {
return status;
}
*result = std::move(stream);
@@ -249,17 +249,8 @@
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 +259,7 @@
}
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;