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