• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anon36323d6f0111::TinyalsaSink49     TinyalsaSink(unsigned pcmCard, unsigned pcmDevice,
50                  const AudioConfig &cfg,
51                  uint64_t &frames)
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(frames)
57             , mFrames(frames)
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::__anon36323d6f0111::TinyalsaSink72     ~TinyalsaSink() {
73         mConsumeThreadRunning = false;
74         mConsumeThread.join();
75     }
76 
getLatencyMsandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::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::__anon36323d6f0111::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::__anon36323d6f0111::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::__anon36323d6f0111::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::__anon36323d6f0111::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::__anon36323d6f0111::TinyalsaSink129     size_t write(float volume, size_t bytesToWrite, IReader &reader) {
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_write 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::__anon36323d6f0111::TinyalsaSink193     void consumeThread() {
194         util::setThreadPriority(PRIORITY_URGENT_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                 talsa::pcmWrite(mPcm.get(), writeBuffer.data(), szBytes);
213             }
214         }
215     }
216 
createandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::TinyalsaSink217     static std::unique_ptr<TinyalsaSink> create(unsigned pcmCard,
218                                                 unsigned pcmDevice,
219                                                 const AudioConfig &cfg,
220                                                 size_t readerBufferSizeHint,
221                                                 uint64_t &frames) {
222         (void)readerBufferSizeHint;
223         auto sink = std::make_unique<TinyalsaSink>(pcmCard, pcmDevice,
224                                                    cfg, frames);
225         if (sink->mMixer && sink->mPcm) {
226             return sink;
227         } else {
228             return FAILURE(nullptr);
229         }
230     }
231 
232 private:
233     const nsecs_t mStartNs;
234     const unsigned mSampleRateHz;
235     const unsigned mFrameSize;
236     const unsigned mWriteSizeFrames;
237     const uint64_t mInitialFrames;
238     uint64_t &mFrames GUARDED_BY(mFrameCountersMutex);
239     uint64_t mMissedFrames GUARDED_BY(mFrameCountersMutex) = 0;
240     uint64_t mReceivedFrames GUARDED_BY(mFrameCountersMutex) = 0;
241     RingBuffer mRingBuffer;
242     talsa::Mixer mMixer;
243     talsa::PcmPtr mPcm;
244     std::thread mConsumeThread;
245     std::atomic<bool> mConsumeThreadRunning = true;
246     mutable Mutex mFrameCountersMutex;
247 };
248 
249 struct NullSink : public DevicePortSink {
NullSinkandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink250     NullSink(const AudioConfig &cfg, uint64_t &frames)
251             : mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
252             , mSampleRateHz(cfg.base.sampleRateHz)
253             , mFrameSize(util::countChannels(cfg.base.channelMask) * sizeof(int16_t))
254             , mInitialFrames(frames)
255             , mFrames(frames) {}
256 
getLatencyMsandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink257     static int getLatencyMs(const AudioConfig &) {
258         return 1;
259     }
260 
getPresentationPositionandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink261     Result getPresentationPosition(uint64_t &frames, TimeSpec &ts) override {
262         const AutoMutex lock(mFrameCountersMutex);
263 
264         nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
265         const uint64_t nowFrames = getPresentationFramesLocked(nowNs);
266         auto presentedFrames = nowFrames - mMissedFrames;
267         if (presentedFrames > mReceivedFrames) {
268           // There is another underrun that is not yet accounted for in mMissedFrames
269           auto delta = presentedFrames - mReceivedFrames;
270           presentedFrames -= delta;
271           // The last frame was presented some time ago, reflect that in the result
272           nowNs -= delta * 1000000000 / mSampleRateHz;
273         }
274         mFrames = presentedFrames + mInitialFrames;
275 
276         frames = mFrames;
277         ts = util::nsecs2TimeSpec(nowNs);
278         return Result::OK;
279     }
280 
getPresentationFramesLockedandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink281     uint64_t getPresentationFramesLocked(const nsecs_t nowNs) const {
282         return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
283     }
284 
calcAvailableFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink285     size_t calcAvailableFramesNowLocked() {
286         const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
287         auto presentationFrames = getPresentationFramesLocked(nowNs);
288         if (mReceivedFrames + mMissedFrames < presentationFrames) {
289             // There has been an underrun
290             mMissedFrames = presentationFrames - mReceivedFrames;
291         }
292         size_t pendingFrames = mReceivedFrames + mMissedFrames - presentationFrames;
293         return sizeof(mWriteBuffer) / mFrameSize - pendingFrames;
294     }
295 
calcWaitFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink296     size_t calcWaitFramesNowLocked(const size_t requestedFrames) {
297         const size_t availableFrames = calcAvailableFramesNowLocked();
298         return (requestedFrames > availableFrames)
299             ? (requestedFrames - availableFrames) : 0;
300     }
301 
writeandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink302     size_t write(float volume, size_t bytesToWrite, IReader &reader) override {
303         (void)volume;
304         const AutoMutex lock(mFrameCountersMutex);
305 
306         const size_t waitFrames = calcWaitFramesNowLocked(bytesToWrite / mFrameSize);
307         const auto blockUntil =
308             std::chrono::high_resolution_clock::now() +
309                 + std::chrono::microseconds(waitFrames * 1000000 / mSampleRateHz);
310         std::this_thread::sleep_until(blockUntil);
311 
312         while (bytesToWrite > 0) {
313             size_t chunkSize =
314                 std::min(bytesToWrite, sizeof(mWriteBuffer)) / mFrameSize * mFrameSize;
315             chunkSize = reader(mWriteBuffer, chunkSize);
316             if (chunkSize > 0) {
317                 mReceivedFrames += chunkSize / mFrameSize;
318                 bytesToWrite -= chunkSize;
319             } else {
320                 break; // reader failed
321             }
322         }
323 
324         return 0;
325     }
326 
createandroid::hardware::audio::CPP_VERSION::implementation::__anon36323d6f0111::NullSink327     static std::unique_ptr<NullSink> create(const AudioConfig &cfg,
328                                             size_t readerBufferSizeHint,
329                                             uint64_t &frames) {
330         (void)readerBufferSizeHint;
331         return std::make_unique<NullSink>(cfg, frames);
332     }
333 
334 private:
335     const nsecs_t mStartNs;
336     const unsigned mSampleRateHz;
337     const unsigned mFrameSize;
338     const uint64_t mInitialFrames;
339     uint64_t &mFrames GUARDED_BY(mFrameCountersMutex);
340     uint64_t mMissedFrames GUARDED_BY(mFrameCountersMutex) = 0;
341     uint64_t mReceivedFrames GUARDED_BY(mFrameCountersMutex) = 0;
342     char mWriteBuffer[1024];
343     mutable Mutex mFrameCountersMutex;
344 };
345 
346 }  // namespace
347 
348 std::unique_ptr<DevicePortSink>
create(size_t readerBufferSizeHint,const DeviceAddress & address,const AudioConfig & cfg,const hidl_vec<AudioInOutFlag> & flags,uint64_t & frames)349 DevicePortSink::create(size_t readerBufferSizeHint,
350                        const DeviceAddress &address,
351                        const AudioConfig &cfg,
352                        const hidl_vec<AudioInOutFlag> &flags,
353                        uint64_t &frames) {
354     (void)flags;
355 
356     if (xsd::stringToAudioFormat(cfg.base.format) != xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT) {
357         ALOGE("%s:%d, unexpected format: '%s'", __func__, __LINE__, cfg.base.format.c_str());
358         return FAILURE(nullptr);
359     }
360 
361     if (GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false)) {
362         goto nullsink;
363     }
364 
365     switch (xsd::stringToAudioDevice(address.deviceType)) {
366     case xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
367     case xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
368         {
369             auto sinkptr = TinyalsaSink::create(talsa::kPcmCard, talsa::kPcmDevice,
370                                                 cfg, readerBufferSizeHint, frames);
371             if (sinkptr != nullptr) {
372                 return sinkptr;
373             } else {
374                 ALOGW("%s:%d failed to create alsa sink for '%s'; creating NullSink instead.",
375                       __func__, __LINE__, address.deviceType.c_str());
376             }
377         }
378         break;
379 
380     case xsd::AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
381     case xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS:
382         ALOGW("%s:%d creating NullSink for '%s'.", __func__, __LINE__, address.deviceType.c_str());
383         break;
384 
385     default:
386         ALOGW("%s:%d unsupported device: '%s', creating NullSink", __func__, __LINE__, address.deviceType.c_str());
387         break;
388     }
389 
390 nullsink:
391     return NullSink::create(cfg, readerBufferSizeHint, frames);
392 }
393 
getLatencyMs(const DeviceAddress & address,const AudioConfig & cfg)394 int DevicePortSink::getLatencyMs(const DeviceAddress &address, const AudioConfig &cfg) {
395     switch (xsd::stringToAudioDevice(address.deviceType)) {
396     default:
397         ALOGW("%s:%d unsupported device: '%s'", __func__, __LINE__, address.deviceType.c_str());
398         return FAILURE(-1);
399 
400     case xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
401     case xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
402         return TinyalsaSink::getLatencyMs(cfg);
403 
404     case xsd::AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
405     case xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS:
406         return NullSink::getLatencyMs(cfg);
407     }
408 }
409 
validateDeviceAddress(const DeviceAddress & address)410 bool DevicePortSink::validateDeviceAddress(const DeviceAddress& address) {
411     switch (xsd::stringToAudioDevice(address.deviceType)) {
412     default:
413         ALOGW("%s:%d unsupported device: '%s'", __func__, __LINE__, address.deviceType.c_str());
414         return FAILURE(false);
415 
416     case xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
417     case xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
418     case xsd::AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
419     case xsd::AudioDevice::AUDIO_DEVICE_OUT_BUS:
420         break;
421     }
422 
423     return true;
424 }
425 
426 }  // namespace implementation
427 }  // namespace CPP_VERSION
428 }  // namespace audio
429 }  // namespace hardware
430 }  // namespace android
431