Loading media/libaudiohal/impl/DeviceHalAidl.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -478,15 +478,21 @@ status_t DeviceHalAidl::openOutputStream( __func__, ret.desc.toString().c_str()); return NO_INIT; } *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0], auto stream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0], std::move(ret.stream), mVendorExt, this /*callbackBroker*/); void* cbCookie = (*outStream).get(); *outStream = stream; /* StreamOutHalInterface* */ void* cbCookie = (*outStream).get(); { std::lock_guard l(mLock); mCallbacks.emplace(cbCookie, Callbacks{}); mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id); } if (streamCb) streamCb->setCookie(cbCookie); if (streamCb) { streamCb->setCookie(cbCookie); // Although StreamOutHalAidl implements StreamOutHalInterfaceCallback, // we always go via the CallbackBroker for consistency. setStreamOutCallback(cbCookie, stream); } eventCb->setCookie(cbCookie); cleanups.disarmAll(); return OK; Loading media/libaudiohal/impl/StreamHalAidl.cpp +77 −23 Original line number Diff line number Diff line Loading @@ -82,7 +82,12 @@ StreamHalAidl::StreamHalAidl( mConfig(configToBase(config)), mContext(std::move(context)), mStream(stream), mVendorExt(vext) { mVendorExt(vext), mLastReplyLifeTimeNs( std::min(static_cast<size_t>(100), 2 * mContext.getBufferDurationMs(mConfig.sample_rate)) * NANOS_PER_MILLISECOND) { ALOGD("%p %s::%s", this, getClassName().c_str(), __func__); { std::lock_guard l(mLock); Loading Loading @@ -285,8 +290,7 @@ status_t StreamHalAidl::getHardwarePosition(int64_t *frames, int64_t *timestamp) ALOGV("%p %s::%s", this, getClassName().c_str(), __func__); if (!mStream) return NO_INIT; StreamDescriptor::Reply reply; // TODO: switch to updateCountersIfNeeded once we sort out mWorkerTid initialization RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true)); RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply)); *frames = std::max<int64_t>(0, reply.hardware.frames); *timestamp = std::max<int64_t>(0, reply.hardware.timeNs); return OK; Loading Loading @@ -409,6 +413,37 @@ status_t StreamHalAidl::exit() { return statusTFromBinderStatus(mStream->prepareToClose()); } void StreamHalAidl::onAsyncTransferReady() { if (auto state = getState(); state == StreamDescriptor::State::TRANSFERRING) { // Retrieve the current state together with position counters. updateCountersIfNeeded(); } else { ALOGW("%s: unexpected onTransferReady in the state %s", __func__, toString(state).c_str()); } } void StreamHalAidl::onAsyncDrainReady() { if (auto state = getState(); state == StreamDescriptor::State::DRAINING) { // Retrieve the current state together with position counters. updateCountersIfNeeded(); } else { ALOGW("%s: unexpected onDrainReady in the state %s", __func__, toString(state).c_str()); } } void StreamHalAidl::onAsyncError() { std::lock_guard l(mLock); if (mLastReply.state == StreamDescriptor::State::IDLE || mLastReply.state == StreamDescriptor::State::DRAINING || mLastReply.state == StreamDescriptor::State::TRANSFERRING) { mLastReply.state = StreamDescriptor::State::ERROR; ALOGW("%s: onError received", __func__); } else { ALOGW("%s: unexpected onError in the state %s", __func__, toString(mLastReply.state).c_str()); } } status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused, struct audio_mmap_buffer_info *info) { ALOGD("%p %s::%s", this, getClassName().c_str(), __func__); Loading Loading @@ -487,6 +522,7 @@ status_t StreamHalAidl::sendCommand( reply->latencyMs = mLastReply.latencyMs; } mLastReply = *reply; mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs; } switch (reply->status) { case STATUS_OK: return OK; Loading @@ -502,14 +538,17 @@ status_t StreamHalAidl::sendCommand( status_t StreamHalAidl::updateCountersIfNeeded( ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) { if (mWorkerTid.load(std::memory_order_acquire) == gettid()) { if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE && state != StreamDescriptor::State::DRAINING && state != StreamDescriptor::State::TRANSFERRING) { return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply); } } if (reply != nullptr) { bool doUpdate = false; { std::lock_guard l(mLock); doUpdate = uptimeNanos() > mLastReplyExpirationNs; } if (doUpdate) { // Since updates are paced, it is OK to perform them from any thread, they should // not interfere with I/O operations of the worker. return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply, true /*safeFromNonWorkerThread */); } else if (reply != nullptr) { // provide cached reply std::lock_guard l(mLock); *reply = mLastReply; } Loading Loading @@ -545,7 +584,7 @@ StreamOutHalAidl::StreamOutHalAidl( StreamOutHalAidl::~StreamOutHalAidl() { if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->clearCallbacks(this); broker->clearCallbacks(static_cast<StreamOutHalInterface*>(this)); } } Loading Loading @@ -602,21 +641,14 @@ status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) { } status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { ALOGD("%p %s", this, __func__); TIME_CHECK(); if (!mStream) return NO_INIT; if (!mContext.isAsynchronous()) { ALOGE("%s: the callback is intended for asynchronous streams only", __func__); return INVALID_OPERATION; } 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__); } } mClientCallback = callback; return OK; } Loading Loading @@ -739,7 +771,7 @@ status_t StreamOutHalAidl::setEventCallback( TIME_CHECK(); if (!mStream) return NO_INIT; if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutEventCallback(this, callback); broker->setStreamOutEventCallback(static_cast<StreamOutHalInterface*>(this), callback); } return OK; } Loading Loading @@ -773,7 +805,8 @@ status_t StreamOutHalAidl::setLatencyModeCallback( TIME_CHECK(); if (!mStream) return NO_INIT; if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutLatencyModeCallback(this, callback); broker->setStreamOutLatencyModeCallback( static_cast<StreamOutHalInterface*>(this), callback); } return OK; }; Loading @@ -782,6 +815,27 @@ status_t StreamOutHalAidl::exit() { return StreamHalAidl::exit(); } void StreamOutHalAidl::onWriteReady() { onAsyncTransferReady(); if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) { clientCb->onWriteReady(); } } void StreamOutHalAidl::onDrainReady() { onAsyncDrainReady(); if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) { clientCb->onDrainReady(); } } void StreamOutHalAidl::onError() { onAsyncError(); if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) { clientCb->onError(); } } status_t StreamOutHalAidl::filterAndUpdateOffloadMetadata(AudioParameter ¶meters) { TIME_CHECK(); bool updateMetadata = false; Loading media/libaudiohal/impl/StreamHalAidl.h +19 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <media/audiohal/StreamHalInterface.h> #include <media/AidlConversionUtil.h> #include <media/AudioParameter.h> #include <mediautils/Synchronization.h> #include "ConversionHelperAidl.h" #include "StreamPowerLog.h" Loading Loading @@ -93,6 +94,9 @@ class StreamContextAidl { } size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; } size_t getBufferSizeFrames() const { return mBufferSizeFrames; } size_t getBufferDurationMs(int32_t sampleRate) const { return sampleRate != 0 ? mBufferSizeFrames * MILLIS_PER_SECOND / sampleRate : 0; } CommandMQ* getCommandMQ() const { return mCommandMQ.get(); } DataMQ* getDataMQ() const { return mDataMQ.get(); } size_t getFrameSizeBytes() const { return mFrameSizeBytes; } Loading Loading @@ -232,6 +236,10 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper status_t exit(); void onAsyncTransferReady(); void onAsyncDrainReady(); void onAsyncError(); const bool mIsInput; const audio_config_base_t mConfig; const StreamContextAidl mContext; Loading @@ -257,8 +265,10 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> mStream; const std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension> mVendorExt; const int64_t mLastReplyLifeTimeNs; std::mutex mLock; ::aidl::android::hardware::audio::core::StreamDescriptor::Reply mLastReply GUARDED_BY(mLock); int64_t mLastReplyExpirationNs GUARDED_BY(mLock) = 0; // mStreamPowerLog is used for audio signal power logging. StreamPowerLog mStreamPowerLog; std::atomic<pid_t> mWorkerTid = -1; Loading @@ -266,7 +276,9 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper class CallbackBroker; class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { class StreamOutHalAidl : public virtual StreamOutHalInterface, public virtual StreamOutHalInterfaceCallback, public StreamHalAidl { public: // Extract the output stream parameters and set by AIDL APIs. status_t setParameters(const String8& kvPairs) override; Loading Loading @@ -344,6 +356,11 @@ class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { status_t exit() override; // StreamOutHalInterfaceCallback void onWriteReady() override; void onDrainReady() override; void onError() override; private: friend class sp<StreamOutHalAidl>; Loading @@ -352,6 +369,7 @@ class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut> mStream; const wp<CallbackBroker> mCallbackBroker; mediautils::atomic_wp<StreamOutHalInterfaceCallback> mClientCallback; AudioOffloadMetadata mOffloadMetadata; Loading Loading
media/libaudiohal/impl/DeviceHalAidl.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -478,15 +478,21 @@ status_t DeviceHalAidl::openOutputStream( __func__, ret.desc.toString().c_str()); return NO_INIT; } *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0], auto stream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0], std::move(ret.stream), mVendorExt, this /*callbackBroker*/); void* cbCookie = (*outStream).get(); *outStream = stream; /* StreamOutHalInterface* */ void* cbCookie = (*outStream).get(); { std::lock_guard l(mLock); mCallbacks.emplace(cbCookie, Callbacks{}); mMapper.addStream(*outStream, mixPortConfig.id, aidlPatch.id); } if (streamCb) streamCb->setCookie(cbCookie); if (streamCb) { streamCb->setCookie(cbCookie); // Although StreamOutHalAidl implements StreamOutHalInterfaceCallback, // we always go via the CallbackBroker for consistency. setStreamOutCallback(cbCookie, stream); } eventCb->setCookie(cbCookie); cleanups.disarmAll(); return OK; Loading
media/libaudiohal/impl/StreamHalAidl.cpp +77 −23 Original line number Diff line number Diff line Loading @@ -82,7 +82,12 @@ StreamHalAidl::StreamHalAidl( mConfig(configToBase(config)), mContext(std::move(context)), mStream(stream), mVendorExt(vext) { mVendorExt(vext), mLastReplyLifeTimeNs( std::min(static_cast<size_t>(100), 2 * mContext.getBufferDurationMs(mConfig.sample_rate)) * NANOS_PER_MILLISECOND) { ALOGD("%p %s::%s", this, getClassName().c_str(), __func__); { std::lock_guard l(mLock); Loading Loading @@ -285,8 +290,7 @@ status_t StreamHalAidl::getHardwarePosition(int64_t *frames, int64_t *timestamp) ALOGV("%p %s::%s", this, getClassName().c_str(), __func__); if (!mStream) return NO_INIT; StreamDescriptor::Reply reply; // TODO: switch to updateCountersIfNeeded once we sort out mWorkerTid initialization RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true)); RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply)); *frames = std::max<int64_t>(0, reply.hardware.frames); *timestamp = std::max<int64_t>(0, reply.hardware.timeNs); return OK; Loading Loading @@ -409,6 +413,37 @@ status_t StreamHalAidl::exit() { return statusTFromBinderStatus(mStream->prepareToClose()); } void StreamHalAidl::onAsyncTransferReady() { if (auto state = getState(); state == StreamDescriptor::State::TRANSFERRING) { // Retrieve the current state together with position counters. updateCountersIfNeeded(); } else { ALOGW("%s: unexpected onTransferReady in the state %s", __func__, toString(state).c_str()); } } void StreamHalAidl::onAsyncDrainReady() { if (auto state = getState(); state == StreamDescriptor::State::DRAINING) { // Retrieve the current state together with position counters. updateCountersIfNeeded(); } else { ALOGW("%s: unexpected onDrainReady in the state %s", __func__, toString(state).c_str()); } } void StreamHalAidl::onAsyncError() { std::lock_guard l(mLock); if (mLastReply.state == StreamDescriptor::State::IDLE || mLastReply.state == StreamDescriptor::State::DRAINING || mLastReply.state == StreamDescriptor::State::TRANSFERRING) { mLastReply.state = StreamDescriptor::State::ERROR; ALOGW("%s: onError received", __func__); } else { ALOGW("%s: unexpected onError in the state %s", __func__, toString(mLastReply.state).c_str()); } } status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused, struct audio_mmap_buffer_info *info) { ALOGD("%p %s::%s", this, getClassName().c_str(), __func__); Loading Loading @@ -487,6 +522,7 @@ status_t StreamHalAidl::sendCommand( reply->latencyMs = mLastReply.latencyMs; } mLastReply = *reply; mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs; } switch (reply->status) { case STATUS_OK: return OK; Loading @@ -502,14 +538,17 @@ status_t StreamHalAidl::sendCommand( status_t StreamHalAidl::updateCountersIfNeeded( ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) { if (mWorkerTid.load(std::memory_order_acquire) == gettid()) { if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE && state != StreamDescriptor::State::DRAINING && state != StreamDescriptor::State::TRANSFERRING) { return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply); } } if (reply != nullptr) { bool doUpdate = false; { std::lock_guard l(mLock); doUpdate = uptimeNanos() > mLastReplyExpirationNs; } if (doUpdate) { // Since updates are paced, it is OK to perform them from any thread, they should // not interfere with I/O operations of the worker. return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply, true /*safeFromNonWorkerThread */); } else if (reply != nullptr) { // provide cached reply std::lock_guard l(mLock); *reply = mLastReply; } Loading Loading @@ -545,7 +584,7 @@ StreamOutHalAidl::StreamOutHalAidl( StreamOutHalAidl::~StreamOutHalAidl() { if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->clearCallbacks(this); broker->clearCallbacks(static_cast<StreamOutHalInterface*>(this)); } } Loading Loading @@ -602,21 +641,14 @@ status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) { } status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) { ALOGD("%p %s", this, __func__); TIME_CHECK(); if (!mStream) return NO_INIT; if (!mContext.isAsynchronous()) { ALOGE("%s: the callback is intended for asynchronous streams only", __func__); return INVALID_OPERATION; } 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__); } } mClientCallback = callback; return OK; } Loading Loading @@ -739,7 +771,7 @@ status_t StreamOutHalAidl::setEventCallback( TIME_CHECK(); if (!mStream) return NO_INIT; if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutEventCallback(this, callback); broker->setStreamOutEventCallback(static_cast<StreamOutHalInterface*>(this), callback); } return OK; } Loading Loading @@ -773,7 +805,8 @@ status_t StreamOutHalAidl::setLatencyModeCallback( TIME_CHECK(); if (!mStream) return NO_INIT; if (auto broker = mCallbackBroker.promote(); broker != nullptr) { broker->setStreamOutLatencyModeCallback(this, callback); broker->setStreamOutLatencyModeCallback( static_cast<StreamOutHalInterface*>(this), callback); } return OK; }; Loading @@ -782,6 +815,27 @@ status_t StreamOutHalAidl::exit() { return StreamHalAidl::exit(); } void StreamOutHalAidl::onWriteReady() { onAsyncTransferReady(); if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) { clientCb->onWriteReady(); } } void StreamOutHalAidl::onDrainReady() { onAsyncDrainReady(); if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) { clientCb->onDrainReady(); } } void StreamOutHalAidl::onError() { onAsyncError(); if (auto clientCb = mClientCallback.load().promote(); clientCb != nullptr) { clientCb->onError(); } } status_t StreamOutHalAidl::filterAndUpdateOffloadMetadata(AudioParameter ¶meters) { TIME_CHECK(); bool updateMetadata = false; Loading
media/libaudiohal/impl/StreamHalAidl.h +19 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <media/audiohal/StreamHalInterface.h> #include <media/AidlConversionUtil.h> #include <media/AudioParameter.h> #include <mediautils/Synchronization.h> #include "ConversionHelperAidl.h" #include "StreamPowerLog.h" Loading Loading @@ -93,6 +94,9 @@ class StreamContextAidl { } size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; } size_t getBufferSizeFrames() const { return mBufferSizeFrames; } size_t getBufferDurationMs(int32_t sampleRate) const { return sampleRate != 0 ? mBufferSizeFrames * MILLIS_PER_SECOND / sampleRate : 0; } CommandMQ* getCommandMQ() const { return mCommandMQ.get(); } DataMQ* getDataMQ() const { return mDataMQ.get(); } size_t getFrameSizeBytes() const { return mFrameSizeBytes; } Loading Loading @@ -232,6 +236,10 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper status_t exit(); void onAsyncTransferReady(); void onAsyncDrainReady(); void onAsyncError(); const bool mIsInput; const audio_config_base_t mConfig; const StreamContextAidl mContext; Loading @@ -257,8 +265,10 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> mStream; const std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension> mVendorExt; const int64_t mLastReplyLifeTimeNs; std::mutex mLock; ::aidl::android::hardware::audio::core::StreamDescriptor::Reply mLastReply GUARDED_BY(mLock); int64_t mLastReplyExpirationNs GUARDED_BY(mLock) = 0; // mStreamPowerLog is used for audio signal power logging. StreamPowerLog mStreamPowerLog; std::atomic<pid_t> mWorkerTid = -1; Loading @@ -266,7 +276,9 @@ class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelper class CallbackBroker; class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { class StreamOutHalAidl : public virtual StreamOutHalInterface, public virtual StreamOutHalInterfaceCallback, public StreamHalAidl { public: // Extract the output stream parameters and set by AIDL APIs. status_t setParameters(const String8& kvPairs) override; Loading Loading @@ -344,6 +356,11 @@ class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { status_t exit() override; // StreamOutHalInterfaceCallback void onWriteReady() override; void onDrainReady() override; void onError() override; private: friend class sp<StreamOutHalAidl>; Loading @@ -352,6 +369,7 @@ class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl { const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut> mStream; const wp<CallbackBroker> mCallbackBroker; mediautils::atomic_wp<StreamOutHalInterfaceCallback> mClientCallback; AudioOffloadMetadata mOffloadMetadata; Loading