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 <android-base/properties.h>
18 #include <cmath>
19 #include <chrono>
20 #include <thread>
21 #include <unistd.h>
22 #include <audio_utils/channels.h>
23 #include <audio_utils/format.h>
24 #include <log/log.h>
25 #include <utils/Mutex.h>
26 #include <utils/ThreadDefs.h>
27 #include <utils/Timers.h>
28 #include PATH(APM_XSD_ENUMS_H_FILENAME)
29 #include "device_port_source.h"
30 #include "talsa.h"
31 #include "ring_buffer.h"
32 #include "audio_ops.h"
33 #include "util.h"
34 #include "debug.h"
35
36 using ::android::base::GetBoolProperty;
37
38 namespace xsd {
39 using namespace ::android::audio::policy::configuration::CPP_VERSION;
40 }
41
42 namespace android {
43 namespace hardware {
44 namespace audio {
45 namespace CPP_VERSION {
46 namespace implementation {
47
48 namespace {
49
50 constexpr int kMaxJitterUs = 3000; // Enforced by CTS, should be <= 6ms
51
52 struct TinyalsaSource : public DevicePortSource {
TinyalsaSourceandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource53 TinyalsaSource(unsigned pcmCard, unsigned pcmDevice,
54 const AudioConfig &cfg, uint64_t &frames)
55 : mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
56 , mSampleRateHz(cfg.base.sampleRateHz)
57 , mFrameSize(util::countChannels(cfg.base.channelMask) * sizeof(int16_t))
58 , mReadSizeFrames(cfg.frameCount)
59 , mFrames(frames)
60 , mRingBuffer(mFrameSize * cfg.frameCount * 3)
61 , mMixer(pcmCard)
62 , mPcm(talsa::pcmOpen(pcmCard, pcmDevice,
63 util::countChannels(cfg.base.channelMask),
64 cfg.base.sampleRateHz,
65 cfg.frameCount,
66 false /* isOut */)) {
67 if (mPcm) {
68 mProduceThread = std::thread(&TinyalsaSource::producerThread, this);
69 } else {
70 mProduceThread = std::thread([](){});
71 }
72 }
73
~TinyalsaSourceandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource74 ~TinyalsaSource() {
75 mProduceThreadRunning = false;
76 ALOGD("%s: joining producerThread", __func__);
77 mProduceThread.join();
78 if (mPcm) {
79 ALOGD("%s: stopping PCM stream", __func__);
80 LOG_ALWAYS_FATAL_IF(pcm_stop(mPcm.get()) != 0);
81 }
82 }
83
getCapturePositionandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource84 Result getCapturePosition(uint64_t &frames, uint64_t &time) override {
85 const AutoMutex lock(mFrameCountersMutex);
86
87 const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
88 const uint64_t nowFrames = getCaptureFramesLocked(nowNs);
89 mFrames += (nowFrames - mPreviousFrames);
90 mPreviousFrames = nowFrames;
91
92 frames = mFrames;
93 time = nowNs;
94 return Result::OK;
95 }
96
getCaptureFramesLockedandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource97 uint64_t getCaptureFramesLocked(const nsecs_t nowNs) const {
98 return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
99 }
100
getAvailableFramesLockedandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource101 uint64_t getAvailableFramesLocked(const nsecs_t nowNs) const {
102 return getCaptureFramesLocked(nowNs) - mSentFrames;
103 }
104
getAvailableFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource105 uint64_t getAvailableFramesNowLocked() const {
106 return getAvailableFramesLocked(systemTime(SYSTEM_TIME_MONOTONIC));
107 }
108
getWaitFramesNowLockedandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource109 size_t getWaitFramesNowLocked(const size_t requestedFrames) const {
110 const size_t availableFrames = getAvailableFramesNowLocked();
111 return (requestedFrames > availableFrames)
112 ? (requestedFrames - availableFrames) : 0;
113 }
114
readandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource115 size_t read(float volume, size_t bytesToRead, IWriter &writer) override {
116 const AutoMutex lock(mFrameCountersMutex);
117
118 const size_t waitFrames = getWaitFramesNowLocked(bytesToRead / mFrameSize);
119 const auto blockUntil =
120 std::chrono::high_resolution_clock::now() +
121 + std::chrono::microseconds(waitFrames * 1000000 / mSampleRateHz);
122
123 while (bytesToRead > 0) {
124 if (mRingBuffer.waitForConsumeAvailable(blockUntil
125 + std::chrono::microseconds(kMaxJitterUs))) {
126 if (mRingBuffer.availableToConsume() >= bytesToRead) {
127 // Since the ring buffer has all bytes we need, make sure we
128 // are not too early here: tinyalsa is jittery, we don't
129 // want to go faster than SYSTEM_TIME_MONOTONIC
130 std::this_thread::sleep_until(blockUntil);
131 }
132
133 auto chunk = mRingBuffer.getConsumeChunk();
134 const size_t writeBufSzBytes = std::min(chunk.size, bytesToRead);
135
136 aops::multiplyByVolume(volume,
137 static_cast<int16_t *>(chunk.data),
138 writeBufSzBytes / sizeof(int16_t));
139
140 writer(chunk.data, writeBufSzBytes);
141 LOG_ALWAYS_FATAL_IF(mRingBuffer.consume(chunk, writeBufSzBytes) < writeBufSzBytes);
142
143 bytesToRead -= writeBufSzBytes;
144 mSentFrames += writeBufSzBytes / mFrameSize;
145 } else {
146 ALOGD("TinyalsaSource::%s:%d pcm_readi was late delivering "
147 "frames, inserting %zu us of silence",
148 __func__, __LINE__,
149 size_t(1000000 * bytesToRead / mFrameSize / mSampleRateHz));
150
151 static const uint8_t zeroes[256] = {0};
152
153 while (bytesToRead > 0) {
154 const size_t nZeroFrames =
155 std::min(bytesToRead, sizeof(zeroes)) / mFrameSize;
156 const size_t nZeroBytes = nZeroFrames * mFrameSize;
157
158 writer(zeroes, nZeroBytes);
159 bytesToRead -= nZeroBytes;
160 mSentFrames += nZeroFrames;
161 }
162 break;
163 }
164 }
165
166 return mFramesLost.exchange(0);
167 }
168
producerThreadandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource169 void producerThread() {
170 util::setThreadPriority(SP_AUDIO_SYS, PRIORITY_AUDIO);
171 std::vector<uint8_t> readBuf(mReadSizeFrames * mFrameSize);
172
173 while (mProduceThreadRunning) {
174 const size_t bytesLost = mRingBuffer.makeRoomForProduce(readBuf.size());
175 mFramesLost += bytesLost / mFrameSize;
176
177 auto produceChunk = mRingBuffer.getProduceChunk();
178 if (produceChunk.size < readBuf.size()) {
179 const size_t sz = doRead(readBuf.data(), readBuf.size());
180 if (sz > 0) {
181 LOG_ALWAYS_FATAL_IF(mRingBuffer.produce(readBuf.data(), sz) < sz);
182 }
183 } else {
184 const size_t sz = doRead(produceChunk.data, readBuf.size());
185 if (sz > 0) {
186 LOG_ALWAYS_FATAL_IF(mRingBuffer.produce(readBuf.size()) < sz);
187 }
188 }
189 }
190 ALOGD("%s: exiting", __func__);
191 }
192
doReadandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource193 size_t doRead(void *dst, size_t sz) {
194 const int n = talsa::pcmRead(mPcm.get(), dst, sz, mFrameSize);
195 if (n > 0) {
196 LOG_ALWAYS_FATAL_IF(static_cast<size_t>(n) > sz,
197 "n=%d sz=%zu mFrameSize=%u", n, sz, mFrameSize);
198 return n;
199 } else {
200 return 0;
201 }
202 }
203
createandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::TinyalsaSource204 static std::unique_ptr<TinyalsaSource> create(unsigned pcmCard,
205 unsigned pcmDevice,
206 const AudioConfig &cfg,
207 size_t writerBufferSizeHint,
208 uint64_t &frames) {
209 (void)writerBufferSizeHint;
210
211 auto src = std::make_unique<TinyalsaSource>(pcmCard, pcmDevice,
212 cfg, frames);
213 if (src->mMixer && src->mPcm) {
214 return src;
215 } else {
216 return FAILURE(nullptr);
217 }
218 }
219
220 private:
221 const nsecs_t mStartNs;
222 const unsigned mSampleRateHz;
223 const unsigned mFrameSize;
224 const unsigned mReadSizeFrames;
225 uint64_t &mFrames GUARDED_BY(mFrameCountersMutex);
226 uint64_t mPreviousFrames GUARDED_BY(mFrameCountersMutex) = 0;
227 uint64_t mSentFrames GUARDED_BY(mFrameCountersMutex) = 0;
228 std::atomic<uint32_t> mFramesLost = 0;
229 RingBuffer mRingBuffer;
230 talsa::Mixer mMixer;
231 talsa::PcmPtr mPcm;
232 std::thread mProduceThread;
233 std::atomic<bool> mProduceThreadRunning = true;
234 mutable Mutex mFrameCountersMutex;
235 };
236
237 template <class G> struct GeneratedSource : public DevicePortSource {
GeneratedSourceandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::GeneratedSource238 GeneratedSource(const AudioConfig &cfg,
239 size_t writerBufferSizeHint,
240 uint64_t &frames,
241 G generator)
242 : mWriteBuffer(writerBufferSizeHint / sizeof(int16_t))
243 , mFrames(frames)
244 , mStartNs(systemTime(SYSTEM_TIME_MONOTONIC))
245 , mSampleRateHz(cfg.base.sampleRateHz)
246 , mNChannels(util::countChannels(cfg.base.channelMask))
247 , mGenerator(std::move(generator)) {}
248
getCapturePositionandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::GeneratedSource249 Result getCapturePosition(uint64_t &frames, uint64_t &time) override {
250 const AutoMutex lock(mFrameCountersMutex);
251
252 const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
253 const uint64_t nowFrames = getCaptureFramesLocked(nowNs);
254 mFrames += (nowFrames - mPreviousFrames);
255 mPreviousFrames = nowFrames;
256 frames = mFrames;
257 time = nowNs;
258 return Result::OK;
259 }
260
getCaptureFramesLockedandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::GeneratedSource261 uint64_t getCaptureFramesLocked(const nsecs_t nowNs) const {
262 return uint64_t(mSampleRateHz) * ns2us(nowNs - mStartNs) / 1000000;
263 }
264
getAvailableFramesLockedandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::GeneratedSource265 uint64_t getAvailableFramesLocked(const nsecs_t nowNs) const {
266 return getCaptureFramesLocked(nowNs) - mSentFrames;
267 }
268
readandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::GeneratedSource269 size_t read(float volume, size_t bytesToRead, IWriter &writer) override {
270 const AutoMutex lock(mFrameCountersMutex);
271 mWriteBuffer.resize(bytesToRead / sizeof(int16_t));
272
273 int16_t *samples = mWriteBuffer.data();
274 const unsigned nChannels = mNChannels;
275 const unsigned requestedFrames = bytesToRead / nChannels / sizeof(*samples);
276
277 unsigned availableFrames;
278 while (true) {
279 const nsecs_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
280 availableFrames = getAvailableFramesLocked(nowNs);
281 if (availableFrames < requestedFrames / 2) {
282 const unsigned neededMoreFrames = requestedFrames / 2 - availableFrames;
283
284 using namespace std::chrono_literals;
285 std::this_thread::sleep_for(1s * neededMoreFrames / mSampleRateHz);
286 } else {
287 break;
288 }
289 }
290
291 const unsigned nFrames = std::min(requestedFrames, availableFrames);
292 mGenerator(samples, nFrames);
293 const size_t nSamples = nFrames * nChannels;
294 if (nChannels > 1) {
295 adjust_channels(samples, 1, samples, nChannels,
296 sizeof(*samples), nFrames * sizeof(*samples));
297 }
298
299 aops::multiplyByVolume(volume,
300 mWriteBuffer.data(),
301 nSamples);
302
303 writer(mWriteBuffer.data(), nSamples * sizeof(*samples));
304 mSentFrames += nFrames;
305
306 return 0;
307 }
308
309 private:
310 std::vector<int16_t> mWriteBuffer;
311 uint64_t &mFrames GUARDED_BY(mFrameCountersMutex);
312 const nsecs_t mStartNs;
313 const unsigned mSampleRateHz;
314 const unsigned mNChannels;
315 uint64_t mPreviousFrames GUARDED_BY(mFrameCountersMutex) = 0;
316 uint64_t mSentFrames GUARDED_BY(mFrameCountersMutex) = 0;
317 G mGenerator;
318 mutable Mutex mFrameCountersMutex;
319 };
320
convertFloatsToInt16(const std::vector<float> & pcmFloat)321 std::vector<int16_t> convertFloatsToInt16(const std::vector<float> &pcmFloat) {
322 std::vector<int16_t> pcmI16(pcmFloat.size());
323
324 memcpy_by_audio_format(pcmI16.data(), AUDIO_FORMAT_PCM_16_BIT,
325 pcmFloat.data(), AUDIO_FORMAT_PCM_FLOAT,
326 pcmFloat.size());
327
328 return pcmI16;
329 }
330
331 // https://en.wikipedia.org/wiki/Busy_signal
332 struct BusySignalGenerator {
BusySignalGeneratorandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::BusySignalGenerator333 explicit BusySignalGenerator(const uint32_t sampleRateHz) : mSampleRateHz(sampleRateHz) {
334 // 24/480 = 31/620, mValues must contain 50ms of audio samples
335 const size_t sz = sampleRateHz / 20;
336 std::vector<float> pcm(sz);
337 for (unsigned i = 0; i < sz; ++i) {
338 const double a = double(i) * M_PI * 2 / sampleRateHz;
339 pcm[i] = .5 * (sin(480 * a) + sin(620 * a));
340 }
341 mValues = convertFloatsToInt16(pcm);
342 }
343
operator ()android::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::BusySignalGenerator344 void operator()(int16_t* s, size_t n) {
345 const unsigned rate = mSampleRateHz;
346 const unsigned rateHalf = rate / 2;
347 const int16_t *const vals = mValues.data();
348 const size_t valsSz = mValues.size();
349 size_t i = mI;
350
351 while (n > 0) {
352 size_t len;
353 if (i < rateHalf) {
354 const size_t valsOff = i % valsSz;
355 len = std::min(n, std::min(rateHalf - i, valsSz - valsOff));
356 memcpy(s, vals + valsOff, len * sizeof(*s));
357 } else {
358 len = std::min(n, rate - i);
359 memset(s, 0, len * sizeof(*s));
360 }
361 s += len;
362 i = (i + len) % rate;
363 n -= len;
364 }
365
366 mI = i;
367 }
368
369 private:
370 const unsigned mSampleRateHz;
371 std::vector<int16_t> mValues;
372 size_t mI = 0;
373 };
374
375 struct RepeatGenerator {
RepeatGeneratorandroid::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::RepeatGenerator376 explicit RepeatGenerator(const std::vector<float> &pcm)
377 : mValues(convertFloatsToInt16(pcm)) {}
378
operator ()android::hardware::audio::CPP_VERSION::implementation::__anond756d68c0111::RepeatGenerator379 void operator()(int16_t* s, size_t n) {
380 const int16_t *const vals = mValues.data();
381 const size_t valsSz = mValues.size();
382 size_t i = mI;
383
384 while (n > 0) {
385 const size_t len = std::min(n, valsSz - i);
386 memcpy(s, vals + i, len * sizeof(*s));
387 s += len;
388 i = (i + len) % valsSz;
389 n -= len;
390 }
391
392 mI = i;
393 }
394
395 private:
396 const std::vector<int16_t> mValues;
397 size_t mI = 0;
398 };
399
generateSinePattern(uint32_t sampleRateHz,double freq,double amp)400 std::vector<float> generateSinePattern(uint32_t sampleRateHz,
401 double freq,
402 double amp) {
403 std::vector<float> result(3 * sampleRateHz / freq + .5);
404
405 for (size_t i = 0; i < result.size(); ++i) {
406 const double a = double(i) * M_PI * 2 / sampleRateHz;
407 result[i] = amp * sin(a * freq);
408 }
409
410 return result;
411 }
412
413 template <class G> std::unique_ptr<GeneratedSource<G>>
createGeneratedSource(const AudioConfig & cfg,size_t writerBufferSizeHint,uint64_t & frames,G generator)414 createGeneratedSource(const AudioConfig &cfg,
415 size_t writerBufferSizeHint,
416 uint64_t &frames,
417 G generator) {
418 return std::make_unique<GeneratedSource<G>>(cfg,
419 writerBufferSizeHint,
420 frames,
421 std::move(generator));
422 }
423
424 } // namespace
425
426 std::unique_ptr<DevicePortSource>
create(size_t writerBufferSizeHint,const DeviceAddress & address,const AudioConfig & cfg,const hidl_vec<AudioInOutFlag> & flags,uint64_t & frames)427 DevicePortSource::create(size_t writerBufferSizeHint,
428 const DeviceAddress &address,
429 const AudioConfig &cfg,
430 const hidl_vec<AudioInOutFlag> &flags,
431 uint64_t &frames) {
432 (void)flags;
433
434 if (xsd::stringToAudioFormat(cfg.base.format) != xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT) {
435 ALOGE("%s:%d, unexpected format: '%s'", __func__, __LINE__, cfg.base.format.c_str());
436 return FAILURE(nullptr);
437 }
438
439 switch (xsd::stringToAudioDevice(address.deviceType)) {
440 case xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT:
441 case xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC:
442 if (GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false)) {
443 return createGeneratedSource(
444 cfg, writerBufferSizeHint, frames,
445 RepeatGenerator(generateSinePattern(cfg.base.sampleRateHz, 300.0, 1.0)));
446 } else {
447 auto sourceptr = TinyalsaSource::create(talsa::kPcmCard, talsa::kPcmDevice,
448 cfg, writerBufferSizeHint, frames);
449 if (sourceptr != nullptr) {
450 return sourceptr;
451 } else {
452 ALOGW("%s:%d failed to create alsa source for '%s'; creating a tone source instead.",
453 __func__, __LINE__, address.deviceType.c_str());
454 }
455 }
456 break;
457
458 case xsd::AudioDevice::AUDIO_DEVICE_IN_TELEPHONY_RX:
459 return createGeneratedSource(cfg, writerBufferSizeHint, frames,
460 BusySignalGenerator(cfg.base.sampleRateHz));
461
462 case xsd::AudioDevice::AUDIO_DEVICE_IN_FM_TUNER:
463 return createGeneratedSource(
464 cfg, writerBufferSizeHint, frames,
465 RepeatGenerator(generateSinePattern(cfg.base.sampleRateHz, 440.0, 1.0)));
466
467 default:
468 ALOGW("%s:%d unsupported device: '%s', creating a tone source",
469 __func__, __LINE__, address.deviceType.c_str());
470 break;
471 }
472
473 return createGeneratedSource(
474 cfg, writerBufferSizeHint, frames,
475 RepeatGenerator(generateSinePattern(cfg.base.sampleRateHz, 220.0, 1.0)));
476 }
477
validateDeviceAddress(const DeviceAddress & address)478 bool DevicePortSource::validateDeviceAddress(const DeviceAddress& address) {
479 switch (xsd::stringToAudioDevice(address.deviceType)) {
480 default:
481 ALOGW("%s:%d unsupported device: '%s'", __func__, __LINE__, address.deviceType.c_str());
482 return FAILURE(false);
483
484 case xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT:
485 case xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC:
486 case xsd::AudioDevice::AUDIO_DEVICE_IN_TELEPHONY_RX:
487 case xsd::AudioDevice::AUDIO_DEVICE_IN_FM_TUNER:
488 case xsd::AudioDevice::AUDIO_DEVICE_IN_BUS:
489 break;
490 }
491
492 return true;
493 }
494
495 } // namespace implementation
496 } // namespace CPP_VERSION
497 } // namespace audio
498 } // namespace hardware
499 } // namespace android
500