audio: Refactor Mmap buffer creation and handling
Unify handling of MQ and Mmap-based buffers in StreamContext.
Update 'Module::createMmapBuffer' to be called before
creating 'StreamContext'.
Flag: EXEMPT refactor
Bug: 274456992
Test: atest VtsHalAudioCoreTargetTest
Change-Id: I8ba775360643666aa7242c673dfc10c0c817994d
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 123a5ec..aa624ff 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -214,24 +214,33 @@
StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
mVendorDebug.forceTransientBurst,
mVendorDebug.forceSynchronousDrain};
- std::unique_ptr<StreamContext::DataMQ> dataMQ = nullptr;
- std::shared_ptr<IStreamCallback> streamAsyncCallback = nullptr;
std::shared_ptr<ISoundDose> soundDose;
if (!getSoundDose(&soundDose).isOk()) {
LOG(ERROR) << __func__ << ": could not create sound dose instance";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
- if (!hasMmapFlag(flags)) {
- dataMQ = std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames);
- streamAsyncCallback = asyncCallback;
+ StreamContext temp;
+ if (hasMmapFlag(flags)) {
+ MmapBufferDescriptor mmapDesc;
+ RETURN_STATUS_IF_ERROR(
+ createMmapBuffer(*portConfigIt, in_bufferSizeFrames, frameSize, &mmapDesc));
+ temp = StreamContext(
+ std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
+ std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
+ portConfigIt->format.value(), portConfigIt->channelMask.value(),
+ portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
+ portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(mmapDesc),
+ outEventCallback, mSoundDose.getInstance(), params);
+ } else {
+ temp = StreamContext(
+ std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
+ std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
+ portConfigIt->format.value(), portConfigIt->channelMask.value(),
+ portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
+ portConfigIt->ext.get<AudioPortExt::mix>().handle,
+ std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
+ asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
}
- StreamContext temp(
- std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
- std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
- portConfigIt->format.value(), portConfigIt->channelMask.value(),
- portConfigIt->sampleRate.value().value, flags, nominalLatencyMs,
- portConfigIt->ext.get<AudioPortExt::mix>().handle, std::move(dataMQ),
- streamAsyncCallback, outEventCallback, mSoundDose.getInstance(), params);
if (temp.isValid()) {
*out_context = std::move(temp);
} else {
@@ -394,9 +403,10 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
-ndk::ScopedAStatus Module::createMmapBuffer(
- const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
- ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
+ndk::ScopedAStatus Module::createMmapBuffer(const AudioPortConfig& portConfig __unused,
+ int32_t bufferSizeFrames __unused,
+ int32_t frameSizeBytes __unused,
+ MmapBufferDescriptor* desc __unused) {
LOG(ERROR) << __func__ << ": " << mType << ": is not implemented";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
@@ -977,9 +987,6 @@
RETURN_STATUS_IF_ERROR(createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
nullptr, nullptr, &context));
context.fillDescriptor(&_aidl_return->desc);
- if (hasMmapFlag(context.getFlags())) {
- RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
- }
std::shared_ptr<StreamIn> stream;
RETURN_STATUS_IF_ERROR(createInputStream(std::move(context), in_args.sinkMetadata,
getMicrophoneInfos(), &stream));
@@ -1027,9 +1034,6 @@
isNonBlocking ? in_args.callback : nullptr,
in_args.eventCallback, &context));
context.fillDescriptor(&_aidl_return->desc);
- if (hasMmapFlag(context.getFlags())) {
- RETURN_STATUS_IF_ERROR(createMmapBuffer(context, &_aidl_return->desc));
- }
std::shared_ptr<StreamOut> stream;
RETURN_STATUS_IF_ERROR(createOutputStream(std::move(context), in_args.sourceMetadata,
in_args.offloadInfo, &stream));
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 2800bed..873fc48 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -65,18 +65,26 @@
if (mReplyMQ) {
desc->reply = mReplyMQ->dupeDesc();
}
+ desc->frameSizeBytes = getFrameSize();
+ desc->bufferSizeFrames = getBufferSizeInFrames();
if (mDataMQ) {
- desc->frameSizeBytes = getFrameSize();
- desc->bufferSizeFrames = getBufferSizeInFrames();
desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
+ } else {
+ MmapBufferDescriptor mmapDesc; // Move-only due to `fd`.
+ mmapDesc.sharedMemory.fd = mMmapBufferDesc.sharedMemory.fd.dup();
+ mmapDesc.sharedMemory.size = mMmapBufferDesc.sharedMemory.size;
+ mmapDesc.burstSizeFrames = mMmapBufferDesc.burstSizeFrames;
+ mmapDesc.flags = mMmapBufferDesc.flags;
+ desc->audio.set<StreamDescriptor::AudioBuffer::Tag::mmap>(std::move(mmapDesc));
}
}
size_t StreamContext::getBufferSizeInFrames() const {
if (mDataMQ) {
return mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / getFrameSize();
+ } else {
+ return mMmapBufferDesc.sharedMemory.size / getFrameSize();
}
- return 0;
}
size_t StreamContext::getFrameSize() const {
@@ -96,9 +104,13 @@
LOG(ERROR) << "frame size is invalid";
return false;
}
- if (!hasMmapFlag(mFlags) && mDataMQ && !mDataMQ->isValid()) {
+ if (!isMmap() && mDataMQ && !mDataMQ->isValid()) {
LOG(ERROR) << "data FMQ is invalid";
return false;
+ } else if (isMmap() &&
+ (mMmapBufferDesc.sharedMemory.fd.get() == -1 ||
+ mMmapBufferDesc.sharedMemory.size == 0 || mMmapBufferDesc.burstSizeFrames == 0)) {
+ LOG(ERROR) << "mmap info is invalid" << mMmapBufferDesc.toString();
}
return true;
}
@@ -115,6 +127,7 @@
mCommandMQ.reset();
mReplyMQ.reset();
mDataMQ.reset();
+ mMmapBufferDesc.sharedMemory.fd.set(-1);
}
pid_t StreamWorkerCommonLogic::getTid() const {
@@ -128,7 +141,7 @@
std::string StreamWorkerCommonLogic::init() {
if (mContext->getCommandMQ() == nullptr) return "Command MQ is null";
if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null";
- if (!hasMmapFlag(mContext->getFlags())) {
+ if (!mContext->isMmap()) {
StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
if (dataMQ == nullptr) return "Data MQ is null";
if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
@@ -167,7 +180,7 @@
} else {
reply->observable = reply->hardware = kUnknownPosition;
}
- if (hasMmapFlag(mContext->getFlags())) {
+ if (mContext->isMmap()) {
if (auto status = mDriver->getMmapPositionAndLatency(&reply->hardware, &reply->latencyMs);
status != ::android::OK) {
reply->hardware = kUnknownPosition;
@@ -252,9 +265,8 @@
mState == StreamDescriptor::State::ACTIVE ||
mState == StreamDescriptor::State::PAUSED ||
mState == StreamDescriptor::State::DRAINING) {
- if (bool success = hasMmapFlag(mContext->getFlags())
- ? readMmap(&reply)
- : read(fmqByteCount, &reply);
+ if (bool success =
+ mContext->isMmap() ? readMmap(&reply) : read(fmqByteCount, &reply);
!success) {
mState = StreamDescriptor::State::ERROR;
}
@@ -548,9 +560,8 @@
if (mState != StreamDescriptor::State::ERROR &&
mState != StreamDescriptor::State::TRANSFERRING &&
mState != StreamDescriptor::State::TRANSFER_PAUSED) {
- if (bool success = hasMmapFlag(mContext->getFlags())
- ? writeMmap(&reply)
- : write(fmqByteCount, &reply);
+ if (bool success = mContext->isMmap() ? writeMmap(&reply)
+ : write(fmqByteCount, &reply);
!success) {
mState = StreamDescriptor::State::ERROR;
}
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 0661015..379264d 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -212,8 +212,8 @@
const ::aidl::android::media::audio::common::AudioFormatDescription &format,
int32_t latencyMs, int32_t sampleRateHz, int32_t *bufferSizeFrames);
virtual ndk::ScopedAStatus createMmapBuffer(
- const ::aidl::android::hardware::audio::core::StreamContext& context,
- ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
+ const ::aidl::android::media::audio::common::AudioPortConfig& portConfig,
+ int32_t bufferSizeFrames, int32_t frameSizeBytes, MmapBufferDescriptor* desc);
// Utility and helper functions accessible to subclasses.
static int32_t calculateBufferSizeFramesForPcm(int32_t latencyMs, int32_t sampleRateHz) {
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 376c684..bb790e9 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -104,6 +104,27 @@
mOutEventCallback(outEventCallback),
mStreamDataProcessor(streamDataProcessor),
mDebugParameters(debugParameters) {}
+ StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
+ const ::aidl::android::media::audio::common::AudioFormatDescription& format,
+ const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
+ int sampleRate, const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+ int32_t nominalLatencyMs, int32_t mixPortHandle, MmapBufferDescriptor&& mmapDesc,
+ std::shared_ptr<IStreamOutEventCallback> outEventCallback,
+ std::weak_ptr<sounddose::StreamDataProcessorInterface> streamDataProcessor,
+ DebugParameters debugParameters)
+ : mCommandMQ(std::move(commandMQ)),
+ mInternalCommandCookie(std::rand() | 1 /* make sure it's not 0 */),
+ mReplyMQ(std::move(replyMQ)),
+ mFormat(format),
+ mChannelLayout(channelLayout),
+ mSampleRate(sampleRate),
+ mFlags(flags),
+ mNominalLatencyMs(nominalLatencyMs),
+ mMixPortHandle(mixPortHandle),
+ mMmapBufferDesc(std::move(mmapDesc)),
+ mOutEventCallback(outEventCallback),
+ mStreamDataProcessor(streamDataProcessor),
+ mDebugParameters(debugParameters) {}
void fillDescriptor(StreamDescriptor* desc);
std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
@@ -136,6 +157,7 @@
bool isInput() const {
return mFlags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::input;
}
+ bool isMmap() const { return ::aidl::android::hardware::audio::common::hasMmapFlag(mFlags); }
bool isValid() const;
// 'reset' is called on a Binder thread when closing the stream. Does not use
// locking because it only cleans MQ pointers which were also set on the Binder thread.
@@ -155,7 +177,9 @@
::aidl::android::media::audio::common::AudioIoFlags mFlags;
int32_t mNominalLatencyMs;
int32_t mMixPortHandle;
+ // Only one of `mDataMQ` or `mMapBufferDesc` can be active, depending on `isMmap`
std::unique_ptr<DataMQ> mDataMQ;
+ MmapBufferDescriptor mMmapBufferDesc;
std::shared_ptr<IStreamCallback> mAsyncCallback;
std::shared_ptr<IStreamOutEventCallback> mOutEventCallback; // Only used by output streams
std::weak_ptr<sounddose::StreamDataProcessorInterface> mStreamDataProcessor;