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 PATH(APM_XSD_ENUMS_H_FILENAME)
18 #include <android-base/properties.h>
19 #include <chrono>
20 #include <thread>
21 #include <log/log.h>
22 #include <utils/Mutex.h>
23 #include <utils/Timers.h>
24 #include <utils/ThreadDefs.h>
25 #include "device_port_sink.h"
26 #include "talsa.h"
27 #include "audio_ops.h"
28 #include "ring_buffer.h"
29 #include "util.h"
30 #include "debug.h"
31 
32 using ::android::base::GetBoolProperty;
33 
34 namespace xsd {
35 using namespace ::android::audio::policy::configuration::CPP_VERSION;
36 }
37 
38 namespace android {
39 namespace hardware {
40 namespace audio {
41 namespace CPP_VERSION {
42 namespace implementation {
43 
44 namespace {
45 
46 constexpr int kMaxJitterUs = 3000;  // Enforced by CTS, should be <= 6ms
47 
48 struct TinyalsaSink : public DevicePortSink {
TinyalsaSinkandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink49     TinyalsaSink(unsigned pcmCard, unsigned pcmDevice,
50                  const AudioConfig &cfg,
51                  uint64_t initialFrames)
52             : mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
53             , mSampleRateHz(cfg.base.sampleRateHz)
54             , mFrameSize(util::countChannels(cfg.base.channelMask) * sizeof(int16_t))
55             , mWriteSizeFrames(cfg.frameCount)
56             , mInitialFrames(initialFrames)
57             , mFrames(initialFrames)
58             , mRingBuffer(mFrameSize * cfg.frameCount * 3)
59             , mMixer(pcmCard)
60             , mPcm(talsa::pcmOpen(pcmCard, pcmDevice,
61                                   util::countChannels(cfg.base.channelMask),
62                                   cfg.base.sampleRateHz,
63                                   cfg.frameCount,
64                                   true /* isOut */)) {
65         if (mPcm) {
66             mConsumeThread = std::thread(&TinyalsaSink::consumeThread, this);
67         } else {
68             mConsumeThread = std::thread([](){});
69         }
70     }
71 
~TinyalsaSinkandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink72     ~TinyalsaSink() {
73         mConsumeThreadRunning = false;
74         mConsumeThread.join();
75     }
76 
getLatencyMsandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink77     static int getLatencyMs(const AudioConfig &cfg) {
78         constexpr size_t inMs = 1000;
79         const talsa::PcmPeriodSettings periodSettings =
80             talsa::pcmGetPcmPeriodSettings();
81         const size_t numerator = periodSettings.periodSizeMultiplier * cfg.frameCount;
82         const size_t denominator = periodSettings.periodCount * cfg.base.sampleRateHz / inMs;
83 
84         // integer division with rounding
85         return (numerator + (denominator >> 1)) / denominator + talsa::pcmGetHostLatencyMs();
86     }
87 
getPresentationPositionandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink88     Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
89         const AutoMutex lock(mFrameCountersMutex);
90 
91         nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
92         const uint64_t nowFrames = getPresentationFramesLocked(nowNs);
93         auto presentedFrames = nowFrames - mMissedFrames;
94         if (presentedFrames > mReceivedFrames) {
95           // There is another underrun that is not yet accounted for in mMissedFrames
96           auto delta = presentedFrames - mReceivedFrames;
97           presentedFrames -= delta;
98           // The last frame was presented some time ago, reflect that in the result
99           nowNs -= delta * 1000000000 / mSampleRateHz;
100         }
101         mFrames = presentedFrames + mInitialFrames;
102 
103         frames = mFrames;
104         ts = util::nsecs2TimeSpec(nowNs);
105         return Result::OK;
106     }
107 
getPresentationFramesLockedandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink108     uint64_t getPresentationFramesLocked(const nsecs_t nowNs) const {
109         return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
110     }
111 
calcAvailableFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink112     size_t calcAvailableFramesNowLocked() {
113         const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
114         auto presentationFrames = getPresentationFramesLocked(nowNs);
115         if (mReceivedFrames + mMissedFrames < presentationFrames) {
116             // There has been an underrun
117             mMissedFrames = presentationFrames - mReceivedFrames;
118         }
119         size_t pendingFrames = mReceivedFrames + mMissedFrames - presentationFrames;
120         return mRingBuffer.capacity() / mFrameSize - pendingFrames;
121     }
122 
calcWaitFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink123     size_t calcWaitFramesNowLocked(const size_t requestedFrames) {
124         const size_t availableFrames = calcAvailableFramesNowLocked();
125         return (requestedFrames > availableFrames)
126             ? (requestedFrames - availableFrames) : 0;
127     }
128 
writeandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink129     size_t write(float volume, size_t bytesToWrite, IReader &reader) override {
130         const AutoMutex lock(mFrameCountersMutex);
131 
132         size_t framesLost = 0;
133         const size_t waitFrames = calcWaitFramesNowLocked(bytesToWrite / mFrameSize);
134         const auto blockUntil =
135             std::chrono::high_resolution_clock::now() +
136                 + std::chrono::microseconds(waitFrames * 1000000 / mSampleRateHz);
137 
138         while (bytesToWrite > 0) {
139             if (mRingBuffer.waitForProduceAvailable(blockUntil
140                     + std::chrono::microseconds(kMaxJitterUs))) {
141                 auto produceChunk = mRingBuffer.getProduceChunk();
142                 if (produceChunk.size >= bytesToWrite) {
143                     // Since the ring buffer has more bytes free than we need,
144                     // make sure we are not too early here: tinyalsa is jittery,
145                     // we don't want to go faster than SYSTEM_TIME_MONOTONIC
146                     std::this_thread::sleep_until(blockUntil);
147                 }
148 
149                 const size_t szFrames =
150                     std::min(produceChunk.size, bytesToWrite) / mFrameSize;
151                 const size_t szBytes = szFrames * mFrameSize;
152                 LOG_ALWAYS_FATAL_IF(reader(produceChunk.data, szBytes) < szBytes);
153 
154                 aops::multiplyByVolume(volume,
155                                        static_cast<int16_t *>(produceChunk.data),
156                                        szBytes / sizeof(int16_t));
157 
158                 LOG_ALWAYS_FATAL_IF(mRingBuffer.produce(szBytes) < szBytes);
159                 mReceivedFrames += szFrames;
160                 bytesToWrite -= szBytes;
161             } else {
162                 ALOGV("TinyalsaSink::%s:%d pcm_writei was late reading "
163                       "frames, dropping %zu us of audio",
164                       __func__, __LINE__,
165                       size_t(1000000 * bytesToWrite / mFrameSize / mSampleRateHz));
166 
167                 // drop old audio to make room for new
168                 const size_t bytesLost = mRingBuffer.makeRoomForProduce(bytesToWrite);
169                 framesLost += bytesLost / mFrameSize;
170 
171                 while (bytesToWrite > 0) {
172                     auto produceChunk = mRingBuffer.getProduceChunk();
173                     const size_t szFrames =
174                         std::min(produceChunk.size, bytesToWrite) / mFrameSize;
175                     const size_t szBytes = szFrames * mFrameSize;
176                     LOG_ALWAYS_FATAL_IF(reader(produceChunk.data, szBytes) < szBytes);
177 
178                     aops::multiplyByVolume(volume,
179                                            static_cast<int16_t *>(produceChunk.data),
180                                            szBytes / sizeof(int16_t));
181 
182                     LOG_ALWAYS_FATAL_IF(mRingBuffer.produce(szBytes) < szBytes);
183                     mReceivedFrames += szFrames;
184                     bytesToWrite -= szBytes;
185                 }
186                 break;
187             }
188         }
189 
190         return framesLost;
191     }
192 
consumeThreadandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink193     void consumeThread() {
194         util::setThreadPriority(SP_AUDIO_SYS, PRIORITY_AUDIO);
195         std::vector<uint8_t> writeBuffer(mWriteSizeFrames * mFrameSize);
196 
197         while (mConsumeThreadRunning) {
198             if (mRingBuffer.waitForConsumeAvailable(
199                     std::chrono::high_resolution_clock::now()
200                     + std::chrono::microseconds(100000))) {
201                 size_t szBytes;
202                 {
203                     auto chunk = mRingBuffer.getConsumeChunk();
204                     szBytes = std::min(writeBuffer.size(), chunk.size);
205                     // We have to memcpy because the consumer holds the lock
206                     // into RingBuffer and pcm_write takes too long to hold
207                     // this lock.
208                     memcpy(writeBuffer.data(), chunk.data, szBytes);
209                     LOG_ALWAYS_FATAL_IF(mRingBuffer.consume(chunk, szBytes) < szBytes);
210                 }
211 
212                 const uint8_t *data8 = writeBuffer.data();
213                 while (szBytes > 0) {
214                     const int n = talsa::pcmWrite(mPcm.get(), data8, szBytes, mFrameSize);
215                     if (n < 0) {
216                         break;
217                     }
218                     LOG_ALWAYS_FATAL_IF(static_cast<size_t>(n) > szBytes,
219                                         "n=%d szBytes=%zu mFrameSize=%u",
220                                         n, szBytes, mFrameSize);
221                     data8 += n;
222                     szBytes -= n;
223                 }
224             }
225         }
226     }
227 
createandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::TinyalsaSink228     static std::unique_ptr<TinyalsaSink> create(unsigned pcmCard,
229                                                 unsigned pcmDevice,
230                                                 const AudioConfig &cfg,
231                                                 size_t readerBufferSizeHint,
232                                                 uint64_t initialFrames) {
233         (void)readerBufferSizeHint;
234         auto sink = std::make_unique<TinyalsaSink>(pcmCard, pcmDevice,
235                                                    cfg, initialFrames);
236         if (sink->mMixer && sink->mPcm) {
237             return sink;
238         } else {
239             return FAILURE(nullptr);
240         }
241     }
242 
243 private:
244     const nsecs_t mStartNs;
245     const unsigned mSampleRateHz;
246     const unsigned mFrameSize;
247     const unsigned mWriteSizeFrames;
248     const uint64_t mInitialFrames;
249     uint64_t mFrames GUARDED_BY(mFrameCountersMutex);
250     uint64_t mMissedFrames GUARDED_BY(mFrameCountersMutex) = 0;
251     uint64_t mReceivedFrames GUARDED_BY(mFrameCountersMutex) = 0;
252     RingBuffer mRingBuffer;
253     talsa::Mixer mMixer;
254     talsa::PcmPtr mPcm;
255     std::thread mConsumeThread;
256     std::atomic<bool> mConsumeThreadRunning = true;
257     mutable Mutex mFrameCountersMutex;
258 };
259 
260 struct NullSink : public DevicePortSink {
NullSinkandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink261     NullSink(const AudioConfig &cfg, uint64_t initialFrames)
262             : mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
263             , mSampleRateHz(cfg.base.sampleRateHz)
264             , mFrameSize(util::countChannels(cfg.base.channelMask) * sizeof(int16_t))
265             , mInitialFrames(initialFrames)
266             , mFrames(initialFrames) {}
267 
getLatencyMsandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink268     static int getLatencyMs(const AudioConfig &) {
269         return 1;
270     }
271 
getPresentationPositionandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink272     Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
273         const AutoMutex lock(mFrameCountersMutex);
274 
275         nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
276         const uint64_t nowFrames = getPresentationFramesLocked(nowNs);
277         auto presentedFrames = nowFrames - mMissedFrames;
278         if (presentedFrames > mReceivedFrames) {
279           // There is another underrun that is not yet accounted for in mMissedFrames
280           auto delta = presentedFrames - mReceivedFrames;
281           presentedFrames -= delta;
282           // The last frame was presented some time ago, reflect that in the result
283           nowNs -= delta * 1000000000 / mSampleRateHz;
284         }
285         mFrames = presentedFrames + mInitialFrames;
286 
287         frames = mFrames;
288         ts = util::nsecs2TimeSpec(nowNs);
289         return Result::OK;
290     }
291 
getPresentationFramesLockedandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink292     uint64_t getPresentationFramesLocked(const nsecs_t nowNs) const {
293         return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
294     }
295 
calcAvailableFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink296     size_t calcAvailableFramesNowLocked() {
297         const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
298         auto presentationFrames = getPresentationFramesLocked(nowNs);
299         if (mReceivedFrames + mMissedFrames < presentationFrames) {
300             // There has been an underrun
301             mMissedFrames = presentationFrames - mReceivedFrames;
302         }
303         size_t pendingFrames = mReceivedFrames + mMissedFrames - presentationFrames;
304         return sizeof(mWriteBuffer) / mFrameSize - pendingFrames;
305     }
306 
calcWaitFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink307     size_t calcWaitFramesNowLocked(const size_t requestedFrames) {
308         const size_t availableFrames = calcAvailableFramesNowLocked();
309         return (requestedFrames > availableFrames)
310             ? (requestedFrames - availableFrames) : 0;
311     }
312 
writeandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink313     size_t write(float volume, size_t bytesToWrite, IReader &reader) override {
314         (void)volume;
315         const AutoMutex lock(mFrameCountersMutex);
316 
317         const size_t waitFrames = calcWaitFramesNowLocked(bytesToWrite / mFrameSize);
318         const auto blockUntil =
319             std::chrono::high_resolution_clock::now() +
320                 + std::chrono::microseconds(waitFrames * 1000000 / mSampleRateHz);
321         std::this_thread::sleep_until(blockUntil);
322 
323         while (bytesToWrite > 0) {
324             size_t chunkSize =
325                 std::min(bytesToWrite, sizeof(mWriteBuffer)) / mFrameSize * mFrameSize;
326             chunkSize = reader(mWriteBuffer, chunkSize);
327             if (chunkSize > 0) {
328                 mReceivedFrames += chunkSize / mFrameSize;
329                 bytesToWrite -= chunkSize;
330             } else {
331                 break; // reader failed
332             }
333         }
334 
335         return 0;
336     }
337 
createandroid::hardware::audio::CPP_VERSION::implementation::__anonb8135f430111::NullSink338     static std::unique_ptr<NullSink> create(const AudioConfig &cfg,
339                                             size_t readerBufferSizeHint,
340                                             uint64_t initialFrames) {
341         (void)readerBufferSizeHint;
342         return std::make_unique<NullSink>(cfg, initialFrames);
343     }
344 
345 private:
346     const nsecs_t mStartNs;
347     const unsigned mSampleRateHz;
348     const unsigned mFrameSize;
349     const uint64_t mInitialFrames;
350     uint64_t mFrames GUARDED_BY(mFrameCountersMutex);
351     uint64_t mMissedFrames GUARDED_BY(mFrameCountersMutex) = 0;
352     uint64_t mReceivedFrames GUARDED_BY(mFrameCountersMutex) = 0;
353     char mWriteBuffer[1024];
354     mutable Mutex mFrameCountersMutex;
355 };
356 
357 }  // namespace
358 
359 std::unique_ptr<DevicePortSink>
create(size_t readerBufferSizeHint,const DeviceAddress & address,const AudioConfig & cfg,const hidl_vec<AudioInOutFlag> & flags,uint64_t initialFrames)360 DevicePortSink::create(size_t readerBufferSizeHint,
361                        const DeviceAddress &address,
362                        const AudioConfig &cfg,
363                        const hidl_vec<AudioInOutFlag> &flags,
364                        uint64_t initialFrames) {
365     (void)flags;
366 
367     if (xsd::stringToAudioFormat(cfg.base.format) != xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT) {
368         ALOGE("%s:%d, unexpected format: '%s'", __func__, __LINE__, cfg.base.format.c_str());
369         return FAILURE(nullptr);
370     }
371 
372     if (GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false)) {
373         goto nullsink;
374     }
375 
376     switch (xsd::stringToAudioDevice(address.deviceType)) {
377     case xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
378     case xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
379         {
380             auto sinkptr = TinyalsaSink::create(talsa::kPcmCard, talsa::kPcmDevice,
381                                                 cfg, readerBufferSizeHint, initialFrames);
382             if (sinkptr != nullptr) {
383                 return sinkptr;
384             } else {
385                 ALOGW("%s:%d failed to create alsa sink for '%s'; creating NullSink instead.",
386                       __func__, __LINE__, address.deviceType.c_str());
387             }
388         }
389         break;
390 
391     case xsd::AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
392     case xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS:
393         ALOGW("%s:%d creating NullSink for '%s'.", __func__, __LINE__, address.deviceType.c_str());
394         break;
395 
396     default:
397         ALOGW("%s:%d unsupported device: '%s', creating NullSink", __func__, __LINE__, address.deviceType.c_str());
398         break;
399     }
400 
401 nullsink:
402     return NullSink::create(cfg, readerBufferSizeHint, initialFrames);
403 }
404 
getLatencyMs(const DeviceAddress & address,const AudioConfig & cfg)405 int DevicePortSink::getLatencyMs(const DeviceAddress &address, const AudioConfig &cfg) {
406     switch (xsd::stringToAudioDevice(address.deviceType)) {
407     default:
408         ALOGW("%s:%d unsupported device: '%s'", __func__, __LINE__, address.deviceType.c_str());
409         return FAILURE(-1);
410 
411     case xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
412     case xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
413         return TinyalsaSink::getLatencyMs(cfg);
414 
415     case xsd::AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
416     case xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS:
417         return NullSink::getLatencyMs(cfg);
418     }
419 }
420 
validateDeviceAddress(const DeviceAddress & address)421 bool DevicePortSink::validateDeviceAddress(const DeviceAddress& address) {
422     switch (xsd::stringToAudioDevice(address.deviceType)) {
423     default:
424         ALOGW("%s:%d unsupported device: '%s'", __func__, __LINE__, address.deviceType.c_str());
425         return FAILURE(false);
426 
427     case xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
428     case xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
429     case xsd::AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
430     case xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS:
431         break;
432     }
433 
434     return true;
435 }
436 
437 }  // namespace implementation
438 }  // namespace CPP_VERSION
439 }  // namespace audio
440 }  // namespace hardware
441 }  // namespace android
442