libaudiohal: Handle pause-flush-resume for offloaded streams
Update StreamHalAidl to support pause-flush-resume sequence.
This is implemented by moving the asynchronous output stream
from IDLE back to ACTIVE state by issuing 'burst' command
(see stream-out-async-sm.gv).
Bug: 270552159
Test: atest CtsMediaAudioTestCases:VolumeShaperTest
Change-Id: I810fe817ef648567c30a161f1762343c9bca990b
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 32ebe36..44f81b7 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -460,7 +460,7 @@
args.eventCallback = eventCb;
::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
- StreamContextAidl context(ret.desc);
+ StreamContextAidl context(ret.desc, isOffload);
if (!context.isValid()) {
ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
__func__, ret.desc.toString().c_str());
@@ -520,7 +520,7 @@
args.bufferSizeFrames = aidlConfig.frameCount;
::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
- StreamContextAidl context(ret.desc);
+ StreamContextAidl context(ret.desc, false /*isAsynchronous*/);
if (!context.isValid()) {
ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
__func__, ret.desc.toString().c_str());
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 757215d..f9c9f3d 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -323,6 +323,26 @@
if (mIsInput) {
return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
} else {
+ if (mContext.isAsynchronous()) {
+ // Handle pause-flush-resume sequence. 'flush' from PAUSED goes to
+ // IDLE. We move here from IDLE to ACTIVE (same as 'start' from PAUSED).
+ const auto state = getState();
+ if (state == StreamDescriptor::State::IDLE) {
+ StreamDescriptor::Reply localReply{};
+ StreamDescriptor::Reply* innerReply = reply ?: &localReply;
+ if (status_t status =
+ sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply);
+ status != OK) {
+ return status;
+ }
+ if (innerReply->state != StreamDescriptor::State::ACTIVE) {
+ ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
+ __func__, toString(innerReply->state).c_str());
+ return INVALID_OPERATION;
+ }
+ return OK;
+ }
+ }
return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
}
}
@@ -514,6 +534,10 @@
status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback) {
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);
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index f43c8e2..d00774c 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -43,24 +43,28 @@
::aidl::android::hardware::common::fmq::SynchronizedReadWrite> DataMQ;
explicit StreamContextAidl(
- const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor)
+ const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor,
+ bool isAsynchronous)
: mFrameSizeBytes(descriptor.frameSizeBytes),
mCommandMQ(new CommandMQ(descriptor.command)),
mReplyMQ(new ReplyMQ(descriptor.reply)),
mBufferSizeFrames(descriptor.bufferSizeFrames),
- mDataMQ(maybeCreateDataMQ(descriptor)) {}
+ mDataMQ(maybeCreateDataMQ(descriptor)),
+ mIsAsynchronous(isAsynchronous) {}
StreamContextAidl(StreamContextAidl&& other) :
mFrameSizeBytes(other.mFrameSizeBytes),
mCommandMQ(std::move(other.mCommandMQ)),
mReplyMQ(std::move(other.mReplyMQ)),
mBufferSizeFrames(other.mBufferSizeFrames),
- mDataMQ(std::move(other.mDataMQ)) {}
+ mDataMQ(std::move(other.mDataMQ)),
+ mIsAsynchronous(other.mIsAsynchronous) {}
StreamContextAidl& operator=(StreamContextAidl&& other) {
mFrameSizeBytes = other.mFrameSizeBytes;
mCommandMQ = std::move(other.mCommandMQ);
mReplyMQ = std::move(other.mReplyMQ);
mBufferSizeFrames = other.mBufferSizeFrames;
mDataMQ = std::move(other.mDataMQ);
+ mIsAsynchronous = other.mIsAsynchronous;
return *this;
}
bool isValid() const {
@@ -78,6 +82,7 @@
DataMQ* getDataMQ() const { return mDataMQ.get(); }
size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+ bool isAsynchronous() const { return mIsAsynchronous; }
private:
static std::unique_ptr<DataMQ> maybeCreateDataMQ(
@@ -94,6 +99,7 @@
std::unique_ptr<ReplyMQ> mReplyMQ;
size_t mBufferSizeFrames;
std::unique_ptr<DataMQ> mDataMQ;
+ bool mIsAsynchronous;
};
class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelperAidl {