diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 19b2397de6..4e583a4808 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -76,6 +76,7 @@ cc_library { "ModulePrimary.cpp", "SoundDose.cpp", "Stream.cpp", + "StreamSwitcher.cpp", "Telephony.cpp", "alsa/Mixer.cpp", "alsa/ModuleAlsa.cpp", diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp index 740788288a..d2be48c389 100644 --- a/audio/aidl/default/Stream.cpp +++ b/audio/aidl/default/Stream.cpp @@ -670,8 +670,7 @@ ndk::ScopedAStatus StreamCommonImpl::close() { LOG(DEBUG) << __func__ << ": joining the worker thread..."; mWorker->stop(); LOG(DEBUG) << __func__ << ": worker thread joined"; - onClose(); - mWorker->setClosed(); + onClose(mWorker->setClosed()); return ndk::ScopedAStatus::ok(); } else { LOG(ERROR) << __func__ << ": stream was already closed"; diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/StreamSwitcher.cpp new file mode 100644 index 0000000000..956f4138ba --- /dev/null +++ b/audio/aidl/default/StreamSwitcher.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define LOG_TAG "AHAL_StreamSwitcher" + +#include +#include +#include + +#include "core-impl/StreamStub.h" +#include "core-impl/StreamSwitcher.h" + +using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::media::audio::common::AudioDevice; + +namespace aidl::android::hardware::audio::core { + +StreamSwitcher::StreamSwitcher(StreamContext* context, const Metadata& metadata) + : mMetadata(metadata), mStream(new InnerStreamWrapper(context, mMetadata)) {} + +ndk::ScopedAStatus StreamSwitcher::closeCurrentStream(bool validateStreamState) { + if (!mStream) return ndk::ScopedAStatus::ok(); + RETURN_STATUS_IF_ERROR(mStream->prepareToClose()); + RETURN_STATUS_IF_ERROR(mStream->close()); + if (validateStreamState && !isValidClosingStreamState(mStream->getStatePriorToClosing())) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + mStream.reset(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::close() { + if (mStream != nullptr) { + auto status = closeCurrentStream(false /*validateStreamState*/); + // The actual state is irrelevant since only StreamSwitcher cares about it. + onClose(StreamDescriptor::State::STANDBY); + return status; + } + LOG(ERROR) << __func__ << ": stream was already closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); +} + +ndk::ScopedAStatus StreamSwitcher::prepareToClose() { + if (mStream != nullptr) { + return mStream->prepareToClose(); + } + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); +} + +ndk::ScopedAStatus StreamSwitcher::updateHwAvSyncId(int32_t in_hwAvSyncId) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + RETURN_STATUS_IF_ERROR(mStream->updateHwAvSyncId(in_hwAvSyncId)); + mHwAvSyncId = in_hwAvSyncId; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::getVendorParameters(const std::vector& in_ids, + std::vector* _aidl_return) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (mIsStubStream) { + LOG(ERROR) << __func__ << ": the stream is not connected"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + return mStream->getVendorParameters(in_ids, _aidl_return); +} + +ndk::ScopedAStatus StreamSwitcher::setVendorParameters( + const std::vector& in_parameters, bool in_async) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (mIsStubStream) { + mMissedParameters.emplace_back(in_parameters, in_async); + return ndk::ScopedAStatus::ok(); + } + return mStream->setVendorParameters(in_parameters, in_async); +} + +ndk::ScopedAStatus StreamSwitcher::addEffect(const std::shared_ptr& in_effect) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if (!mIsStubStream) { + RETURN_STATUS_IF_ERROR(mStream->addEffect(in_effect)); + } + mEffects.push_back(in_effect); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::removeEffect(const std::shared_ptr& in_effect) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + for (auto it = mEffects.begin(); it != mEffects.end();) { + if ((*it)->asBinder() == in_effect->asBinder()) { + it = mEffects.erase(it); + } else { + ++it; + } + } + return !mIsStubStream ? mStream->removeEffect(in_effect) : ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::getStreamCommonCommon( + std::shared_ptr* _aidl_return) { + if (!mCommon) { + LOG(FATAL) << __func__ << ": the common interface was not created"; + } + *_aidl_return = mCommon.getInstance(); + LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::updateMetadataCommon(const Metadata& metadata) { + if (mStream == nullptr) { + LOG(ERROR) << __func__ << ": stream was closed"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + mMetadata = metadata; + return !mIsStubStream ? mStream->updateMetadataCommon(metadata) : ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus StreamSwitcher::initInstance( + const std::shared_ptr& delegate) { + mCommon = ndk::SharedRefBase::make(delegate); + // The delegate is null because StreamSwitcher handles IStreamCommon methods by itself. + return mStream->initInstance(nullptr); +} + +const StreamContext& StreamSwitcher::getContext() const { + return *mContext; +} + +bool StreamSwitcher::isClosed() const { + return mStream == nullptr || mStream->isClosed(); +} + +const StreamCommonInterface::ConnectedDevices& StreamSwitcher::getConnectedDevices() const { + return mStream->getConnectedDevices(); +} + +ndk::ScopedAStatus StreamSwitcher::setConnectedDevices(const std::vector& devices) { + LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(devices); + if (mStream->getConnectedDevices() == devices) return ndk::ScopedAStatus::ok(); + const DeviceSwitchBehavior behavior = switchCurrentStream(devices); + if (behavior == DeviceSwitchBehavior::UNSUPPORTED_DEVICES) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } else if (behavior == DeviceSwitchBehavior::SWITCH_TO_STUB_STREAM && !devices.empty()) { + // This is an error in the extending class. + LOG(FATAL) << __func__ + << ": switching to stub stream with connected devices is not allowed"; + } + if (behavior == USE_CURRENT_STREAM) { + mIsStubStream = false; + } else { + LOG(DEBUG) << __func__ << ": connected devices changed, switching stream"; + // Two streams can't be opened for the same context, thus we always need to close + // the current one before creating a new one. + RETURN_STATUS_IF_ERROR(closeCurrentStream(true /*validateStreamState*/)); + if (behavior == CREATE_NEW_STREAM) { + mStream = createNewStream(devices, mContext, mMetadata); + mIsStubStream = false; + } else { // SWITCH_TO_STUB_STREAM + mStream.reset(new InnerStreamWrapper(mContext, mMetadata)); + mIsStubStream = true; + } + // The delegate is null because StreamSwitcher handles IStreamCommon methods by itself. + if (ndk::ScopedAStatus status = mStream->initInstance(nullptr); !status.isOk()) { + // Need to close the current failed stream, and report an error. + // Since we can't operate without a stream implementation, put a stub in. + RETURN_STATUS_IF_ERROR(closeCurrentStream(false /*validateStreamState*/)); + mStream.reset(new InnerStreamWrapper(mContext, mMetadata)); + (void)mStream->initInstance(nullptr); + (void)mStream->setConnectedDevices(devices); + return status; + } + } + RETURN_STATUS_IF_ERROR(mStream->setConnectedDevices(devices)); + if (behavior == CREATE_NEW_STREAM) { + // These updates are less critical, only log warning on failure. + if (mHwAvSyncId.has_value()) { + if (auto status = mStream->updateHwAvSyncId(*mHwAvSyncId); !status.isOk()) { + LOG(WARNING) << __func__ << ": could not update HW AV Sync for a new stream: " + << status.getDescription(); + } + } + for (const auto& vndParam : mMissedParameters) { + if (auto status = mStream->setVendorParameters(vndParam.first, vndParam.second); + !status.isOk()) { + LOG(WARNING) << __func__ << ": error while setting parameters for a new stream: " + << status.getDescription(); + } + } + mMissedParameters.clear(); + for (const auto& effect : mEffects) { + if (auto status = mStream->addEffect(effect); !status.isOk()) { + LOG(WARNING) << __func__ << ": error while adding effect for a new stream: " + << status.getDescription(); + } + } + } + return ndk::ScopedAStatus::ok(); +} + +} // 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 0970774263..fa2b760861 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -66,7 +66,8 @@ class StreamContext { DataMQ; // Ensure that this value is not used by any of StreamDescriptor.State enums - static constexpr int32_t STATE_CLOSED = -1; + static constexpr StreamDescriptor::State STATE_CLOSED = + static_cast(-1); struct DebugParameters { // An extra delay for transient states, in ms. @@ -205,10 +206,14 @@ struct DriverInterface { class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic { public: - bool isClosed() const { - return static_cast(mState.load()) == StreamContext::STATE_CLOSED; + bool isClosed() const { return mState == StreamContext::STATE_CLOSED; } + StreamDescriptor::State setClosed() { + auto prevState = mState.exchange(StreamContext::STATE_CLOSED); + if (prevState != StreamContext::STATE_CLOSED) { + mStatePriorToClosing = prevState; + } + return mStatePriorToClosing; } - void setClosed() { mState = static_cast(StreamContext::STATE_CLOSED); } void setIsConnected(bool connected) { mIsConnected = connected; } protected: @@ -231,6 +236,9 @@ class StreamWorkerCommonLogic : public ::android::hardware::audio::common::Strea // which happens on the worker thread only. StreamContext* const mContext; DriverInterface* const mDriver; + // This is the state the stream was in before being closed. It is retrieved by the main + // thread after joining the worker thread. + StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY; // Atomic fields are used both by the main and worker threads. std::atomic mIsConnected = false; static_assert(std::atomic::is_always_lock_free); @@ -252,7 +260,7 @@ struct StreamWorkerInterface { virtual ~StreamWorkerInterface() = default; virtual bool isClosed() const = 0; virtual void setIsConnected(bool isConnected) = 0; - virtual void setClosed() = 0; + virtual StreamDescriptor::State setClosed() = 0; virtual bool start() = 0; virtual void stop() = 0; }; @@ -267,7 +275,7 @@ class StreamWorkerImpl : public StreamWorkerInterface, : WorkerImpl(context, driver) {} bool isClosed() const override { return WorkerImpl::isClosed(); } void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); } - void setClosed() override { WorkerImpl::setClosed(); } + StreamDescriptor::State setClosed() override { return WorkerImpl::setClosed(); } bool start() override { return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_AUDIO); } @@ -459,7 +467,7 @@ class StreamCommonImpl : virtual public StreamCommonInterface, virtual public Dr }; } - virtual void onClose() = 0; + virtual void onClose(StreamDescriptor::State statePriorToClosing) = 0; void stopWorker(); const StreamContext& mContext; diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h index cc44a6e368..b39583ea8b 100644 --- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h +++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h @@ -81,7 +81,7 @@ class StreamInRemoteSubmix final : public StreamIn, public StreamRemoteSubmix { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; @@ -97,7 +97,7 @@ class StreamOutRemoteSubmix final : public StreamOut, public StreamRemoteSubmix offloadInfo); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index d16318107c..a8a3fc4961 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -52,7 +52,7 @@ class StreamInStub final : public StreamIn, public StreamStub { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } }; class StreamOutStub final : public StreamOut, public StreamStub { @@ -64,7 +64,7 @@ class StreamOutStub final : public StreamOut, public StreamStub { offloadInfo); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/include/core-impl/StreamSwitcher.h new file mode 100644 index 0000000000..e462481fc1 --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamSwitcher.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Stream.h" + +namespace aidl::android::hardware::audio::core { + +// 'StreamSwitcher' is implementation of 'StreamCommonInterface' which allows +// dynamically switching the underlying stream implementation based on currently +// connected devices. This is achieved by replacing inheritance from +// 'StreamCommonImpl' with owning an instance of it. StreamSwitcher must be +// extended in order to supply the logic for choosing the stream +// implementation. When there are no connected devices, for instance, upon the +// creation, the StreamSwitcher engages an instance of a stub stream in order to +// keep serving requests coming via 'StreamDescriptor'. +// +// StreamSwitcher implements the 'IStreamCommon' interface directly, with +// necessary delegation to the current stream implementation. While the stub +// stream is engaged, any requests made via 'IStreamCommon' (parameters, effects +// setting, etc) are postponed and only delivered on device connection change +// to the "real" stream implementation provided by the extending class. This is why +// the behavior of StreamSwitcher in the "stub" state is not identical to behavior +// of 'StreamStub'. It can become a full substitute for 'StreamStub' once +// device connection change event occurs and the extending class returns +// 'LEAVE_CURRENT_STREAM' from 'switchCurrentStream' method. +// +// There is a natural limitation that the current stream implementation may only +// be switched when the stream is in the 'STANDBY' state. Thus, when the event +// to switch the stream occurs, the current stream is stopped and joined, and +// its last state is validated. Since the change of the set of connected devices +// normally occurs on patch updates, if the stream was not in standby, this is +// reported to the caller of 'IModule.setAudioPatch' as the 'EX_ILLEGAL_STATE' +// error. +// +// The simplest use case, when the implementor just needs to emulate the legacy HAL API +// behavior of receiving the connected devices upon stream creation, the implementation +// of the extending class can look as follows. We assume that 'StreamLegacy' implementation +// is the one requiring to know connected devices on creation: +// +// class StreamLegacy : public StreamCommonImpl { +// public: +// StreamLegacy(StreamContext* context, const Metadata& metadata, +// const std::vector& devices); +// }; +// +// class StreamOutLegacy final : public StreamOut, public StreamSwitcher { +// public: +// StreamOutLegacy(StreamContext&& context, metatadata etc.) +// private: +// DeviceSwitchBehavior switchCurrentStream(const std::vector&) override { +// // This implementation effectively postpones stream creation until +// // receiving the first call to 'setConnectedDevices' with a non-empty list. +// return isStubStream() ? DeviceSwitchBehavior::CREATE_NEW_STREAM : +// DeviceSwitchBehavior::USE_CURRENT_STREAM; +// } +// std::unique_ptr createNewStream( +// const std::vector& devices, +// StreamContext* context, const Metadata& metadata) override { +// return std::unique_ptr(new InnerStreamWrapper( +// context, metadata, devices)); +// } +// void onClose(StreamDescriptor::State) override { defaultOnClose(); } +// } +// + +class StreamCommonInterfaceEx : virtual public StreamCommonInterface { + public: + virtual StreamDescriptor::State getStatePriorToClosing() const = 0; +}; + +template +class InnerStreamWrapper : public T, public StreamCommonInterfaceEx { + public: + InnerStreamWrapper(StreamContext* context, const Metadata& metadata) : T(context, metadata) {} + StreamDescriptor::State getStatePriorToClosing() const override { return mStatePriorToClosing; } + + private: + // Do not need to do anything on close notification from the inner stream + // because StreamSwitcher handles IStreamCommon::close by itself. + void onClose(StreamDescriptor::State statePriorToClosing) override { + mStatePriorToClosing = statePriorToClosing; + } + + StreamDescriptor::State mStatePriorToClosing = StreamDescriptor::State::STANDBY; +}; + +class StreamSwitcher : virtual public StreamCommonInterface { + public: + StreamSwitcher(StreamContext* context, const Metadata& metadata); + + ndk::ScopedAStatus close() override; + ndk::ScopedAStatus prepareToClose() override; + ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override; + ndk::ScopedAStatus getVendorParameters(const std::vector& in_ids, + std::vector* _aidl_return) override; + ndk::ScopedAStatus setVendorParameters(const std::vector& in_parameters, + bool in_async) override; + ndk::ScopedAStatus addEffect( + const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) + override; + ndk::ScopedAStatus removeEffect( + const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) + override; + + 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; + bool isClosed() const override; + const ConnectedDevices& getConnectedDevices() const override; + ndk::ScopedAStatus setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) + override; + + protected: + // Since switching a stream requires closing down the current stream, StreamSwitcher + // asks the extending class its intent on the connected devices change. + enum DeviceSwitchBehavior { + // Continue using the current stream implementation. If it's the stub implementation, + // StreamSwitcher starts treating the stub stream as a "real" implementation, + // without effectively closing it and starting again. + USE_CURRENT_STREAM, + // This is the normal case when the extending class provides a "real" implementation + // which is not a stub implementation. + CREATE_NEW_STREAM, + // This is the case when the extending class wants to revert back to the initial + // condition of using a stub stream provided by the StreamSwitcher. This behavior + // is only allowed when the list of connected devices is empty. + SWITCH_TO_STUB_STREAM, + // Use when the set of devices is not supported by the extending class. This returns + // 'EX_UNSUPPORTED_OPERATION' from 'setConnectedDevices'. + UNSUPPORTED_DEVICES, + }; + // StreamSwitcher will call these methods from 'setConnectedDevices'. If the switch behavior + // is 'CREATE_NEW_STREAM', the 'createwNewStream' function will be called (with the same + // device vector) for obtaining a new stream implementation, assuming that closing + // the current stream was a success. + virtual DeviceSwitchBehavior switchCurrentStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0; + virtual std::unique_ptr createNewStream( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices, + StreamContext* context, const Metadata& metadata) = 0; + virtual void onClose(StreamDescriptor::State streamPriorToClosing) = 0; + + bool isStubStream() const { return mIsStubStream; } + StreamCommonInterfaceEx* getCurrentStream() const { return mStream.get(); } + + private: + using VndParam = std::pair, bool /*isAsync*/>; + + static constexpr bool isValidClosingStreamState(StreamDescriptor::State state) { + return state == StreamDescriptor::State::STANDBY || state == StreamDescriptor::State::ERROR; + } + + ndk::ScopedAStatus closeCurrentStream(bool validateStreamState); + + // StreamSwitcher does not own the context. + StreamContext* mContext; + Metadata mMetadata; + ChildInterface mCommon; + // The current stream. + std::unique_ptr mStream; + // Indicates whether 'mCurrentStream' is a stub stream implementation + // maintained by StreamSwitcher until the extending class provides a "real" + // implementation. The invariant of this state is that there are no connected + // devices. + bool mIsStubStream = true; + // Storage for the data from commands received via 'IStreamCommon'. + std::optional mHwAvSyncId; + std::vector mMissedParameters; + std::vector> mEffects; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 4fcd0e48a2..74e30ff97b 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -53,7 +53,7 @@ class StreamInUsb final : public StreamIn, public StreamUsb { const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getActiveMicrophones( std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return) override; @@ -68,7 +68,7 @@ class StreamOutUsb final : public StreamOut, public StreamUsb { offloadInfo); private: - void onClose() override { defaultOnClose(); } + void onClose(StreamDescriptor::State) override { defaultOnClose(); } ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override;