libaudiohal@aidl: Align position reporting with HIDL
Update comments in StreamHalInterface to align with HIDL HAL
framework contract. Update StreamHalAidl to match the contract.
Bug: 338557486
Test: atest CtsMediaAudioTestCases
(cherry picked from https://android-review.googlesource.com/q/commit:f0a9fbc32ce1a89d987e18580b28585c0b2f4bac)
Merged-In: I7c21b93c1cc985b7176d2e7ec0207ee0f9abbdb1
Change-Id: I7c21b93c1cc985b7176d2e7ec0207ee0f9abbdb1
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 9d32be6..941927f 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -285,11 +285,12 @@
return OK;
}
-status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
+status_t StreamHalAidl::getObservablePosition(int64_t* frames, int64_t* timestamp,
+ StatePositions* statePositions) {
ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
- RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+ RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply, statePositions));
*frames = std::max<int64_t>(0, reply.observable.frames);
*timestamp = std::max<int64_t>(0, reply.observable.timeNs);
return OK;
@@ -437,8 +438,12 @@
if (auto state = getState(); state == StreamDescriptor::State::DRAINING) {
// Retrieve the current state together with position counters unconditionally
// to ensure that the state on our side gets updated.
- sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(),
- nullptr, true /*safeFromNonWorkerThread */);
+ sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), nullptr,
+ true /*safeFromNonWorkerThread */);
+ // For compatibility with HIDL behavior, apply a "soft" position reset
+ // after receiving the "drain ready" callback.
+ std::lock_guard l(mLock);
+ mStatePositions.framesAtFlushOrDrain = mLastReply.observable.frames;
} else {
ALOGW("%s: unexpected onDrainReady in the state %s", __func__, toString(state).c_str());
}
@@ -505,9 +510,9 @@
}
status_t StreamHalAidl::sendCommand(
- const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
+ const ::aidl::android::hardware::audio::core::StreamDescriptor::Command& command,
::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
- bool safeFromNonWorkerThread) {
+ bool safeFromNonWorkerThread, StatePositions* statePositions) {
// TIME_CHECK(); // TODO(b/243839867) reenable only when optimized.
if (!safeFromNonWorkerThread) {
const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
@@ -539,6 +544,23 @@
}
mLastReply = *reply;
mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
+ if (!mIsInput && reply->status == STATUS_OK) {
+ if (command.getTag() == StreamDescriptor::Command::standby &&
+ reply->state == StreamDescriptor::State::STANDBY) {
+ mStatePositions.framesAtStandby = reply->observable.frames;
+ } else if (command.getTag() == StreamDescriptor::Command::flush &&
+ reply->state == StreamDescriptor::State::IDLE) {
+ mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
+ } else if (!mContext.isAsynchronous() &&
+ command.getTag() == StreamDescriptor::Command::drain &&
+ (reply->state == StreamDescriptor::State::IDLE ||
+ reply->state == StreamDescriptor::State::DRAINING)) {
+ mStatePositions.framesAtFlushOrDrain = reply->observable.frames;
+ } // for asynchronous drain, the frame count is saved in 'onAsyncDrainReady'
+ }
+ if (statePositions != nullptr) {
+ *statePositions = mStatePositions;
+ }
}
}
switch (reply->status) {
@@ -554,7 +576,8 @@
}
status_t StreamHalAidl::updateCountersIfNeeded(
- ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
+ StatePositions* statePositions) {
bool doUpdate = false;
{
std::lock_guard l(mLock);
@@ -564,10 +587,13 @@
// 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 */);
+ reply, true /*safeFromNonWorkerThread */, statePositions);
} else if (reply != nullptr) { // provide cached reply
std::lock_guard l(mLock);
*reply = mLastReply;
+ if (statePositions != nullptr) {
+ *statePositions = mStatePositions;
+ }
}
return OK;
}
@@ -659,8 +685,19 @@
return BAD_VALUE;
}
int64_t aidlFrames = 0, aidlTimestamp = 0;
- RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
- *dspFrames = aidlFrames;
+ StatePositions statePositions{};
+ RETURN_STATUS_IF_ERROR(
+ getObservablePosition(&aidlFrames, &aidlTimestamp, &statePositions));
+ // Number of audio frames since the stream has exited standby.
+ // See the table at the start of 'StreamHalInterface' on when it needs to reset.
+ int64_t mostRecentResetPoint;
+ if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
+ mostRecentResetPoint = statePositions.framesAtStandby;
+ } else {
+ mostRecentResetPoint =
+ std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
+ }
+ *dspFrames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
return OK;
}
@@ -717,8 +754,16 @@
return BAD_VALUE;
}
int64_t aidlFrames = 0, aidlTimestamp = 0;
- RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
- *frames = aidlFrames;
+ StatePositions statePositions{};
+ RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp, &statePositions));
+ // See the table at the start of 'StreamHalInterface'.
+ if (!mContext.isAsynchronous() && audio_has_proportional_frames(mConfig.format)) {
+ *frames = aidlFrames;
+ } else {
+ const int64_t mostRecentResetPoint =
+ std::max(statePositions.framesAtStandby, statePositions.framesAtFlushOrDrain);
+ *frames = aidlFrames <= mostRecentResetPoint ? 0 : aidlFrames - mostRecentResetPoint;
+ }
timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
return OK;