From efe980bb4478b91489982deeb30b2106f3fc29dd Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Wed, 21 Jun 2023 15:20:31 -0700 Subject: [PATCH] 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 Merged-In: I5bf8da2f22b27f0e284a41fc30b920d87ac2936c Change-Id: I5bf8da2f22b27f0e284a41fc30b920d87ac2936c (cherry picked from commit d5554cfae2a2b7af14c770f4f2f9aded76f64ea1) --- audio/aidl/default/Stream.cpp | 88 +++----- audio/aidl/default/StreamStub.cpp | 51 ++--- audio/aidl/default/include/core-impl/Stream.h | 191 +++++++++--------- .../default/include/core-impl/StreamStub.h | 14 +- .../default/include/core-impl/StreamUsb.h | 23 +-- audio/aidl/default/usb/StreamUsb.cpp | 77 ++++--- 6 files changed, 192 insertions(+), 252 deletions(-) diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 77b06011c6..73f1293007 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -152,6 +152,7 @@ StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() { case Tag::halReservedExit: if (const int32_t cookie = command.get(); 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(); 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 -StreamCommonImpl::~StreamCommonImpl() { +StreamCommonImpl::~StreamCommonImpl() { if (!isClosed()) { LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak"; stopWorker(); @@ -576,19 +577,16 @@ StreamCommonImpl::~StreamCommonImpl() { } } -template -void StreamCommonImpl::createStreamCommon( +ndk::ScopedAStatus StreamCommonImpl::initInstance( const std::shared_ptr& delegate) { - if (mCommon != nullptr) { - LOG(FATAL) << __func__ << ": attempting to create the common interface twice"; - } - mCommon = ndk::SharedRefBase::make(delegate); + mCommon = ndk::SharedRefBase::make(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 -ndk::ScopedAStatus StreamCommonImpl::getStreamCommon( +ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon( std::shared_ptr* _aidl_return) { if (mCommon == nullptr) { LOG(FATAL) << __func__ << ": the common interface was not created"; @@ -598,30 +596,26 @@ ndk::ScopedAStatus StreamCommonImpl::getStreamCommon( return ndk::ScopedAStatus::ok(); } -template -ndk::ScopedAStatus StreamCommonImpl::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 -ndk::ScopedAStatus StreamCommonImpl::getVendorParameters( +ndk::ScopedAStatus StreamCommonImpl::getVendorParameters( const std::vector& in_ids, std::vector* _aidl_return) { LOG(DEBUG) << __func__ << ": id count: " << in_ids.size(); (void)_aidl_return; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::setVendorParameters( +ndk::ScopedAStatus StreamCommonImpl::setVendorParameters( const std::vector& in_parameters, bool in_async) { LOG(DEBUG) << __func__ << ": parameters count " << in_parameters.size() << ", async: " << in_async; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::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::addEffect( return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::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::removeEffect( return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -template -ndk::ScopedAStatus StreamCommonImpl::close() { +ndk::ScopedAStatus StreamCommonImpl::close() { LOG(DEBUG) << __func__; if (!isClosed()) { stopWorker(); @@ -659,8 +651,7 @@ ndk::ScopedAStatus StreamCommonImpl::close() { } } -template -ndk::ScopedAStatus StreamCommonImpl::prepareToClose() { +ndk::ScopedAStatus StreamCommonImpl::prepareToClose() { LOG(DEBUG) << __func__; if (!isClosed()) { return ndk::ScopedAStatus::ok(); @@ -669,8 +660,7 @@ ndk::ScopedAStatus StreamCommonImpl::prepareToClose() { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } -template -void StreamCommonImpl::stopWorker() { +void StreamCommonImpl::stopWorker() { if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) { LOG(DEBUG) << __func__ << ": asking the worker to exit..."; auto cmd = StreamDescriptor::Command::make( @@ -686,10 +676,12 @@ void StreamCommonImpl::stopWorker() { } } -template -ndk::ScopedAStatus StreamCommonImpl::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::updateMetadata(const Metadata& me return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } -// static -ndk::ScopedAStatus StreamIn::initInstance(const std::shared_ptr& 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 transformMicrophones( } } // namespace -StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext&& context, - const DriverInterface::CreateInstance& createDriver, - const StreamWorkerInterface::CreateInstance& createWorker, - const std::vector& microphones) - : StreamCommonImpl(sinkMetadata, std::move(context), createDriver, createWorker), - mMicrophones(transformMicrophones(microphones)) { +StreamIn::StreamIn(const std::vector& microphones) + : mMicrophones(transformMicrophones(microphones)) { LOG(DEBUG) << __func__; } @@ -729,9 +715,9 @@ ndk::ScopedAStatus StreamIn::getActiveMicrophones( std::vector* _aidl_return) { std::vector result; std::vector 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& in_channelGains return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } -// static -ndk::ScopedAStatus StreamOut::initInstance(const std::shared_ptr& 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& offloadInfo) - : StreamCommonImpl(sourceMetadata, std::move(context), createDriver, - createWorker), - mOffloadInfo(offloadInfo) { +StreamOut::StreamOut(const std::optional& offloadInfo) + : mOffloadInfo(offloadInfo) { LOG(DEBUG) << __func__; } diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp index 2467320f0c..289afa1c85 100644 --- a/audio/aidl/default/StreamStub.cpp +++ b/audio/aidl/default/StreamStub.cpp @@ -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,16 +80,12 @@ 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& connectedDevices __unused) { - usleep(500); - return ::android::OK; -} +void StreamStub::shutdown() {} // static ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata, @@ -97,7 +94,7 @@ ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata std::shared_ptr* result) { std::shared_ptr stream = ndk::SharedRefBase::make(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 @@ ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata StreamInStub::StreamInStub(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& 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 @@ ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMet std::shared_ptr* result) { std::shared_ptr stream = ndk::SharedRefBase::make( 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 @@ ndk::ScopedAStatus StreamOutStub::createInstance(const SourceMetadata& sourceMet StreamOutStub::StreamOutStub(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& 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 826b0f1ec9..ff5b5a0ab1 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -164,8 +164,8 @@ class StreamContext { DebugParameters mDebugParameters; }; +// This interface provides operations of the stream which are executed on the worker thread. struct DriverInterface { - using CreateInstance = std::function; 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 @@ 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 { @@ -296,14 +292,20 @@ class StreamOutWorkerLogic : public StreamWorkerCommonLogic { }; using StreamOutWorker = StreamWorkerImpl; -// 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 @@ 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* _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& 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& delegate) + explicit StreamCommonDelegator(const std::shared_ptr& delegate) : mDelegate(delegate) {} private: @@ -372,9 +393,20 @@ class StreamCommon : public BnStreamCommon { std::weak_ptr mDelegate; }; -template -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 @@ class StreamCommonImpl : public StreamCommonInterface { const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) override; - ndk::ScopedAStatus getStreamCommon(std::shared_ptr* _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* _aidl_return) override; + ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override; + + ndk::ScopedAStatus initInstance( + const std::shared_ptr& 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& 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 mCommon; - ndk::SpAIBinder mCommonBinder; Metadata mMetadata; StreamContext mContext; - std::unique_ptr mDriver; std::unique_ptr mWorker; - std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices; + std::shared_ptr 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* _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 @@ 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* _aidl_return) override; ndk::ScopedAStatus setHwGain(const std::vector& in_channelGains) override; - protected: friend class ndk::SharedRefBase; - static ndk::ScopedAStatus initInstance(const std::shared_ptr& 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& 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 @@ class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::commo std::shared_ptr* 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* _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 @@ 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& myPtr) { - StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata>:: - createStreamCommon(myPtr); - } - - protected: friend class ndk::SharedRefBase; - static ndk::ScopedAStatus initInstance(const std::shared_ptr& 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 @@ 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(); } 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> mStream; + std::weak_ptr 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 436e610ccf..def98b7986 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 @@ 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,7 +40,7 @@ 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, @@ -58,7 +56,7 @@ 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, diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 05d889a713..24ea8be51c 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -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,27 +41,25 @@ 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 mConfig; const bool mIsInput; - // Cached device addresses for connected devices. - std::vector<::aidl::android::media::audio::common::AudioDeviceAddress> mConnectedDevices - GUARDED_BY(mLock); std::vector> 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 @@ class StreamInUsb final : public StreamIn { 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 d2ee484c2d..fcac5dfc49 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -18,6 +18,7 @@ #include #include +#include #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& 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 @@ 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 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> alsaDeviceProxies; for (const auto& device : connectedDevices) { @@ -203,7 +212,7 @@ ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata, std::shared_ptr* result) { std::shared_ptr stream = ndk::SharedRefBase::make(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 @@ ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata, StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context, const std::vector& 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* _aidl_return __unused) { @@ -240,7 +240,7 @@ ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMeta } std::shared_ptr stream = ndk::SharedRefBase::make(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 @@ ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMeta StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& 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* _aidl_return) { @@ -268,7 +259,7 @@ ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { } ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& 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;