Loading media/libaudiohal/impl/DeviceHalAidl.cpp +191 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <algorithm> #include <forward_list> #include <aidl/android/hardware/audio/core/BnStreamCallback.h> #include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h> #include <aidl/android/hardware/audio/core/StreamDescriptor.h> #include <error/expected_utils.h> #include <media/AidlConversionCppNdk.h> Loading @@ -37,6 +39,7 @@ using aidl::android::media::audio::common::AudioDevice; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioInputFlags; using aidl::android::media::audio::common::AudioIoFlags; using aidl::android::media::audio::common::AudioLatencyMode; using aidl::android::media::audio::common::AudioMode; using aidl::android::media::audio::common::AudioOutputFlags; using aidl::android::media::audio::common::AudioPort; Loading Loading @@ -298,6 +301,123 @@ status_t DeviceHalAidl::prepareToOpenStream( return OK; } namespace { class StreamCallbackBase { protected: explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {} public: void* getCookie() const { return mCookie; } void setCookie(void* cookie) { mCookie = cookie; } sp<CallbackBroker> getBroker() const { if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote(); return nullptr; } private: const wp<CallbackBroker> mBroker; std::atomic<void*> mCookie; }; template<class C> class StreamCallbackBaseHelper { protected: explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {} sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie); using CbRef = const sp<C>&; ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) { if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb); return ndk::ScopedAStatus::ok(); } private: const StreamCallbackBase& mBase; }; template<> sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb( const sp<CallbackBroker>& broker, void* cookie) { if (broker != nullptr) return broker->getStreamOutCallback(cookie); return nullptr; } template<> sp<StreamOutHalInterfaceEventCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb( const sp<CallbackBroker>& broker, void* cookie) { if (broker != nullptr) return broker->getStreamOutEventCallback(cookie); return nullptr; } template<> sp<StreamOutHalInterfaceLatencyModeCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb( const sp<CallbackBroker>& broker, void* cookie) { if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie); return nullptr; } /* Note on the callback ownership. In the Binder ownership model, the server implementation is kept alive as long as there is any client (proxy object) alive. This is done by incrementing the refcount of the server-side object by the Binder framework. When it detects that the last client is gone, it decrements the refcount back. Thus, it is not needed to keep any references to StreamCallback on our side (after we have sent an instance to the client), because we are the server-side. The callback object will be kept alive as long as the HAL server holds a strong ref to IStreamCallback proxy. */ class OutputStreamCallbackAidl : public StreamCallbackBase, public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>, public ::aidl::android::hardware::audio::core::BnStreamCallback { public: explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker) : StreamCallbackBase(broker), StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>( *static_cast<StreamCallbackBase*>(this)) {} ndk::ScopedAStatus onTransferReady() override { return runCb([](CbRef cb) { cb->onWriteReady(); }); } ndk::ScopedAStatus onError() override { return runCb([](CbRef cb) { cb->onError(); }); } ndk::ScopedAStatus onDrainReady() override { return runCb([](CbRef cb) { cb->onDrainReady(); }); } }; class OutputStreamEventCallbackAidl : public StreamCallbackBase, public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>, public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>, public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback { public: explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker) : StreamCallbackBase(broker), StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>( *static_cast<StreamCallbackBase*>(this)), StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>( *static_cast<StreamCallbackBase*>(this)) {} ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override { std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end()); return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb( [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); }); } ndk::ScopedAStatus onRecommendedLatencyModeChanged( const std::vector<AudioLatencyMode>& in_modes) override { auto halModes = VALUE_OR_FATAL( ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>( in_modes, ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t)); return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb( [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); }); } }; } // namespace status_t DeviceHalAidl::openOutputStream( audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags, struct audio_config* config, Loading Loading @@ -325,8 +445,19 @@ status_t DeviceHalAidl::openOutputStream( &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency)); ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args; args.portConfigId = mixPortConfig.id; const bool isOffload = isBitPositionFlagSet( aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD); std::shared_ptr<OutputStreamCallbackAidl> streamCb; if (isOffload) { streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this); } auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this); if (isOffload) { args.offloadInfo = aidlConfig.offloadInfo; args.callback = streamCb; } args.bufferSizeFrames = aidlConfig.frameCount; args.eventCallback = eventCb; ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret; RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret))); StreamContextAidl context(ret.desc); Loading @@ -336,7 +467,14 @@ status_t DeviceHalAidl::openOutputStream( return NO_INIT; } *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency, std::move(ret.stream)); std::move(ret.stream), this /*callbackBroker*/); void* cbCookie = (*outStream).get(); { std::lock_guard l(mLock); mCallbacks.emplace(cbCookie, Callbacks{}); } if (streamCb) streamCb->setCookie(cbCookie); eventCb->setCookie(cbCookie); cleanups.disarmAll(); return OK; } Loading Loading @@ -862,4 +1000,55 @@ void DeviceHalAidl::resetPortConfig(int32_t portConfigId) { ALOGE("%s: port config id %d not found", __func__, portConfigId); } void DeviceHalAidl::clearCallbacks(void* cookie) { std::lock_guard l(mLock); mCallbacks.erase(cookie); } sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) { return getCallbackImpl(cookie, &Callbacks::out); } void DeviceHalAidl::setStreamOutCallback( void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) { setCallbackImpl(cookie, &Callbacks::out, cb); } sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback( void* cookie) { return getCallbackImpl(cookie, &Callbacks::event); } void DeviceHalAidl::setStreamOutEventCallback( void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) { setCallbackImpl(cookie, &Callbacks::event, cb); } sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback( void* cookie) { return getCallbackImpl(cookie, &Callbacks::latency); } void DeviceHalAidl::setStreamOutLatencyModeCallback( void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) { setCallbackImpl(cookie, &Callbacks::latency, cb); } template<class C> sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) { std::lock_guard l(mLock); if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) { return ((it->second).*field).promote(); } return nullptr; } template<class C> void DeviceHalAidl::setCallbackImpl( void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) { std::lock_guard l(mLock); if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) { (it->second).*field = cb; } } } // namespace android media/libaudiohal/impl/DeviceHalAidl.h +54 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <vector> #include <aidl/android/hardware/audio/core/BpModule.h> #include <android-base/thread_annotations.h> #include <media/audiohal/DeviceHalInterface.h> #include <media/audiohal/EffectHalInterface.h> Loading @@ -28,7 +29,35 @@ namespace android { class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { class StreamOutHalInterfaceCallback; class StreamOutHalInterfaceEventCallback; class StreamOutHalInterfaceLatencyModeCallback; // The role of the broker is to connect AIDL callback interface implementations // with StreamOut callback implementations. Since AIDL requires all callbacks // to be provided upfront, while libaudiohal interfaces allow late registration, // there is a need to coordinate the matching process. class CallbackBroker : public virtual RefBase { public: virtual ~CallbackBroker() = default; // The cookie is always the stream instance pointer. We don't use weak pointers to avoid extra // costs on reference counting. The stream cleans up related entries on destruction. Since // access to the callbacks map is synchronized, the possibility for pointer aliasing due to // allocation of a new stream at the address of previously deleted stream is avoided. virtual void clearCallbacks(void* cookie) = 0; virtual sp<StreamOutHalInterfaceCallback> getStreamOutCallback(void* cookie) = 0; virtual void setStreamOutCallback(void* cookie, const sp<StreamOutHalInterfaceCallback>&) = 0; virtual sp<StreamOutHalInterfaceEventCallback> getStreamOutEventCallback(void* cookie) = 0; virtual void setStreamOutEventCallback(void* cookie, const sp<StreamOutHalInterfaceEventCallback>&) = 0; virtual sp<StreamOutHalInterfaceLatencyModeCallback> getStreamOutLatencyModeCallback( void* cookie) = 0; virtual void setStreamOutLatencyModeCallback( void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>&) = 0; }; class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, public CallbackBroker { public: // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t. status_t getSupportedDevices(uint32_t *devices) override; Loading Loading @@ -123,6 +152,12 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { private: friend class sp<DeviceHalAidl>; struct Callbacks { // No need to use `atomic_wp` because access is serialized. wp<StreamOutHalInterfaceCallback> out; wp<StreamOutHalInterfaceEventCallback> event; wp<StreamOutHalInterfaceLatencyModeCallback> latency; }; using Patches = std::map<int32_t /*patch ID*/, ::aidl::android::hardware::audio::core::AudioPatch>; using PortConfigs = std::map<int32_t /*port config ID*/, Loading Loading @@ -191,6 +226,21 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { void resetPatch(int32_t patchId); void resetPortConfig(int32_t portConfigId); // CallbackBroker implementation void clearCallbacks(void* cookie) override; sp<StreamOutHalInterfaceCallback> getStreamOutCallback(void* cookie) override; void setStreamOutCallback(void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) override; sp<StreamOutHalInterfaceEventCallback> getStreamOutEventCallback(void* cookie) override; void setStreamOutEventCallback(void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) override; sp<StreamOutHalInterfaceLatencyModeCallback> getStreamOutLatencyModeCallback( void* cookie) override; void setStreamOutLatencyModeCallback( void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) override; // Implementation helpers. template<class C> sp<C> getCallbackImpl(void* cookie, wp<C> Callbacks::* field); template<class C> void setCallbackImpl(void* cookie, wp<C> Callbacks::* field, const sp<C>& cb); const std::string mInstance; const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule; Ports mPorts; Loading @@ -199,6 +249,8 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { PortConfigs mPortConfigs; Patches mPatches; std::map<audio_patch_handle_t, int32_t /*patch ID*/> mFwkHandles; std::mutex mLock; std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock); }; } // namespace android media/libaudiohal/impl/StreamHalAidl.cpp +26 −85 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ #include <algorithm> #include <cstdint> #include <aidl/android/hardware/audio/core/BnStreamCallback.h> #include <audio_utils/clock.h> #include <mediautils/TimeCheck.h> #include <utils/Log.h> Loading Loading @@ -448,43 +447,18 @@ status_t StreamHalAidl::updateCountersIfNeeded( return OK; } namespace { /* Notes on callback ownership. This is how Binder ownership model looks like. The server implementation is owned by Binder framework (via sp<>). Proxies are owned by clients. When the last proxy disappears, Binder framework releases the server impl. Thus, it is not needed to keep any references to StreamCallback (this is the server impl) -- it will live as long as HAL server holds a strong ref to IStreamCallback proxy. The callback only keeps a weak reference to the stream. The stream is owned by AudioFlinger. */ class StreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback { ndk::ScopedAStatus onTransferReady() override { return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus onError() override { return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus onDrainReady() override { return ndk::ScopedAStatus::ok(); } }; } // namespace StreamOutHalAidl::StreamOutHalAidl( const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency, const std::shared_ptr<IStreamOut>& stream) const std::shared_ptr<IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker) : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency, std::move(context), getStreamCommon(stream)), mStream(stream) {} mStream(stream), mCallbackBroker(callbackBroker) {} StreamOutHalAidl::~StreamOutHalAidl() { if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->clearCallbacks(this); } } status_t StreamOutHalAidl::getLatency(uint32_t *latency) { return StreamHalAidl::getLatency(latency); Loading Loading @@ -529,10 +503,18 @@ status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) { return INVALID_OPERATION; } status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback __unused) { status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { TIME_CHECK(); if (!mStream) return NO_INIT; ALOGE("%s not implemented yet", __func__); if (auto broker = mCallbackBroker.promote(); broker != nullptr) { if (auto cb = callback.promote(); cb != nullptr) { broker->setStreamOutCallback(this, cb); } else { // It is expected that the framework never passes a null pointer. // In the AIDL model callbacks can't be "unregistered". LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__); } } return OK; } Loading Loading @@ -639,23 +621,15 @@ status_t StreamOutHalAidl::setPlaybackRateParameters( } status_t StreamOutHalAidl::setEventCallback( const sp<StreamOutHalInterfaceEventCallback>& callback __unused) { const sp<StreamOutHalInterfaceEventCallback>& callback) { TIME_CHECK(); if (!mStream) return NO_INIT; ALOGE("%s not implemented yet", __func__); if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutEventCallback(this, callback); } return OK; } namespace { struct StreamOutEventCallback { StreamOutEventCallback(const wp<StreamOutHalAidl>& stream) : mStream(stream) {} private: wp<StreamOutHalAidl> mStream; }; } // namespace status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) { TIME_CHECK(); if (!mStream) return NO_INIT; Loading @@ -672,48 +646,15 @@ status_t StreamOutHalAidl::getRecommendedLatencyModes( }; status_t StreamOutHalAidl::setLatencyModeCallback( const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) { const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) { TIME_CHECK(); if (!mStream) return NO_INIT; ALOGE("%s not implemented yet", __func__); if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutLatencyModeCallback(this, callback); } return OK; }; void StreamOutHalAidl::onWriteReady() { sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); if (callback == 0) return; ALOGV("asyncCallback onWriteReady"); callback->onWriteReady(); } void StreamOutHalAidl::onDrainReady() { sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); if (callback == 0) return; ALOGV("asyncCallback onDrainReady"); callback->onDrainReady(); } void StreamOutHalAidl::onError() { sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); if (callback == 0) return; ALOGV("asyncCallback onError"); callback->onError(); } void StreamOutHalAidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs __unused) { sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote(); if (callback == nullptr) return; ALOGV("asyncCodecFormatCallback %s", __func__); callback->onCodecFormatChanged(metadataBs); } void StreamOutHalAidl::onRecommendedLatencyModeChanged( const std::vector<audio_latency_mode_t>& modes __unused) { sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote(); if (callback == nullptr) return; callback->onRecommendedLatencyModeChanged(modes); } status_t StreamOutHalAidl::exit() { return StreamHalAidl::exit(); } Loading media/libaudiohal/impl/StreamHalAidl.h +6 −17 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <fmq/AidlMessageQueue.h> #include <media/audiohal/EffectHalInterface.h> #include <media/audiohal/StreamHalInterface.h> #include <mediautils/Synchronization.h> #include "ConversionHelperAidl.h" #include "StreamPowerLog.h" Loading Loading @@ -221,6 +220,8 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper std::atomic<pid_t> mWorkerTid = -1; }; class CallbackBroker; class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { public: // Return the audio hardware driver estimated latency in milliseconds. Loading Loading @@ -294,33 +295,21 @@ class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { status_t setLatencyModeCallback( const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) override; void onRecommendedLatencyModeChanged(const std::vector<audio_latency_mode_t>& modes); status_t exit() override; void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs); // Methods used by StreamOutCallback (). // FIXME: Consider the required visibility. void onWriteReady(); void onDrainReady(); void onError(); private: friend class sp<StreamOutHalAidl>; mediautils::atomic_wp<StreamOutHalInterfaceCallback> mCallback; mediautils::atomic_wp<StreamOutHalInterfaceEventCallback> mEventCallback; mediautils::atomic_wp<StreamOutHalInterfaceLatencyModeCallback> mLatencyModeCallback; const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut> mStream; const wp<CallbackBroker> mCallbackBroker; // Can not be constructed directly by clients. StreamOutHalAidl( const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency, const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream); const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker); ~StreamOutHalAidl() override = default; ~StreamOutHalAidl() override; }; class StreamInHalAidl : public StreamInHalInterface, public StreamHalAidl { Loading media/libaudiohal/include/media/audiohal/DeviceHalInterface.h +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ namespace android { class StreamInHalInterface; class StreamOutHalInterface; class DeviceHalInterface : public RefBase class DeviceHalInterface : public virtual RefBase { public: // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t. Loading Loading
media/libaudiohal/impl/DeviceHalAidl.cpp +191 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <algorithm> #include <forward_list> #include <aidl/android/hardware/audio/core/BnStreamCallback.h> #include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h> #include <aidl/android/hardware/audio/core/StreamDescriptor.h> #include <error/expected_utils.h> #include <media/AidlConversionCppNdk.h> Loading @@ -37,6 +39,7 @@ using aidl::android::media::audio::common::AudioDevice; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioInputFlags; using aidl::android::media::audio::common::AudioIoFlags; using aidl::android::media::audio::common::AudioLatencyMode; using aidl::android::media::audio::common::AudioMode; using aidl::android::media::audio::common::AudioOutputFlags; using aidl::android::media::audio::common::AudioPort; Loading Loading @@ -298,6 +301,123 @@ status_t DeviceHalAidl::prepareToOpenStream( return OK; } namespace { class StreamCallbackBase { protected: explicit StreamCallbackBase(const sp<CallbackBroker>& broker) : mBroker(broker) {} public: void* getCookie() const { return mCookie; } void setCookie(void* cookie) { mCookie = cookie; } sp<CallbackBroker> getBroker() const { if (void* cookie = mCookie; cookie != nullptr) return mBroker.promote(); return nullptr; } private: const wp<CallbackBroker> mBroker; std::atomic<void*> mCookie; }; template<class C> class StreamCallbackBaseHelper { protected: explicit StreamCallbackBaseHelper(const StreamCallbackBase& base) : mBase(base) {} sp<C> getCb(const sp<CallbackBroker>& broker, void* cookie); using CbRef = const sp<C>&; ndk::ScopedAStatus runCb(const std::function<void(CbRef cb)>& f) { if (auto cb = getCb(mBase.getBroker(), mBase.getCookie()); cb != nullptr) f(cb); return ndk::ScopedAStatus::ok(); } private: const StreamCallbackBase& mBase; }; template<> sp<StreamOutHalInterfaceCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>::getCb( const sp<CallbackBroker>& broker, void* cookie) { if (broker != nullptr) return broker->getStreamOutCallback(cookie); return nullptr; } template<> sp<StreamOutHalInterfaceEventCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::getCb( const sp<CallbackBroker>& broker, void* cookie) { if (broker != nullptr) return broker->getStreamOutEventCallback(cookie); return nullptr; } template<> sp<StreamOutHalInterfaceLatencyModeCallback> StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::getCb( const sp<CallbackBroker>& broker, void* cookie) { if (broker != nullptr) return broker->getStreamOutLatencyModeCallback(cookie); return nullptr; } /* Note on the callback ownership. In the Binder ownership model, the server implementation is kept alive as long as there is any client (proxy object) alive. This is done by incrementing the refcount of the server-side object by the Binder framework. When it detects that the last client is gone, it decrements the refcount back. Thus, it is not needed to keep any references to StreamCallback on our side (after we have sent an instance to the client), because we are the server-side. The callback object will be kept alive as long as the HAL server holds a strong ref to IStreamCallback proxy. */ class OutputStreamCallbackAidl : public StreamCallbackBase, public StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>, public ::aidl::android::hardware::audio::core::BnStreamCallback { public: explicit OutputStreamCallbackAidl(const sp<CallbackBroker>& broker) : StreamCallbackBase(broker), StreamCallbackBaseHelper<StreamOutHalInterfaceCallback>( *static_cast<StreamCallbackBase*>(this)) {} ndk::ScopedAStatus onTransferReady() override { return runCb([](CbRef cb) { cb->onWriteReady(); }); } ndk::ScopedAStatus onError() override { return runCb([](CbRef cb) { cb->onError(); }); } ndk::ScopedAStatus onDrainReady() override { return runCb([](CbRef cb) { cb->onDrainReady(); }); } }; class OutputStreamEventCallbackAidl : public StreamCallbackBase, public StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>, public StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>, public ::aidl::android::hardware::audio::core::BnStreamOutEventCallback { public: explicit OutputStreamEventCallbackAidl(const sp<CallbackBroker>& broker) : StreamCallbackBase(broker), StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>( *static_cast<StreamCallbackBase*>(this)), StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>( *static_cast<StreamCallbackBase*>(this)) {} ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override { std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end()); return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb( [&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); }); } ndk::ScopedAStatus onRecommendedLatencyModeChanged( const std::vector<AudioLatencyMode>& in_modes) override { auto halModes = VALUE_OR_FATAL( ::aidl::android::convertContainer<std::vector<audio_latency_mode_t>>( in_modes, ::aidl::android::aidl2legacy_AudioLatencyMode_audio_latency_mode_t)); return StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>::runCb( [&halModes](auto cb) { cb->onRecommendedLatencyModeChanged(halModes); }); } }; } // namespace status_t DeviceHalAidl::openOutputStream( audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags, struct audio_config* config, Loading Loading @@ -325,8 +445,19 @@ status_t DeviceHalAidl::openOutputStream( &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency)); ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args; args.portConfigId = mixPortConfig.id; const bool isOffload = isBitPositionFlagSet( aidlOutputFlags, AudioOutputFlags::COMPRESS_OFFLOAD); std::shared_ptr<OutputStreamCallbackAidl> streamCb; if (isOffload) { streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this); } auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this); if (isOffload) { args.offloadInfo = aidlConfig.offloadInfo; args.callback = streamCb; } args.bufferSizeFrames = aidlConfig.frameCount; args.eventCallback = eventCb; ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret; RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret))); StreamContextAidl context(ret.desc); Loading @@ -336,7 +467,14 @@ status_t DeviceHalAidl::openOutputStream( return NO_INIT; } *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency, std::move(ret.stream)); std::move(ret.stream), this /*callbackBroker*/); void* cbCookie = (*outStream).get(); { std::lock_guard l(mLock); mCallbacks.emplace(cbCookie, Callbacks{}); } if (streamCb) streamCb->setCookie(cbCookie); eventCb->setCookie(cbCookie); cleanups.disarmAll(); return OK; } Loading Loading @@ -862,4 +1000,55 @@ void DeviceHalAidl::resetPortConfig(int32_t portConfigId) { ALOGE("%s: port config id %d not found", __func__, portConfigId); } void DeviceHalAidl::clearCallbacks(void* cookie) { std::lock_guard l(mLock); mCallbacks.erase(cookie); } sp<StreamOutHalInterfaceCallback> DeviceHalAidl::getStreamOutCallback(void* cookie) { return getCallbackImpl(cookie, &Callbacks::out); } void DeviceHalAidl::setStreamOutCallback( void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) { setCallbackImpl(cookie, &Callbacks::out, cb); } sp<StreamOutHalInterfaceEventCallback> DeviceHalAidl::getStreamOutEventCallback( void* cookie) { return getCallbackImpl(cookie, &Callbacks::event); } void DeviceHalAidl::setStreamOutEventCallback( void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) { setCallbackImpl(cookie, &Callbacks::event, cb); } sp<StreamOutHalInterfaceLatencyModeCallback> DeviceHalAidl::getStreamOutLatencyModeCallback( void* cookie) { return getCallbackImpl(cookie, &Callbacks::latency); } void DeviceHalAidl::setStreamOutLatencyModeCallback( void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) { setCallbackImpl(cookie, &Callbacks::latency, cb); } template<class C> sp<C> DeviceHalAidl::getCallbackImpl(void* cookie, wp<C> DeviceHalAidl::Callbacks::* field) { std::lock_guard l(mLock); if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) { return ((it->second).*field).promote(); } return nullptr; } template<class C> void DeviceHalAidl::setCallbackImpl( void* cookie, wp<C> DeviceHalAidl::Callbacks::* field, const sp<C>& cb) { std::lock_guard l(mLock); if (auto it = mCallbacks.find(cookie); it != mCallbacks.end()) { (it->second).*field = cb; } } } // namespace android
media/libaudiohal/impl/DeviceHalAidl.h +54 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <vector> #include <aidl/android/hardware/audio/core/BpModule.h> #include <android-base/thread_annotations.h> #include <media/audiohal/DeviceHalInterface.h> #include <media/audiohal/EffectHalInterface.h> Loading @@ -28,7 +29,35 @@ namespace android { class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { class StreamOutHalInterfaceCallback; class StreamOutHalInterfaceEventCallback; class StreamOutHalInterfaceLatencyModeCallback; // The role of the broker is to connect AIDL callback interface implementations // with StreamOut callback implementations. Since AIDL requires all callbacks // to be provided upfront, while libaudiohal interfaces allow late registration, // there is a need to coordinate the matching process. class CallbackBroker : public virtual RefBase { public: virtual ~CallbackBroker() = default; // The cookie is always the stream instance pointer. We don't use weak pointers to avoid extra // costs on reference counting. The stream cleans up related entries on destruction. Since // access to the callbacks map is synchronized, the possibility for pointer aliasing due to // allocation of a new stream at the address of previously deleted stream is avoided. virtual void clearCallbacks(void* cookie) = 0; virtual sp<StreamOutHalInterfaceCallback> getStreamOutCallback(void* cookie) = 0; virtual void setStreamOutCallback(void* cookie, const sp<StreamOutHalInterfaceCallback>&) = 0; virtual sp<StreamOutHalInterfaceEventCallback> getStreamOutEventCallback(void* cookie) = 0; virtual void setStreamOutEventCallback(void* cookie, const sp<StreamOutHalInterfaceEventCallback>&) = 0; virtual sp<StreamOutHalInterfaceLatencyModeCallback> getStreamOutLatencyModeCallback( void* cookie) = 0; virtual void setStreamOutLatencyModeCallback( void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>&) = 0; }; class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, public CallbackBroker { public: // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t. status_t getSupportedDevices(uint32_t *devices) override; Loading Loading @@ -123,6 +152,12 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { private: friend class sp<DeviceHalAidl>; struct Callbacks { // No need to use `atomic_wp` because access is serialized. wp<StreamOutHalInterfaceCallback> out; wp<StreamOutHalInterfaceEventCallback> event; wp<StreamOutHalInterfaceLatencyModeCallback> latency; }; using Patches = std::map<int32_t /*patch ID*/, ::aidl::android::hardware::audio::core::AudioPatch>; using PortConfigs = std::map<int32_t /*port config ID*/, Loading Loading @@ -191,6 +226,21 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { void resetPatch(int32_t patchId); void resetPortConfig(int32_t portConfigId); // CallbackBroker implementation void clearCallbacks(void* cookie) override; sp<StreamOutHalInterfaceCallback> getStreamOutCallback(void* cookie) override; void setStreamOutCallback(void* cookie, const sp<StreamOutHalInterfaceCallback>& cb) override; sp<StreamOutHalInterfaceEventCallback> getStreamOutEventCallback(void* cookie) override; void setStreamOutEventCallback(void* cookie, const sp<StreamOutHalInterfaceEventCallback>& cb) override; sp<StreamOutHalInterfaceLatencyModeCallback> getStreamOutLatencyModeCallback( void* cookie) override; void setStreamOutLatencyModeCallback( void* cookie, const sp<StreamOutHalInterfaceLatencyModeCallback>& cb) override; // Implementation helpers. template<class C> sp<C> getCallbackImpl(void* cookie, wp<C> Callbacks::* field); template<class C> void setCallbackImpl(void* cookie, wp<C> Callbacks::* field, const sp<C>& cb); const std::string mInstance; const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule; Ports mPorts; Loading @@ -199,6 +249,8 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl { PortConfigs mPortConfigs; Patches mPatches; std::map<audio_patch_handle_t, int32_t /*patch ID*/> mFwkHandles; std::mutex mLock; std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock); }; } // namespace android
media/libaudiohal/impl/StreamHalAidl.cpp +26 −85 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ #include <algorithm> #include <cstdint> #include <aidl/android/hardware/audio/core/BnStreamCallback.h> #include <audio_utils/clock.h> #include <mediautils/TimeCheck.h> #include <utils/Log.h> Loading Loading @@ -448,43 +447,18 @@ status_t StreamHalAidl::updateCountersIfNeeded( return OK; } namespace { /* Notes on callback ownership. This is how Binder ownership model looks like. The server implementation is owned by Binder framework (via sp<>). Proxies are owned by clients. When the last proxy disappears, Binder framework releases the server impl. Thus, it is not needed to keep any references to StreamCallback (this is the server impl) -- it will live as long as HAL server holds a strong ref to IStreamCallback proxy. The callback only keeps a weak reference to the stream. The stream is owned by AudioFlinger. */ class StreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback { ndk::ScopedAStatus onTransferReady() override { return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus onError() override { return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus onDrainReady() override { return ndk::ScopedAStatus::ok(); } }; } // namespace StreamOutHalAidl::StreamOutHalAidl( const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency, const std::shared_ptr<IStreamOut>& stream) const std::shared_ptr<IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker) : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency, std::move(context), getStreamCommon(stream)), mStream(stream) {} mStream(stream), mCallbackBroker(callbackBroker) {} StreamOutHalAidl::~StreamOutHalAidl() { if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->clearCallbacks(this); } } status_t StreamOutHalAidl::getLatency(uint32_t *latency) { return StreamHalAidl::getLatency(latency); Loading Loading @@ -529,10 +503,18 @@ status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) { return INVALID_OPERATION; } status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback __unused) { status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { TIME_CHECK(); if (!mStream) return NO_INIT; ALOGE("%s not implemented yet", __func__); if (auto broker = mCallbackBroker.promote(); broker != nullptr) { if (auto cb = callback.promote(); cb != nullptr) { broker->setStreamOutCallback(this, cb); } else { // It is expected that the framework never passes a null pointer. // In the AIDL model callbacks can't be "unregistered". LOG_ALWAYS_FATAL("%s: received an expired or null callback pointer", __func__); } } return OK; } Loading Loading @@ -639,23 +621,15 @@ status_t StreamOutHalAidl::setPlaybackRateParameters( } status_t StreamOutHalAidl::setEventCallback( const sp<StreamOutHalInterfaceEventCallback>& callback __unused) { const sp<StreamOutHalInterfaceEventCallback>& callback) { TIME_CHECK(); if (!mStream) return NO_INIT; ALOGE("%s not implemented yet", __func__); if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutEventCallback(this, callback); } return OK; } namespace { struct StreamOutEventCallback { StreamOutEventCallback(const wp<StreamOutHalAidl>& stream) : mStream(stream) {} private: wp<StreamOutHalAidl> mStream; }; } // namespace status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) { TIME_CHECK(); if (!mStream) return NO_INIT; Loading @@ -672,48 +646,15 @@ status_t StreamOutHalAidl::getRecommendedLatencyModes( }; status_t StreamOutHalAidl::setLatencyModeCallback( const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) { const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) { TIME_CHECK(); if (!mStream) return NO_INIT; ALOGE("%s not implemented yet", __func__); if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutLatencyModeCallback(this, callback); } return OK; }; void StreamOutHalAidl::onWriteReady() { sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); if (callback == 0) return; ALOGV("asyncCallback onWriteReady"); callback->onWriteReady(); } void StreamOutHalAidl::onDrainReady() { sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); if (callback == 0) return; ALOGV("asyncCallback onDrainReady"); callback->onDrainReady(); } void StreamOutHalAidl::onError() { sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote(); if (callback == 0) return; ALOGV("asyncCallback onError"); callback->onError(); } void StreamOutHalAidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs __unused) { sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote(); if (callback == nullptr) return; ALOGV("asyncCodecFormatCallback %s", __func__); callback->onCodecFormatChanged(metadataBs); } void StreamOutHalAidl::onRecommendedLatencyModeChanged( const std::vector<audio_latency_mode_t>& modes __unused) { sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote(); if (callback == nullptr) return; callback->onRecommendedLatencyModeChanged(modes); } status_t StreamOutHalAidl::exit() { return StreamHalAidl::exit(); } Loading
media/libaudiohal/impl/StreamHalAidl.h +6 −17 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <fmq/AidlMessageQueue.h> #include <media/audiohal/EffectHalInterface.h> #include <media/audiohal/StreamHalInterface.h> #include <mediautils/Synchronization.h> #include "ConversionHelperAidl.h" #include "StreamPowerLog.h" Loading Loading @@ -221,6 +220,8 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper std::atomic<pid_t> mWorkerTid = -1; }; class CallbackBroker; class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { public: // Return the audio hardware driver estimated latency in milliseconds. Loading Loading @@ -294,33 +295,21 @@ class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { status_t setLatencyModeCallback( const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) override; void onRecommendedLatencyModeChanged(const std::vector<audio_latency_mode_t>& modes); status_t exit() override; void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs); // Methods used by StreamOutCallback (). // FIXME: Consider the required visibility. void onWriteReady(); void onDrainReady(); void onError(); private: friend class sp<StreamOutHalAidl>; mediautils::atomic_wp<StreamOutHalInterfaceCallback> mCallback; mediautils::atomic_wp<StreamOutHalInterfaceEventCallback> mEventCallback; mediautils::atomic_wp<StreamOutHalInterfaceLatencyModeCallback> mLatencyModeCallback; const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut> mStream; const wp<CallbackBroker> mCallbackBroker; // Can not be constructed directly by clients. StreamOutHalAidl( const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency, const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream); const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream, const sp<CallbackBroker>& callbackBroker); ~StreamOutHalAidl() override = default; ~StreamOutHalAidl() override; }; class StreamInHalAidl : public StreamInHalInterface, public StreamHalAidl { Loading
media/libaudiohal/include/media/audiohal/DeviceHalInterface.h +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ namespace android { class StreamInHalInterface; class StreamOutHalInterface; class DeviceHalInterface : public RefBase class DeviceHalInterface : public virtual RefBase { public: // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t. Loading