1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <chrono>
18 #include <thread>
19 #include <log/log.h>
20 #include <utils/Timers.h>
21 #include <utils/ThreadDefs.h>
22 #include "device_port_sink.h"
23 #include "talsa.h"
24 #include "audio_ops.h"
25 #include "ring_buffer.h"
26 #include "util.h"
27 #include "debug.h"
28
29 namespace android {
30 namespace hardware {
31 namespace audio {
32 namespace V6_0 {
33 namespace implementation {
34
35 namespace {
36
37 constexpr int kMaxJitterUs = 3000; // Enforced by CTS, should be <= 6ms
38
39 struct TinyalsaSink : public DevicePortSink {
TinyalsaSinkandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink40 TinyalsaSink(unsigned pcmCard, unsigned pcmDevice,
41 const AudioConfig &cfg,
42 uint64_t &frames)
43 : mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
44 , mSampleRateHz(cfg.sampleRateHz)
45 , mFrameSize(util::countChannels(cfg.channelMask) * sizeof(int16_t))
46 , mWriteSizeFrames(cfg.frameCount)
47 , mFrames(frames)
48 , mRingBuffer(mFrameSize * cfg.frameCount * 3)
49 , mMixer(pcmCard)
50 , mPcm(talsa::pcmOpen(pcmCard, pcmDevice,
51 util::countChannels(cfg.channelMask),
52 cfg.sampleRateHz,
53 cfg.frameCount,
54 true /* isOut */)) {
55 mConsumeThread = std::thread(&TinyalsaSink::consumeThread, this);
56 }
57
~TinyalsaSinkandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink58 ~TinyalsaSink() {
59 mConsumeThreadRunning = false;
60 mConsumeThread.join();
61 }
62
getPresentationPositionandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink63 Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
64 const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
65 const uint64_t nowFrames = getPresentationFrames(nowNs);
66 mFrames += (nowFrames - mPreviousFrames);
67 mPreviousFrames = nowFrames;
68
69 frames = mFrames;
70 ts = util::nsecs2TimeSpec(nowNs);
71 return Result::OK;
72 }
73
getPresentationFramesandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink74 uint64_t getPresentationFrames(const nsecs_t nowNs) const {
75 return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
76 }
77
getAvailableFramesandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink78 uint64_t getAvailableFrames(const nsecs_t nowNs) const {
79 return getPresentationFrames(nowNs) - mReceivedFrames;
80 }
81
getAvailableFramesNowandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink82 uint64_t getAvailableFramesNow() const {
83 return getAvailableFrames(systemTime(SYSTEM_TIME_MONOTONIC));
84 }
85
getWaitFramesNowandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink86 size_t getWaitFramesNow(const size_t requestedFrames) const {
87 const size_t availableFrames = getAvailableFramesNow();
88 return (requestedFrames > availableFrames)
89 ? (requestedFrames - availableFrames) : 0;
90 }
91
writeandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink92 size_t write(float volume, size_t bytesToWrite, IReader &reader) {
93 size_t framesLost = 0;
94 const size_t waitFrames = getWaitFramesNow(bytesToWrite / mFrameSize);
95 const auto blockUntil =
96 std::chrono::high_resolution_clock::now() +
97 + std::chrono::microseconds(waitFrames * 1000000 / mSampleRateHz);
98
99 while (bytesToWrite > 0) {
100 if (mRingBuffer.waitForProduceAvailable(blockUntil
101 + std::chrono::microseconds(kMaxJitterUs))) {
102 auto produceChunk = mRingBuffer.getProduceChunk();
103 if (produceChunk.size >= bytesToWrite) {
104 // Since the ring buffer has more bytes free than we need,
105 // make sure we are not too early here: tinyalsa is jittery,
106 // we don't want to go faster than SYSTEM_TIME_MONOTONIC
107 std::this_thread::sleep_until(blockUntil);
108 }
109
110 const size_t szFrames =
111 std::min(produceChunk.size, bytesToWrite) / mFrameSize;
112 const size_t szBytes = szFrames * mFrameSize;
113 LOG_ALWAYS_FATAL_IF(reader(produceChunk.data, szBytes) < szBytes);
114
115 aops::multiplyByVolume(volume,
116 static_cast<int16_t *>(produceChunk.data),
117 szBytes / sizeof(int16_t));
118
119 LOG_ALWAYS_FATAL_IF(mRingBuffer.produce(szBytes) < szBytes);
120 mReceivedFrames += szFrames;
121 bytesToWrite -= szBytes;
122 } else {
123 ALOGW("TinyalsaSink::%s:%d pcm_write was late reading "
124 "frames, dropping %zu us of audio",
125 __func__, __LINE__,
126 size_t(1000000 * bytesToWrite / mFrameSize / mSampleRateHz));
127
128 // drop old audio to make room for new
129 const size_t bytesLost = mRingBuffer.makeRoomForProduce(bytesToWrite);
130 framesLost += bytesLost / mFrameSize;
131
132 while (bytesToWrite > 0) {
133 auto produceChunk = mRingBuffer.getProduceChunk();
134 const size_t szFrames =
135 std::min(produceChunk.size, bytesToWrite) / mFrameSize;
136 const size_t szBytes = szFrames * mFrameSize;
137 LOG_ALWAYS_FATAL_IF(reader(produceChunk.data, szBytes) < szBytes);
138
139 aops::multiplyByVolume(volume,
140 static_cast<int16_t *>(produceChunk.data),
141 szBytes / sizeof(int16_t));
142
143 LOG_ALWAYS_FATAL_IF(mRingBuffer.produce(szBytes) < szBytes);
144 mReceivedFrames += szFrames;
145 bytesToWrite -= szBytes;
146 }
147 break;
148 }
149 }
150
151 return framesLost;
152 }
153
consumeThreadandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink154 void consumeThread() {
155 util::setThreadPriority(PRIORITY_URGENT_AUDIO);
156 std::vector<uint8_t> writeBuffer(mWriteSizeFrames * mFrameSize);
157
158 while (mConsumeThreadRunning) {
159 if (mRingBuffer.waitForConsumeAvailable(
160 std::chrono::high_resolution_clock::now()
161 + std::chrono::microseconds(100000))) {
162 size_t szBytes;
163 {
164 auto chunk = mRingBuffer.getConsumeChunk();
165 szBytes = std::min(writeBuffer.size(), chunk.size);
166 // We have to memcpy because the consumer holds the lock
167 // into RingBuffer and pcm_write takes too long to hold
168 // this lock.
169 memcpy(writeBuffer.data(), chunk.data, szBytes);
170 LOG_ALWAYS_FATAL_IF(mRingBuffer.consume(chunk, szBytes) < szBytes);
171 }
172
173 int res = ::pcm_write(mPcm.get(), writeBuffer.data(), szBytes);
174 if (res < 0) {
175 ALOGW("TinyalsaSink::%s:%d pcm_write failed with res=%d",
176 __func__, __LINE__, res);
177 }
178 }
179 }
180 }
181
createandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::TinyalsaSink182 static std::unique_ptr<TinyalsaSink> create(unsigned pcmCard,
183 unsigned pcmDevice,
184 const AudioConfig &cfg,
185 size_t readerBufferSizeHint,
186 uint64_t &frames) {
187 (void)readerBufferSizeHint;
188 auto sink = std::make_unique<TinyalsaSink>(pcmCard, pcmDevice,
189 cfg, frames);
190 if (sink->mMixer && sink->mPcm) {
191 return sink;
192 } else {
193 return FAILURE(nullptr);
194 }
195 }
196
197 private:
198 const nsecs_t mStartNs;
199 const unsigned mSampleRateHz;
200 const unsigned mFrameSize;
201 const unsigned mWriteSizeFrames;
202 uint64_t &mFrames;
203 uint64_t mPreviousFrames = 0;
204 uint64_t mReceivedFrames = 0;
205 RingBuffer mRingBuffer;
206 talsa::Mixer mMixer;
207 talsa::PcmPtr mPcm;
208 std::thread mConsumeThread;
209 std::atomic<bool> mConsumeThreadRunning = true;
210 };
211
212 struct NullSink : public DevicePortSink {
NullSinkandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::NullSink213 NullSink(const AudioConfig &cfg, uint64_t &frames)
214 : mFrames(frames)
215 , mSampleRateHz(cfg.sampleRateHz)
216 , mNChannels(util::countChannels(cfg.channelMask))
217 , mTimestamp(systemTime(SYSTEM_TIME_MONOTONIC)) {}
218
getPresentationPositionandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::NullSink219 Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
220 simulatePresentationPosition();
221 frames = mFrames;
222 ts = util::nsecs2TimeSpec(mTimestamp);
223 return Result::OK;
224 }
225
writeandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::NullSink226 size_t write(float volume, size_t bytesToWrite, IReader &reader) override {
227 (void)volume;
228
229 while (bytesToWrite > 0) {
230 size_t chunkSize = std::min(bytesToWrite, sizeof(mWriteBuffer));
231 chunkSize = reader(mWriteBuffer, chunkSize);
232 if (chunkSize > 0) {
233 bytesToWrite -= chunkSize;
234 } else {
235 break; // reader failed
236 }
237 }
238
239 return 0;
240 }
241
simulatePresentationPositionandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::NullSink242 void simulatePresentationPosition() {
243 const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
244 const nsecs_t deltaNs = nowNs - mTimestamp;
245 const uint64_t deltaFrames = uint64_t(mSampleRateHz) * ns2ms(deltaNs) / 1000;
246 const uint64_t f = std::min(deltaFrames, mAvailableFrames);
247
248 mFrames += f;
249 mAvailableFrames -= f;
250 if (mAvailableFrames) {
251 mTimestamp += us2ns(f * 1000000 / mSampleRateHz);
252 } else {
253 mTimestamp = nowNs;
254 }
255 }
256
createandroid::hardware::audio::V6_0::implementation::__anonb8135f430111::NullSink257 static std::unique_ptr<NullSink> create(const AudioConfig &cfg,
258 size_t readerBufferSizeHint,
259 uint64_t &frames) {
260 (void)readerBufferSizeHint;
261 return std::make_unique<NullSink>(cfg, frames);
262 }
263
264 private:
265 uint64_t &mFrames;
266 const unsigned mSampleRateHz;
267 const unsigned mNChannels;
268 uint64_t mAvailableFrames = 0;
269 nsecs_t mTimestamp;
270 char mWriteBuffer[1024];
271 };
272
273 } // namespace
274
275 std::unique_ptr<DevicePortSink>
create(size_t readerBufferSizeHint,const DeviceAddress & address,const AudioConfig & cfg,const hidl_bitfield<AudioOutputFlag> & flags,uint64_t & frames)276 DevicePortSink::create(size_t readerBufferSizeHint,
277 const DeviceAddress &address,
278 const AudioConfig &cfg,
279 const hidl_bitfield<AudioOutputFlag> &flags,
280 uint64_t &frames) {
281 (void)flags;
282
283 if (cfg.format != AudioFormat::PCM_16_BIT) {
284 ALOGE("%s:%d Only PCM_16_BIT is supported", __func__, __LINE__);
285 return FAILURE(nullptr);
286 }
287
288 switch (address.device) {
289 case AudioDevice::OUT_SPEAKER:
290 return TinyalsaSink::create(talsa::kPcmCard, talsa::kPcmDevice,
291 cfg, readerBufferSizeHint, frames);
292
293 case AudioDevice::OUT_TELEPHONY_TX:
294 return NullSink::create(cfg, readerBufferSizeHint, frames);
295
296 default:
297 ALOGE("%s:%d unsupported device: %x", __func__, __LINE__, address.device);
298 return FAILURE(nullptr);
299 }
300 }
301
302 } // namespace implementation
303 } // namespace V6_0
304 } // namespace audio
305 } // namespace hardware
306 } // namespace android
307