1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "DummyBusOutputStream.h"
16
17 #include <algorithm>
18
19 #include <aidl/device/google/atv/audio_proxy/TimeSpec.h>
20 #include <android-base/logging.h>
21 #include <unistd.h>
22
23 using aidl::device::google::atv::audio_proxy::TimeSpec;
24
25 namespace audio_proxy::service {
26 namespace {
27 constexpr int64_t kOneSecInNs = 1'000'000'000;
28 constexpr int64_t kOneSecInUs = 1'000'000;
29 constexpr int64_t kOneUSecInNs = 1'000;
30
timespecDelta(const timespec & newTime,const timespec & oldTime)31 int64_t timespecDelta(const timespec& newTime, const timespec& oldTime) {
32 int64_t deltaSec = 0;
33 int64_t deltaNSec = 0;
34 if (newTime.tv_nsec >= oldTime.tv_nsec) {
35 deltaSec = newTime.tv_sec - oldTime.tv_sec;
36 deltaNSec = newTime.tv_nsec - oldTime.tv_nsec;
37 } else {
38 deltaSec = newTime.tv_sec - oldTime.tv_sec - 1;
39 deltaNSec = kOneSecInNs + newTime.tv_nsec - oldTime.tv_nsec;
40 }
41
42 return deltaSec * kOneSecInUs + deltaNSec / kOneUSecInNs;
43 }
44 } // namespace
45
DummyBusOutputStream(const std::string & address,const AidlAudioConfig & config,int32_t flags)46 DummyBusOutputStream::DummyBusOutputStream(const std::string& address,
47 const AidlAudioConfig& config,
48 int32_t flags)
49 : BusOutputStream(address, config, flags) {}
50 DummyBusOutputStream::~DummyBusOutputStream() = default;
51
standby()52 bool DummyBusOutputStream::standby() { return true; }
pause()53 bool DummyBusOutputStream::pause() { return true; }
resume()54 bool DummyBusOutputStream::resume() { return true; }
drain(AidlAudioDrain drain)55 bool DummyBusOutputStream::drain(AidlAudioDrain drain) { return true; }
flush()56 bool DummyBusOutputStream::flush() { return true; }
close()57 bool DummyBusOutputStream::close() { return true; }
setVolume(float left,float right)58 bool DummyBusOutputStream::setVolume(float left, float right) { return true; }
59
availableToWrite()60 size_t DummyBusOutputStream::availableToWrite() {
61 return mWritingFrameSize * mWritingFrameCount;
62 }
63
writeRingBuffer(const uint8_t * firstMem,size_t firstLength,const uint8_t * secondMem,size_t secondLength)64 AidlWriteStatus DummyBusOutputStream::writeRingBuffer(const uint8_t* firstMem,
65 size_t firstLength,
66 const uint8_t* secondMem,
67 size_t secondLength) {
68 size_t bufferBytes = firstLength + secondLength;
69 int64_t numFrames = bufferBytes / getFrameSize();
70 int64_t durationUs = numFrames * kOneSecInUs / mConfig.sampleRateHz;
71
72 timespec now = {0, 0};
73 clock_gettime(CLOCK_MONOTONIC, &now);
74 if (mStartTime.tv_sec == 0) {
75 mStartTime = now;
76 }
77
78 // Check underrun
79 int64_t elapsedTimeUs = timespecDelta(now, mStartTime);
80 if (elapsedTimeUs > mInputUsSinceStart) {
81 // Underrun
82 mPlayedUsBeforeUnderrun += mInputUsSinceStart;
83 mStartTime = now;
84 mInputUsSinceStart = 0;
85 }
86
87 // Wait if buffer full.
88 mInputUsSinceStart += durationUs;
89 int64_t waitTimeUs = mInputUsSinceStart - elapsedTimeUs - mMaxBufferUs;
90 if (waitTimeUs > 0) {
91 usleep(waitTimeUs);
92 clock_gettime(CLOCK_MONOTONIC, &now);
93 }
94
95 // Calculate played frames.
96 int64_t playedUs =
97 mPlayedUsBeforeUnderrun +
98 std::min(timespecDelta(now, mStartTime), mInputUsSinceStart);
99
100 TimeSpec timeSpec = {now.tv_sec, now.tv_nsec};
101
102 AidlWriteStatus status;
103 status.written = bufferBytes;
104 status.position = {playedUs * mConfig.sampleRateHz / kOneSecInUs, timeSpec};
105
106 return status;
107 }
108
prepareForWritingImpl(uint32_t frameSize,uint32_t frameCount)109 bool DummyBusOutputStream::prepareForWritingImpl(uint32_t frameSize,
110 uint32_t frameCount) {
111 // The `frame` here is not audio frame, it doesn't count the sample format and
112 // channel layout.
113 mMaxBufferUs = frameSize * frameCount * 10 * kOneSecInUs /
114 (mConfig.sampleRateHz * getFrameSize());
115 return true;
116 }
117
start()118 bool DummyBusOutputStream::start() { return false; }
119
stop()120 bool DummyBusOutputStream::stop() { return false; };
121
createMmapBuffer(int32_t minBufferSizeFrames)122 AidlMmapBufferInfo DummyBusOutputStream::createMmapBuffer(
123 int32_t minBufferSizeFrames) {
124 return AidlMmapBufferInfo();
125 }
126
getMmapPosition()127 AidlPresentationPosition DummyBusOutputStream::getMmapPosition() {
128 return AidlPresentationPosition();
129 }
130
131 } // namespace audio_proxy::service
132