Merge changes I26fd4fd2,Iaadf6e9b,I7d42f8a7,I0482376e into stage-aosp-tm-ts-dev am: 744c329227
Original change: https://googleplex-android-review.googlesource.com/c/platform/hardware/interfaces/+/19345935
Change-Id: I2b54fab89ae38c8060fbec12c080304830a467fc
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 13068dc..505c54c 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -898,10 +898,49 @@
}
};
+class OffloadCallbacks : public IStreamOutCallback {
+ public:
+ Return<void> onDrainReady() override {
+ ALOGI("onDrainReady");
+ {
+ std::lock_guard lg(mLock);
+ mOnDrainReady = true;
+ }
+ mCondVar.notify_one();
+ return {};
+ }
+ Return<void> onWriteReady() override { return {}; }
+ Return<void> onError() override {
+ ALOGW("onError");
+ {
+ std::lock_guard lg(mLock);
+ mOnError = true;
+ }
+ mCondVar.notify_one();
+ return {};
+ }
+ bool waitForDrainReadyOrError() {
+ std::unique_lock l(mLock);
+ if (!mOnDrainReady && !mOnError) {
+ mCondVar.wait(l, [&]() { return mOnDrainReady || mOnError; });
+ }
+ const bool success = !mOnError;
+ mOnDrainReady = mOnError = false;
+ return success;
+ }
+
+ private:
+ std::mutex mLock;
+ bool mOnDrainReady = false;
+ bool mOnError = false;
+ std::condition_variable mCondVar;
+};
+
TEST_P(CompressedOffloadOutputStreamTest, Mp3FormatGaplessOffload) {
doc::test("Check that compressed offload mix ports for MP3 implement gapless offload");
const auto& flags = getOutputFlags();
const bool isNewDeviceLaunchingOnTPlus = property_get_int32("ro.vendor.api_level", 0) >= 33;
+ // See test instantiation, only offload MP3 mix ports are used.
if (std::find_if(flags.begin(), flags.end(), [](const auto& flag) {
return flag == toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD);
}) == flags.end()) {
@@ -912,8 +951,7 @@
GTEST_SKIP() << "Compressed offload mix port does not support gapless offload";
}
}
- // FIXME: The presentation position is not updated if there is no zero padding in data.
- std::vector<uint8_t> offloadData(stream->getBufferSize());
+ std::vector<uint8_t> offloadData;
ASSERT_NO_FATAL_FAILURE(loadData("/data/local/tmp/sine882hz3s.mp3", &offloadData));
ASSERT_FALSE(offloadData.empty());
ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
@@ -923,38 +961,70 @@
const int delay = 576 + 1000;
const int padding = 756 + 1000;
const int durationMs = 3000 - 44;
- // StreamWriter plays 'offloadData' in a loop, possibly using multiple calls to 'write',
- // this depends on the relative sizes of 'offloadData' and the HAL buffer. Writer calls
- // 'onDataWrap' callback each time it wraps around the buffer.
+ auto start = std::chrono::steady_clock::now();
+ auto callbacks = sp<OffloadCallbacks>::make();
+ std::mutex presentationEndLock;
+ std::vector<float> presentationEndTimes;
+ // StreamWriter plays 'offloadData' in a loop, possibly using multiple calls to 'write', this
+ // depends on the relative sizes of 'offloadData' and the HAL buffer. Writer calls 'onDataStart'
+ // each time it starts writing the buffer from the beginning, and 'onDataWrap' callback each
+ // time it wraps around the buffer.
StreamWriter writer(
- stream.get(), stream->getBufferSize(), std::move(offloadData), [&]() /* onDataWrap */ {
- Parameters::set(stream,
- {{AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, std::to_string(delay)},
+ stream.get(), stream->getBufferSize(), std::move(offloadData),
+ [&]() /* onDataStart */ { start = std::chrono::steady_clock::now(); },
+ [&]() /* onDataWrap */ {
+ Return<Result> ret(Result::OK);
+ // Decrease the volume since the test plays a loud sine wave.
+ ret = stream->setVolume(0.1, 0.1);
+ if (!ret.isOk() || ret != Result::OK) {
+ ALOGE("%s: setVolume failed: %s", __func__, toString(ret).c_str());
+ return false;
+ }
+ ret = Parameters::set(
+ stream, {{AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, std::to_string(delay)},
{AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, std::to_string(padding)}});
- stream->drain(AudioDrain::EARLY_NOTIFY);
+ if (!ret.isOk() || ret != Result::OK) {
+ ALOGE("%s: setParameters failed: %s", __func__, toString(ret).c_str());
+ return false;
+ }
+ ret = stream->drain(AudioDrain::EARLY_NOTIFY);
+ if (!ret.isOk() || ret != Result::OK) {
+ ALOGE("%s: drain failed: %s", __func__, toString(ret).c_str());
+ return false;
+ }
+ // FIXME: On some SoCs intermittent errors are possible, ignore them.
+ if (callbacks->waitForDrainReadyOrError()) {
+ const float duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count();
+ std::lock_guard lg(presentationEndLock);
+ presentationEndTimes.push_back(duration);
+ }
+ return true;
});
+ ASSERT_OK(stream->setCallback(callbacks));
ASSERT_TRUE(writer.start());
- ASSERT_TRUE(writer.waitForAtLeastOneCycle());
- // Decrease the volume since the test plays a loud sine wave.
- ASSERT_OK(stream->setVolume(0.1, 0.1));
// How many times to loop the track so that the sum of gapless delay and padding from
// the first presentation end to the last is at least 'presentationeEndPrecisionMs'.
const int playbackNumber = (int)(significantSampleNumber / ((float)delay + padding) + 1);
- std::vector<float> presentationEndTimes;
- uint64_t previousPosition = std::numeric_limits<uint64_t>::max();
- for (int i = 0; i < playbackNumber; ++i) {
- const auto start = std::chrono::steady_clock::now();
- ASSERT_NO_FATAL_FAILURE(
- waitForPresentationPositionAdvance(writer, &previousPosition, &previousPosition));
- presentationEndTimes.push_back(std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now() - start)
- .count());
+ for (bool done = false; !done;) {
+ usleep(presentationeEndPrecisionMs * 1000);
+ {
+ std::lock_guard lg(presentationEndLock);
+ done = presentationEndTimes.size() >= playbackNumber;
+ }
+ ASSERT_FALSE(writer.hasError()) << "Recent write or drain operation has failed";
}
const float avgDuration =
std::accumulate(presentationEndTimes.begin(), presentationEndTimes.end(), 0.0) /
presentationEndTimes.size();
- EXPECT_NEAR(durationMs, avgDuration, presentationeEndPrecisionMs * 0.1);
+ std::stringstream observedEndTimes;
+ std::copy(presentationEndTimes.begin(), presentationEndTimes.end(),
+ std::ostream_iterator<float>(observedEndTimes, ", "));
+ EXPECT_NEAR(durationMs, avgDuration, presentationeEndPrecisionMs * 0.1)
+ << "Observed durations: " << observedEndTimes.str();
writer.stop();
+ EXPECT_OK(stream->clearCallback());
releasePatchIfNeeded();
}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 6c5584d..e46e5b4 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -938,12 +938,13 @@
StreamWriter(IStreamOut* stream, size_t bufferSize)
: mStream(stream), mBufferSize(bufferSize), mData(mBufferSize) {}
StreamWriter(IStreamOut* stream, size_t bufferSize, std::vector<uint8_t>&& data,
- std::function<void()> onDataWrap)
+ std::function<void()> onDataStart, std::function<bool()> onDataWrap)
: mStream(stream),
mBufferSize(bufferSize),
mData(std::move(data)),
+ mOnDataStart(onDataStart),
mOnDataWrap(onDataWrap) {
- ALOGW("StreamWriter data size: %d", (int)mData.size());
+ ALOGI("StreamWriter data size: %d", (int)mData.size());
}
~StreamWriter() {
stop();
@@ -1010,6 +1011,7 @@
ALOGE("command message queue write failed");
return false;
}
+ if (mDataPosition == 0) mOnDataStart();
const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
ALOGE_IF(!success, "data message queue write failed");
@@ -1040,7 +1042,9 @@
ALOGE("bad wait status: %d", ret);
success = false;
}
- if (success && mDataPosition == 0) mOnDataWrap();
+ if (success && mDataPosition == 0) {
+ success = mOnDataWrap();
+ }
return success;
}
@@ -1048,7 +1052,8 @@
IStreamOut* const mStream;
const size_t mBufferSize;
std::vector<uint8_t> mData;
- std::function<void()> mOnDataWrap = []() {};
+ std::function<void()> mOnDataStart = []() {};
+ std::function<bool()> mOnDataWrap = []() { return true; };
size_t mDataPosition = 0;
std::unique_ptr<CommandMQ> mCommandMQ;
std::unique_ptr<DataMQ> mDataMQ;