diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2022-08-02 23:21:35 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-08-02 23:21:35 +0000 |
commit | 5c5c78aa51a2cdcabb5afe7c63093d8ed67f8082 (patch) | |
tree | 8352901944a1cf78915c7ec7e26d0d5197d12680 | |
parent | b9b5652fcc4d1de82df67d781ade0dda8bbde623 (diff) | |
parent | 744c3292278b9801f25fd10ea393ba66b21ba489 (diff) |
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>
-rw-r--r-- | audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp | 114 | ||||
-rw-r--r-- | audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h | 13 |
2 files changed, 101 insertions, 26 deletions
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 13068dce94..505c54c1df 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 CompressedOffloadOutputStreamTest : public PcmOnlyConfigOutputStreamTest { } }; +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 @@ TEST_P(CompressedOffloadOutputStreamTest, Mp3FormatGaplessOffload) { 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 @@ TEST_P(CompressedOffloadOutputStreamTest, Mp3FormatGaplessOffload) { 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 6c5584d427..e46e5b4f52 100644 --- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h +++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h @@ -938,12 +938,13 @@ class StreamWriter : public StreamWorker<StreamWriter> { 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 @@ class StreamWriter : public StreamWorker<StreamWriter> { 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 @@ class StreamWriter : public StreamWorker<StreamWriter> { 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 @@ class StreamWriter : public StreamWorker<StreamWriter> { 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; |