diff options
author | yucliu <yucliu@google.com> | 2022-03-09 10:59:11 -0800 |
---|---|---|
committer | Yuchen Liu <yucliu@google.com> | 2022-03-25 17:02:29 +0000 |
commit | 5dd30deaae4457f42a60252d4ca6f9da78bc5833 (patch) | |
tree | 167f9679fdb43c38a51a50893cc45951d1687d89 /audio_proxy | |
parent | 3af881dd3ea1d369d0a401cf85d506f0f64cfa3b (diff) | |
download | atv-5dd30deaae4457f42a60252d4ca6f9da78bc5833.tar.gz |
[AudioProxy] PcmOnlyConfigOutputStreamTest
VTS test runs without the audio proxy client app. So audio proxy will
use the DummyBusOutputStream. Change the write behavior to actually
consume the PCMs in realtime.
Bug: 219879559
Test: VtsHalAudioV7_0TargetTest
Change-Id: I904da685f3aafd72d0fb3f22923a9471ae841230
(cherry picked from commit 63c4ab65b17908d056c60e9087923d50c312c7b8)
Diffstat (limited to 'audio_proxy')
-rw-r--r-- | audio_proxy/service/DummyBusOutputStream.cpp | 75 | ||||
-rw-r--r-- | audio_proxy/service/DummyBusOutputStream.h | 19 | ||||
-rw-r--r-- | audio_proxy/service/main.cpp | 2 |
3 files changed, 90 insertions, 6 deletions
diff --git a/audio_proxy/service/DummyBusOutputStream.cpp b/audio_proxy/service/DummyBusOutputStream.cpp index 7a626c9..b18728f 100644 --- a/audio_proxy/service/DummyBusOutputStream.cpp +++ b/audio_proxy/service/DummyBusOutputStream.cpp @@ -14,9 +14,34 @@ #include "DummyBusOutputStream.h" +#include <algorithm> + +#include <aidl/device/google/atv/audio_proxy/TimeSpec.h> #include <android-base/logging.h> +#include <unistd.h> + +using aidl::device::google::atv::audio_proxy::TimeSpec; namespace audio_proxy::service { +namespace { +constexpr int64_t kOneSecInNs = 1'000'000'000; +constexpr int64_t kOneSecInUs = 1'000'000; +constexpr int64_t kOneUSecInNs = 1'000; + +int64_t timespecDelta(const timespec& newTime, const timespec& oldTime) { + int64_t deltaSec = 0; + int64_t deltaNSec = 0; + if (newTime.tv_nsec >= oldTime.tv_nsec) { + deltaSec = newTime.tv_sec - oldTime.tv_sec; + deltaNSec = newTime.tv_nsec - oldTime.tv_nsec; + } else { + deltaSec = newTime.tv_sec - oldTime.tv_sec - 1; + deltaNSec = kOneSecInNs + newTime.tv_nsec - oldTime.tv_nsec; + } + + return deltaSec * kOneSecInUs + deltaNSec / kOneUSecInNs; +} +} // namespace DummyBusOutputStream::DummyBusOutputStream(const std::string& address, const AidlAudioConfig& config, @@ -32,18 +57,62 @@ bool DummyBusOutputStream::flush() { return true; } bool DummyBusOutputStream::close() { return true; } bool DummyBusOutputStream::setVolume(float left, float right) { return true; } -size_t DummyBusOutputStream::availableToWrite() { return 0; } +size_t DummyBusOutputStream::availableToWrite() { + return mWritingFrameSize * mWritingFrameCount; +} AidlWriteStatus DummyBusOutputStream::writeRingBuffer(const uint8_t* firstMem, size_t firstLength, const uint8_t* secondMem, size_t secondLength) { - return {}; + size_t bufferBytes = firstLength + secondLength; + int64_t numFrames = bufferBytes / getFrameSize(); + int64_t durationUs = numFrames * kOneSecInUs / mConfig.sampleRateHz; + + timespec now = {0, 0}; + clock_gettime(CLOCK_MONOTONIC, &now); + if (mStartTime.tv_sec == 0) { + mStartTime = now; + } + + // Check underrun + int64_t elapsedTimeUs = timespecDelta(now, mStartTime); + if (elapsedTimeUs > mInputUsSinceStart) { + // Underrun + mPlayedUsBeforeUnderrun += mInputUsSinceStart; + mStartTime = now; + mInputUsSinceStart = 0; + } + + // Wait if buffer full. + mInputUsSinceStart += durationUs; + int64_t waitTimeUs = mInputUsSinceStart - elapsedTimeUs - mMaxBufferUs; + if (waitTimeUs > 0) { + usleep(waitTimeUs); + clock_gettime(CLOCK_MONOTONIC, &now); + } + + // Calculate played frames. + int64_t playedUs = + mPlayedUsBeforeUnderrun + + std::min(timespecDelta(now, mStartTime), mInputUsSinceStart); + + TimeSpec timeSpec = {now.tv_sec, now.tv_nsec}; + + AidlWriteStatus status; + status.written = bufferBytes; + status.position = {playedUs * mConfig.sampleRateHz / kOneSecInUs, timeSpec}; + + return status; } bool DummyBusOutputStream::prepareForWritingImpl(uint32_t frameSize, uint32_t frameCount) { + // The `frame` here is not audio frame, it doesn't count the sample format and + // channel layout. + mMaxBufferUs = frameSize * frameCount * 10 * kOneSecInUs / + (mConfig.sampleRateHz * getFrameSize()); return true; } -} // namespace audio_proxy::service
\ No newline at end of file +} // namespace audio_proxy::service diff --git a/audio_proxy/service/DummyBusOutputStream.h b/audio_proxy/service/DummyBusOutputStream.h index 400ccf2..c5ca47e 100644 --- a/audio_proxy/service/DummyBusOutputStream.h +++ b/audio_proxy/service/DummyBusOutputStream.h @@ -16,10 +16,12 @@ #include "BusOutputStream.h" +#include <time.h> + namespace audio_proxy::service { -// Impl of BusOutputStream which blocks the write, a.k.a, it always has -// 0 available write space. +// Impl of BusOutputStream which has a small buffer and consumes the audio data +// in real time. class DummyBusOutputStream : public BusOutputStream { public: DummyBusOutputStream(const std::string& address, @@ -41,6 +43,19 @@ class DummyBusOutputStream : public BusOutputStream { protected: bool prepareForWritingImpl(uint32_t frameSize, uint32_t frameCount) override; + + private: + // Buffer capacity. + int64_t mMaxBufferUs = 0; + + // Timestamp for the first played frame. Underrun will reset it. + timespec mStartTime = {0, 0}; + + // Total written buffer size in us after `mStartTime` reset. + int64_t mInputUsSinceStart = 0; + + // Total played buffer size in us before underrun. + int64_t mPlayedUsBeforeUnderrun = 0; }; } // namespace audio_proxy::service
\ No newline at end of file diff --git a/audio_proxy/service/main.cpp b/audio_proxy/service/main.cpp index a277dd3..352ff0d 100644 --- a/audio_proxy/service/main.cpp +++ b/audio_proxy/service/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char** argv) { } // Default stream config. - StreamConfig defaultStreamConfig = {100, 100}; + StreamConfig defaultStreamConfig = {10, 10}; config->streams.emplace("default", defaultStreamConfig); // Config thread pool. |