Merge "audio: fix mmap output" into main am: f28b8e809c am: 35b81e0b47
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/3116044
Change-Id: I8bec36fd1b35886a39790498eb6f090a3b3ca7b3
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index b431340..6241f44 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -26,6 +26,7 @@
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <aidl/android/media/audio/common/AudioFormatDescription.h>
#include <aidl/android/media/audio/common/AudioInputFlags.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioMode.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <aidl/android/media/audio/common/PcmType.h>
@@ -191,4 +192,15 @@
return frameCountFromDurationUs(durationMs * 1000, sampleRateHz);
}
+constexpr bool hasMmapFlag(const ::aidl::android::media::audio::common::AudioIoFlags& flags) {
+ return (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::input &&
+ isBitPositionFlagSet(
+ flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::input>(),
+ ::aidl::android::media::audio::common::AudioInputFlags::MMAP_NOIRQ)) ||
+ (flags.getTag() == ::aidl::android::media::audio::common::AudioIoFlags::Tag::output &&
+ isBitPositionFlagSet(
+ flags.get<::aidl::android::media::audio::common::AudioIoFlags::Tag::output>(),
+ ::aidl::android::media::audio::common::AudioOutputFlags::MMAP_NOIRQ));
+}
+
} // namespace aidl::android::hardware::audio::common
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 0d6151e..543efd1 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -36,6 +36,7 @@
using aidl::android::hardware::audio::common::frameCountFromDurationMs;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::isValidAudioMode;
using aidl::android::hardware::audio::common::SinkMetadata;
@@ -205,35 +206,31 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
const auto& flags = portConfigIt->flags.value();
- if ((flags.getTag() == AudioIoFlags::Tag::input &&
- !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
- AudioInputFlags::MMAP_NOIRQ)) ||
- (flags.getTag() == AudioIoFlags::Tag::output &&
- !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
- AudioOutputFlags::MMAP_NOIRQ))) {
- StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
- mVendorDebug.forceTransientBurst,
- mVendorDebug.forceSynchronousDrain};
- 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);
- }
- 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::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
- asyncCallback, outEventCallback, mSoundDose.getInstance(), params);
- if (temp.isValid()) {
- *out_context = std::move(temp);
- } else {
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
+ 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(
+ 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 {
- // TODO: Implement simulation of MMAP buffer allocation
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
return ndk::ScopedAStatus::ok();
}
@@ -373,6 +370,13 @@
return kLatencyMs;
}
+ndk::ScopedAStatus Module::createMmapBuffer(
+ const ::aidl::android::hardware::audio::core::StreamContext& context __unused,
+ ::aidl::android::hardware::audio::core::StreamDescriptor* desc __unused) {
+ LOG(ERROR) << __func__ << ": " << mType << ": is not implemented";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
std::vector<AudioRoute*> Module::getAudioRoutesForAudioPortImpl(int32_t portId) {
std::vector<AudioRoute*> result;
auto& routes = getConfig().routes;
@@ -866,6 +870,9 @@
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));
@@ -913,6 +920,9 @@
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 31b0645..8f5e839 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -30,6 +30,7 @@
using aidl::android::hardware::audio::common::AudioOffloadMetadata;
using aidl::android::hardware::audio::common::getChannelCount;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
@@ -84,7 +85,7 @@
LOG(ERROR) << "frame size is invalid";
return false;
}
- if (mDataMQ && !mDataMQ->isValid()) {
+ if (!hasMmapFlag(mFlags) && mDataMQ && !mDataMQ->isValid()) {
LOG(ERROR) << "data FMQ is invalid";
return false;
}
@@ -116,17 +117,19 @@
std::string StreamWorkerCommonLogic::init() {
if (mContext->getCommandMQ() == nullptr) return "Command MQ is null";
if (mContext->getReplyMQ() == nullptr) return "Reply MQ is null";
- StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
- if (dataMQ == nullptr) return "Data MQ is null";
- if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
- return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize());
- }
- mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize();
- mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
- if (mDataBuffer == nullptr) {
- return "Failed to allocate data buffer for element count " +
- std::to_string(dataMQ->getQuantumCount()) +
- ", size in bytes: " + std::to_string(mDataBufferSize);
+ if (!hasMmapFlag(mContext->getFlags())) {
+ StreamContext::DataMQ* const dataMQ = mContext->getDataMQ();
+ if (dataMQ == nullptr) return "Data MQ is null";
+ if (sizeof(DataBufferElement) != dataMQ->getQuantumSize()) {
+ return "Unexpected Data MQ quantum size: " + std::to_string(dataMQ->getQuantumSize());
+ }
+ mDataBufferSize = dataMQ->getQuantumCount() * dataMQ->getQuantumSize();
+ mDataBuffer.reset(new (std::nothrow) DataBufferElement[mDataBufferSize]);
+ if (mDataBuffer == nullptr) {
+ return "Failed to allocate data buffer for element count " +
+ std::to_string(dataMQ->getQuantumCount()) +
+ ", size in bytes: " + std::to_string(mDataBufferSize);
+ }
}
if (::android::status_t status = mDriver->init(); status != STATUS_OK) {
return "Failed to initialize the driver: " + std::to_string(status);
@@ -136,16 +139,26 @@
void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
bool isConnected) const {
+ static const StreamDescriptor::Position kUnknownPosition = {
+ .frames = StreamDescriptor::Position::UNKNOWN,
+ .timeNs = StreamDescriptor::Position::UNKNOWN};
reply->status = STATUS_OK;
if (isConnected) {
reply->observable.frames = mContext->getFrameCount();
reply->observable.timeNs = ::android::uptimeNanos();
- if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
- return;
+ if (auto status = mDriver->refinePosition(&reply->observable); status != ::android::OK) {
+ reply->observable = kUnknownPosition;
+ }
+ } else {
+ reply->observable = reply->hardware = kUnknownPosition;
+ }
+ if (hasMmapFlag(mContext->getFlags())) {
+ if (auto status = mDriver->getMmapPositionAndLatency(&reply->hardware, &reply->latencyMs);
+ status != ::android::OK) {
+ reply->hardware = kUnknownPosition;
+ reply->latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
}
}
- reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
- reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
}
void StreamWorkerCommonLogic::populateReplyWrongState(
@@ -224,7 +237,9 @@
mState == StreamDescriptor::State::ACTIVE ||
mState == StreamDescriptor::State::PAUSED ||
mState == StreamDescriptor::State::DRAINING) {
- if (!read(fmqByteCount, &reply)) {
+ if (hasMmapFlag(mContext->getFlags())) {
+ populateReply(&reply, mIsConnected);
+ } else if (!read(fmqByteCount, &reply)) {
mState = StreamDescriptor::State::ERROR;
}
if (mState == StreamDescriptor::State::IDLE ||
@@ -470,7 +485,9 @@
if (mState != StreamDescriptor::State::ERROR &&
mState != StreamDescriptor::State::TRANSFERRING &&
mState != StreamDescriptor::State::TRANSFER_PAUSED) {
- if (!write(fmqByteCount, &reply)) {
+ if (hasMmapFlag(mContext->getFlags())) {
+ populateReply(&reply, mIsConnected);
+ } else if (!write(fmqByteCount, &reply)) {
mState = StreamDescriptor::State::ERROR;
}
std::shared_ptr<IStreamCallback> asyncCallback = mContext->getAsyncCallback();
@@ -657,6 +674,7 @@
const std::shared_ptr<StreamCommonInterface>& delegate) {
mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
if (!mWorker->start()) {
+ LOG(ERROR) << __func__ << ": Worker start error: " << mWorker->getError();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
if (auto flags = getContext().getFlags();
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index a326217..00eeb4e 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -205,6 +205,9 @@
virtual std::unique_ptr<Configuration> initializeConfig();
virtual int32_t getNominalLatencyMs(
const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
+ virtual ndk::ScopedAStatus createMmapBuffer(
+ const ::aidl::android::hardware::audio::core::StreamContext& context,
+ ::aidl::android::hardware::audio::core::StreamDescriptor* desc);
// Utility and helper functions accessible to subclasses.
static int32_t calculateBufferSizeFrames(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 21e63f9..6b45866 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -177,6 +177,11 @@
virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
return ::android::OK;
}
+ // Implement 'getMmapPositionAndLatency' is necessary if driver can support mmap stream.
+ virtual ::android::status_t getMmapPositionAndLatency(StreamDescriptor::Position* /*position*/,
+ int32_t* /*latency*/) {
+ return ::android::OK;
+ }
virtual void shutdown() = 0; // This function is only called once.
};
@@ -241,6 +246,7 @@
virtual bool start() = 0;
virtual pid_t getTid() = 0;
virtual void stop() = 0;
+ virtual std::string getError() = 0;
};
template <class WorkerLogic>
@@ -260,6 +266,7 @@
}
pid_t getTid() override { return WorkerImpl::getTid(); }
void stop() override { return WorkerImpl::stop(); }
+ std::string getError() override { return WorkerImpl::getError(); }
};
class StreamInWorkerLogic : public StreamWorkerCommonLogic {
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index d576c7c..bbc4caf 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -56,6 +56,7 @@
using namespace android;
using aidl::android::hardware::audio::common::AudioOffloadMetadata;
using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::common::hasMmapFlag;
using aidl::android::hardware::audio::common::isAnyBitPositionFlagSet;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::isTelephonyDeviceType;
@@ -637,19 +638,39 @@
mCommandMQ(new CommandMQ(descriptor.command)),
mReplyMQ(new ReplyMQ(descriptor.reply)),
mBufferSizeFrames(descriptor.bufferSizeFrames),
- mDataMQ(maybeCreateDataMQ(descriptor)) {}
+ mDataMQ(maybeCreateDataMQ(descriptor)),
+ mIsMmapped(isMmapped(descriptor)),
+ mSharedMemoryFd(maybeGetMmapFd(descriptor)) {
+ if (isMmapped()) {
+ mSharedMemory = (int8_t*)mmap(nullptr, getBufferSizeBytes(), PROT_READ | PROT_WRITE,
+ MAP_SHARED, mSharedMemoryFd, 0);
+ if (mSharedMemory == MAP_FAILED) {
+ PLOG(ERROR) << __func__ << ": mmap() failed.";
+ mSharedMemory = nullptr;
+ }
+ }
+ }
+ ~StreamContext() {
+ if (mSharedMemory != nullptr) {
+ munmap(mSharedMemory, getBufferSizeBytes());
+ }
+ }
void checkIsValid() const {
EXPECT_NE(0UL, mFrameSizeBytes);
ASSERT_NE(nullptr, mCommandMQ);
EXPECT_TRUE(mCommandMQ->isValid());
ASSERT_NE(nullptr, mReplyMQ);
EXPECT_TRUE(mReplyMQ->isValid());
- if (mDataMQ != nullptr) {
- EXPECT_TRUE(mDataMQ->isValid());
- EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
- mFrameSizeBytes * mBufferSizeFrames)
- << "Data MQ actual buffer size is "
- "less than the buffer size as specified by the descriptor";
+ if (isMmapped()) {
+ ASSERT_NE(nullptr, mSharedMemory);
+ } else {
+ if (mDataMQ != nullptr) {
+ EXPECT_TRUE(mDataMQ->isValid());
+ EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
+ mFrameSizeBytes * mBufferSizeFrames)
+ << "Data MQ actual buffer size is "
+ "less than the buffer size as specified by the descriptor";
+ }
}
}
size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
@@ -658,6 +679,8 @@
DataMQ* getDataMQ() const { return mDataMQ.get(); }
size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+ bool isMmapped() const { return mIsMmapped; }
+ int8_t* getMmapMemory() const { return mSharedMemory; }
private:
static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
@@ -667,12 +690,26 @@
}
return nullptr;
}
+ static bool isMmapped(const StreamDescriptor& descriptor) {
+ using Tag = StreamDescriptor::AudioBuffer::Tag;
+ return descriptor.audio.getTag() == Tag::mmap;
+ }
+ static int32_t maybeGetMmapFd(const StreamDescriptor& descriptor) {
+ using Tag = StreamDescriptor::AudioBuffer::Tag;
+ if (descriptor.audio.getTag() == Tag::mmap) {
+ return descriptor.audio.get<Tag::mmap>().sharedMemory.fd.get();
+ }
+ return -1;
+ }
const size_t mFrameSizeBytes;
std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<ReplyMQ> mReplyMQ;
const size_t mBufferSizeFrames;
std::unique_ptr<DataMQ> mDataMQ;
+ const bool mIsMmapped;
+ const int32_t mSharedMemoryFd;
+ int8_t* mSharedMemory = nullptr;
};
struct StreamEventReceiver {
@@ -868,12 +905,15 @@
mDataMQ(context.getDataMQ()),
mData(context.getBufferSizeBytes()),
mDriver(driver),
- mEventReceiver(eventReceiver) {}
+ mEventReceiver(eventReceiver),
+ mIsMmapped(context.isMmapped()),
+ mSharedMemory(context.getMmapMemory()) {}
StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
StreamLogicDriver* getDriver() const { return mDriver; }
StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
+ bool isMmapped() const { return mIsMmapped; }
std::string init() override {
LOG(DEBUG) << __func__;
@@ -914,6 +954,22 @@
LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
return false;
}
+ bool readDataFromMmap(size_t readCount) {
+ if (mSharedMemory != nullptr) {
+ std::memcpy(mData.data(), mSharedMemory, readCount);
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from mmap failed";
+ return false;
+ }
+ bool writeDataToMmap() {
+ if (mSharedMemory != nullptr) {
+ std::memcpy(mSharedMemory, mData.data(), mData.size());
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to mmap failed";
+ return false;
+ }
private:
StreamContext::CommandMQ* mCommandMQ;
@@ -923,6 +979,8 @@
StreamLogicDriver* const mDriver;
StreamEventReceiver* const mEventReceiver;
int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
+ const bool mIsMmapped;
+ int8_t* mSharedMemory = nullptr;
};
class StreamReaderLogic : public StreamCommonLogic {
@@ -970,7 +1028,8 @@
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
}
- if (static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
+ if (!isMmapped() &&
+ static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
LOG(ERROR) << __func__
<< ": the byte count in the reply is not the same as the amount of "
<< "data available in the MQ: " << reply.fmqByteCount
@@ -991,8 +1050,10 @@
return Status::ABORT;
}
const bool acceptedReply = getDriver()->processValidReply(reply);
- if (const size_t readCount = getDataMQ()->availableToRead(); readCount > 0) {
- if (readDataFromMQ(readCount)) {
+ if (const size_t readCount =
+ !isMmapped() ? getDataMQ()->availableToRead() : reply.fmqByteCount;
+ readCount > 0) {
+ if (isMmapped() ? readDataFromMmap(readCount) : readDataFromMQ(readCount)) {
goto checkAcceptedReply;
}
LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
@@ -1028,8 +1089,10 @@
LOG(ERROR) << __func__ << ": no next command";
return Status::ABORT;
}
- if (actualSize != 0 && !writeDataToMQ()) {
- return Status::ABORT;
+ if (actualSize != 0) {
+ if (isMmapped() ? !writeDataToMmap() : !writeDataToMQ()) {
+ return Status::ABORT;
+ }
}
LOG(DEBUG) << "Writing command: " << command.toString();
if (!getCommandMQ()->writeBlocking(&command, 1)) {
@@ -1058,7 +1121,7 @@
return Status::ABORT;
}
// It is OK for the implementation to leave data in the MQ when the stream is paused.
- if (reply.state != StreamDescriptor::State::PAUSED &&
+ if (!isMmapped() && reply.state != StreamDescriptor::State::PAUSED &&
getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
<< "available to write " << getDataMQ()->availableToWrite()
@@ -2904,15 +2967,24 @@
class StreamLogicDefaultDriver : public StreamLogicDriver {
public:
- StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes)
- : mCommands(commands), mFrameSizeBytes(frameSizeBytes) {
+ StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes,
+ bool isMmap)
+ : mCommands(commands), mFrameSizeBytes(frameSizeBytes), mIsMmap(isMmap) {
mCommands->rewind();
}
- // The three methods below is intended to be called after the worker
+ // The five methods below is intended to be called after the worker
// thread has joined, thus no extra synchronization is needed.
bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
- bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
+ bool hasObservableRetrogradePosition() const { return mRetrogradeObservablePosition; }
+ bool hasHardwarePositionIncrease() const {
+ // For non-MMap, always return true to pass the validation.
+ return mIsMmap ? mHardwarePositionIncrease : true;
+ }
+ bool hasHardwareRetrogradePosition() const {
+ // For non-MMap, always return false to pass the validation.
+ return mIsMmap ? mRetrogradeHardwarePosition : false;
+ }
std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
bool done() override { return mCommands->done(); }
@@ -2940,14 +3012,24 @@
bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
bool processValidReply(const StreamDescriptor::Reply& reply) override {
if (reply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
- if (mPreviousFrames.has_value()) {
- if (reply.observable.frames > mPreviousFrames.value()) {
+ if (mPreviousObservableFrames.has_value()) {
+ if (reply.observable.frames > mPreviousObservableFrames.value()) {
mObservablePositionIncrease = true;
- } else if (reply.observable.frames < mPreviousFrames.value()) {
+ } else if (reply.observable.frames < mPreviousObservableFrames.value()) {
mRetrogradeObservablePosition = true;
}
}
- mPreviousFrames = reply.observable.frames;
+ mPreviousObservableFrames = reply.observable.frames;
+ }
+ if (mIsMmap) {
+ if (mPreviousHardwareFrames.has_value()) {
+ if (reply.hardware.frames > mPreviousHardwareFrames.value()) {
+ mHardwarePositionIncrease = true;
+ } else if (reply.hardware.frames < mPreviousHardwareFrames.value()) {
+ mRetrogradeHardwarePosition = true;
+ }
+ }
+ mPreviousHardwareFrames = reply.hardware.frames;
}
auto expected = mCommands->getExpectedStates();
@@ -2974,10 +3056,14 @@
protected:
std::shared_ptr<StateSequence> mCommands;
const size_t mFrameSizeBytes;
+ const bool mIsMmap;
std::optional<StreamDescriptor::State> mPreviousState;
- std::optional<int64_t> mPreviousFrames;
+ std::optional<int64_t> mPreviousObservableFrames;
bool mObservablePositionIncrease = false;
bool mRetrogradeObservablePosition = false;
+ std::optional<int64_t> mPreviousHardwareFrames;
+ bool mHardwarePositionIncrease = false;
+ bool mRetrogradeHardwarePosition = false;
std::string mUnexpectedTransition;
};
@@ -2988,8 +3074,8 @@
static bool skipStreamIoTestForMixPortConfig(const AudioPortConfig& portConfig) {
return (portConfig.flags.value().getTag() == AudioIoFlags::input &&
isAnyBitPositionFlagSet(portConfig.flags.value().template get<AudioIoFlags::input>(),
- {AudioInputFlags::MMAP_NOIRQ, AudioInputFlags::VOIP_TX,
- AudioInputFlags::HW_HOTWORD, AudioInputFlags::HOTWORD_TAP})) ||
+ {AudioInputFlags::VOIP_TX, AudioInputFlags::HW_HOTWORD,
+ AudioInputFlags::HOTWORD_TAP})) ||
(portConfig.flags.value().getTag() == AudioIoFlags::output &&
isAnyBitPositionFlagSet(
portConfig.flags.value().template get<AudioIoFlags::output>(),
@@ -3029,8 +3115,8 @@
void StartWorkerToSendBurstCommands() {
const StreamContext* context = mStream->getStreamContext();
- mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(makeBurstCommands(mIsSync),
- context->getFrameSizeBytes());
+ mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(
+ makeBurstCommands(mIsSync), context->getFrameSizeBytes(), context->isMmapped());
mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
*context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
@@ -3047,10 +3133,13 @@
EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
EXPECT_EQ("", mWorkerDriver->getUnexpectedStateTransition());
if (validatePosition) {
- if (IOTraits<Stream>::is_input) {
+ if (IOTraits<Stream>::is_input &&
+ !mStream->getStreamContext()->isMmapped() /*TODO(b/274456992) remove*/) {
EXPECT_TRUE(mWorkerDriver->hasObservablePositionIncrease());
+ EXPECT_TRUE(mWorkerDriver->hasHardwarePositionIncrease());
}
- EXPECT_FALSE(mWorkerDriver->hasRetrogradeObservablePosition());
+ EXPECT_FALSE(mWorkerDriver->hasObservableRetrogradePosition());
+ EXPECT_FALSE(mWorkerDriver->hasHardwareRetrogradePosition());
}
mWorker.reset();
mWorkerDriver.reset();
@@ -3984,7 +4073,7 @@
}
}
- bool ValidateObservablePosition(const AudioDevice& device) {
+ bool ValidatePosition(const AudioDevice& device) {
return !isTelephonyDeviceType(device.type.type);
}
@@ -3998,7 +4087,8 @@
if (skipStreamIoTestForDevice(stream.getDevice())) return;
ASSERT_EQ("", stream.skipTestReason());
StreamLogicDefaultDriver driver(commandsAndStates,
- stream.getStreamContext()->getFrameSizeBytes());
+ stream.getStreamContext()->getFrameSizeBytes(),
+ stream.getStreamContext()->isMmapped());
typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
stream.getStreamEventReceiver());
@@ -4008,11 +4098,14 @@
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(stream.getDevice())) {
- if (validatePositionIncrease) {
+ if (ValidatePosition(stream.getDevice())) {
+ if (validatePositionIncrease &&
+ !stream.getStreamContext()->isMmapped() /*TODO(b/274456992) remove*/) {
EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_TRUE(driver.hasHardwarePositionIncrease());
}
- EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ EXPECT_FALSE(driver.hasObservableRetrogradePosition());
+ EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
}
}
@@ -4028,7 +4121,8 @@
ASSERT_EQ("", stream.skipTestReason());
ASSERT_NO_FATAL_FAILURE(stream.TeardownPatchSetUpStream(module.get()));
StreamLogicDefaultDriver driver(commandsAndStates,
- stream.getStreamContext()->getFrameSizeBytes());
+ stream.getStreamContext()->getFrameSizeBytes(),
+ stream.getStreamContext()->isMmapped());
typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
stream.getStreamEventReceiver());
ASSERT_NO_FATAL_FAILURE(stream.ReconnectPatch(module.get()));
@@ -4039,11 +4133,14 @@
worker.join();
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
- if (ValidateObservablePosition(stream.getDevice())) {
- if (validatePositionIncrease) {
+ if (ValidatePosition(stream.getDevice())) {
+ if (validatePositionIncrease &&
+ !stream.getStreamContext()->isMmapped() /*TODO(b/274456992) remove*/) {
EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_TRUE(driver.hasHardwarePositionIncrease());
}
- EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ EXPECT_FALSE(driver.hasObservableRetrogradePosition());
+ EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
}
}
};