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 <log/log.h>
18 #include <fmq/EventFlag.h>
19 #include <fmq/MessageQueue.h>
20 #include <hidl/MQDescriptor.h>
21 #include <hidl/Status.h>
22 #include <math.h>
23 #include "stream_out.h"
24 #include "device_port_sink.h"
25 #include "deleters.h"
26 #include "util.h"
27 #include "debug.h"
28 #include <sys/resource.h>
29 #include <pthread.h>
30 #include <cutils/sched_policy.h>
31 #include <utils/ThreadDefs.h>
32 #include <future>
33 #include <thread>
34
35 namespace android {
36 namespace hardware {
37 namespace audio {
38 namespace V6_0 {
39 namespace implementation {
40
41 using ::android::hardware::Void;
42 using namespace ::android::hardware::audio::common::V6_0;
43 using namespace ::android::hardware::audio::V6_0;
44
45 namespace {
46
47 struct WriteThread : public IOThread {
48 typedef MessageQueue<IStreamOut::WriteCommand, kSynchronizedReadWrite> CommandMQ;
49 typedef MessageQueue<IStreamOut::WriteStatus, kSynchronizedReadWrite> StatusMQ;
50 typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
51
WriteThreadandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread52 WriteThread(StreamOut *stream, const size_t mqBufferSize)
53 : mStream(stream)
54 , mCommandMQ(1)
55 , mStatusMQ(1)
56 , mDataMQ(mqBufferSize, true /* EventFlag */) {
57 if (!mCommandMQ.isValid()) {
58 ALOGE("WriteThread::%s:%d: mCommandMQ is invalid", __func__, __LINE__);
59 return;
60 }
61 if (!mDataMQ.isValid()) {
62 ALOGE("WriteThread::%s:%d: mDataMQ is invalid", __func__, __LINE__);
63 return;
64 }
65 if (!mStatusMQ.isValid()) {
66 ALOGE("WriteThread::%s:%d: mStatusMQ is invalid", __func__, __LINE__);
67 return;
68 }
69
70 status_t status;
71
72 EventFlag* rawEfGroup = nullptr;
73 status = EventFlag::createEventFlag(mDataMQ.getEventFlagWord(), &rawEfGroup);
74 if (status != OK || !rawEfGroup) {
75 ALOGE("WriteThread::%s:%d: rawEfGroup is invalid", __func__, __LINE__);
76 return;
77 } else {
78 mEfGroup.reset(rawEfGroup);
79 }
80
81 mThread = std::thread(&WriteThread::threadLoop, this);
82 }
83
~WriteThreadandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread84 ~WriteThread() {
85 if (mThread.joinable()) {
86 requestExit();
87 mThread.join();
88 }
89 }
90
getEventFlagandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread91 EventFlag *getEventFlag() override {
92 return mEfGroup.get();
93 }
94
isRunningandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread95 bool isRunning() const {
96 return mThread.joinable();
97 }
98
getTidandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread99 std::future<pthread_t> getTid() {
100 return mTid.get_future();
101 }
102
threadLoopandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread103 void threadLoop() {
104 setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_AUDIO);
105 set_sched_policy(0, SP_FOREGROUND);
106 mTid.set_value(pthread_self());
107
108 while (true) {
109 uint32_t efState = 0;
110 mEfGroup->wait(MessageQueueFlagBits::NOT_EMPTY | STAND_BY_REQUEST | EXIT_REQUEST,
111 &efState);
112 if (efState & EXIT_REQUEST) {
113 return;
114 }
115
116 if (efState & STAND_BY_REQUEST) {
117 mSink.reset();
118 }
119
120 if (efState & (MessageQueueFlagBits::NOT_EMPTY | 0)) {
121 if (!mSink) {
122 mBuffer.reset(new uint8_t[mDataMQ.getQuantumCount()]);
123 LOG_ALWAYS_FATAL_IF(!mBuffer);
124
125 mSink = DevicePortSink::create(mStream->getDeviceAddress(),
126 mStream->getAudioConfig(),
127 mStream->getAudioOutputFlags(),
128 mStream->getFrameCounter());
129 LOG_ALWAYS_FATAL_IF(!mSink);
130 }
131
132 processCommand();
133 }
134 }
135 }
136
processCommandandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread137 void processCommand() {
138 IStreamOut::WriteCommand wCommand;
139
140 if (!mCommandMQ.read(&wCommand)) {
141 return; // Nothing to do.
142 }
143
144 IStreamOut::WriteStatus wStatus;
145 switch (wCommand) {
146 case IStreamOut::WriteCommand::WRITE:
147 wStatus = doWrite();
148 break;
149
150 case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION:
151 wStatus = doGetPresentationPosition();
152 break;
153
154 case IStreamOut::WriteCommand::GET_LATENCY:
155 wStatus = doGetLatency();
156 break;
157
158 default:
159 ALOGE("WriteThread::%s:%d: Unknown write thread command code %d",
160 __func__, __LINE__, wCommand);
161 wStatus.retval = FAILURE(Result::NOT_SUPPORTED);
162 break;
163 }
164
165 wStatus.replyTo = wCommand;
166
167 if (!mStatusMQ.write(&wStatus)) {
168 ALOGE("status message queue write failed");
169 }
170
171 mEfGroup->wake(MessageQueueFlagBits::NOT_FULL | 0);
172 }
173
doWriteandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread174 IStreamOut::WriteStatus doWrite() {
175 IStreamOut::WriteStatus status;
176
177 const size_t availToRead = mDataMQ.availableToRead();
178 size_t written = 0;
179 if (mDataMQ.read(&mBuffer[0], availToRead)) {
180 applyVolume(&mBuffer[0], availToRead, mStream->getVolumeNumerator());
181 status.retval = doWriteImpl(&mBuffer[0], availToRead, written);
182 status.reply.written = written;
183 } else {
184 ALOGE("WriteThread::%s:%d: mDataMQ.read failed", __func__, __LINE__);
185 status.retval = Result::OK;
186 }
187
188 return status;
189 }
190
applyVolumeandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread191 static void applyVolume(void *buf, const size_t szBytes, const int32_t numerator) {
192 constexpr int32_t kDenominator = StreamOut::kVolumeDenominator;
193
194 if (numerator == kDenominator) {
195 return;
196 }
197
198 int16_t *samples = static_cast<int16_t *>(buf);
199 std::for_each(samples,
200 samples + szBytes / sizeof(*samples),
201 [numerator](int16_t &x) {
202 x = (x * numerator + kDenominator / 2) / kDenominator;
203 });
204 }
205
doGetPresentationPositionandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread206 IStreamOut::WriteStatus doGetPresentationPosition() {
207 IStreamOut::WriteStatus status;
208
209 status.retval = mSink->getPresentationPosition(
210 status.reply.presentationPosition.frames,
211 status.reply.presentationPosition.timeStamp);
212
213 return status;
214 }
215
doGetLatencyandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread216 IStreamOut::WriteStatus doGetLatency() {
217 IStreamOut::WriteStatus status;
218
219 status.retval = Result::OK;
220 status.reply.latencyMs = mStream->getLatency();
221
222 return status;
223 }
224
doWriteImplandroid::hardware::audio::V6_0::implementation::__anon5ad945690111::WriteThread225 Result doWriteImpl(const uint8_t *const data,
226 const size_t toWrite,
227 size_t &written) {
228 const int res = mSink->write(data, toWrite);
229 if (res < 0) {
230 ALOGE("WriteThread::%s:%d: DevicePortSink::write failed with %s",
231 __func__, __LINE__, strerror(-res));
232 written = toWrite;
233 } else {
234 written = res;
235 }
236
237 return Result::OK;
238 }
239
240 StreamOut *const mStream;
241 CommandMQ mCommandMQ;
242 StatusMQ mStatusMQ;
243 DataMQ mDataMQ;
244 std::unique_ptr<EventFlag, deleters::forEventFlag> mEfGroup;
245 std::unique_ptr<uint8_t[]> mBuffer;
246 std::unique_ptr<DevicePortSink> mSink;
247 std::thread mThread;
248 std::promise<pthread_t> mTid;
249 };
250
251 } // namespace
252
StreamOut(sp<IDevice> dev,void (* unrefDevice)(IDevice *),int32_t ioHandle,const DeviceAddress & device,const AudioConfig & config,hidl_bitfield<AudioOutputFlag> flags,const SourceMetadata & sourceMetadata)253 StreamOut::StreamOut(sp<IDevice> dev,
254 void (*unrefDevice)(IDevice*),
255 int32_t ioHandle,
256 const DeviceAddress& device,
257 const AudioConfig& config,
258 hidl_bitfield<AudioOutputFlag> flags,
259 const SourceMetadata& sourceMetadata)
260 : mDev(std::move(dev))
261 , mUnrefDevice(unrefDevice)
262 , mCommon(ioHandle, device, config, flags)
263 , mSourceMetadata(sourceMetadata) {}
264
~StreamOut()265 StreamOut::~StreamOut() {
266 closeImpl(true);
267 }
268
getFrameSize()269 Return<uint64_t> StreamOut::getFrameSize() {
270 return mCommon.getFrameSize();
271 }
272
getFrameCount()273 Return<uint64_t> StreamOut::getFrameCount() {
274 return mCommon.getFrameCount();
275 }
276
getBufferSize()277 Return<uint64_t> StreamOut::getBufferSize() {
278 return mCommon.getBufferSize();
279 }
280
getSampleRate()281 Return<uint32_t> StreamOut::getSampleRate() {
282 return mCommon.getSampleRate();
283 }
284
getSupportedSampleRates(AudioFormat format,getSupportedSampleRates_cb _hidl_cb)285 Return<void> StreamOut::getSupportedSampleRates(AudioFormat format,
286 getSupportedSampleRates_cb _hidl_cb) {
287 mCommon.getSupportedSampleRates(format, _hidl_cb);
288 return Void();
289 }
290
setSampleRate(uint32_t sampleRateHz)291 Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
292 return mCommon.setSampleRate(sampleRateHz);
293 }
294
getChannelMask()295 Return<hidl_bitfield<AudioChannelMask>> StreamOut::getChannelMask() {
296 return mCommon.getChannelMask();
297 }
298
getSupportedChannelMasks(AudioFormat format,IStream::getSupportedChannelMasks_cb _hidl_cb)299 Return<void> StreamOut::getSupportedChannelMasks(AudioFormat format,
300 IStream::getSupportedChannelMasks_cb _hidl_cb) {
301 mCommon.getSupportedChannelMasks(format, _hidl_cb);
302 return Void();
303 }
304
setChannelMask(hidl_bitfield<AudioChannelMask> mask)305 Return<Result> StreamOut::setChannelMask(hidl_bitfield<AudioChannelMask> mask) {
306 return mCommon.setChannelMask(mask);
307 }
308
getFormat()309 Return<AudioFormat> StreamOut::getFormat() {
310 return mCommon.getFormat();
311 }
312
getSupportedFormats(getSupportedFormats_cb _hidl_cb)313 Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
314 mCommon.getSupportedFormats(_hidl_cb);
315 return Void();
316 }
317
setFormat(AudioFormat format)318 Return<Result> StreamOut::setFormat(AudioFormat format) {
319 return mCommon.setFormat(format);
320 }
321
getAudioProperties(getAudioProperties_cb _hidl_cb)322 Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
323 mCommon.getAudioProperties(_hidl_cb);
324 return Void();
325 }
326
addEffect(uint64_t effectId)327 Return<Result> StreamOut::addEffect(uint64_t effectId) {
328 (void)effectId;
329 return FAILURE(Result::INVALID_ARGUMENTS);
330 }
331
removeEffect(uint64_t effectId)332 Return<Result> StreamOut::removeEffect(uint64_t effectId) {
333 (void)effectId;
334 return FAILURE(Result::INVALID_ARGUMENTS);
335 }
336
standby()337 Return<Result> StreamOut::standby() {
338 if (mWriteThread) {
339 LOG_ALWAYS_FATAL_IF(!mWriteThread->standby());
340 }
341
342 return Result::OK;
343 }
344
getDevices(getDevices_cb _hidl_cb)345 Return<void> StreamOut::getDevices(getDevices_cb _hidl_cb) {
346 mCommon.getDevices(_hidl_cb);
347 return Void();
348 }
349
setDevices(const hidl_vec<DeviceAddress> & devices)350 Return<Result> StreamOut::setDevices(const hidl_vec<DeviceAddress>& devices) {
351 return mCommon.setDevices(devices);
352 }
353
getParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)354 Return<void> StreamOut::getParameters(const hidl_vec<ParameterValue>& context,
355 const hidl_vec<hidl_string>& keys,
356 getParameters_cb _hidl_cb) {
357 (void)context;
358 _hidl_cb((keys.size() > 0) ? FAILURE(Result::NOT_SUPPORTED) : Result::OK, {});
359 return Void();
360 }
361
setParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<ParameterValue> & parameters)362 Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& context,
363 const hidl_vec<ParameterValue>& parameters) {
364 (void)context;
365 (void)parameters;
366 return Result::OK;
367 }
368
setHwAvSync(uint32_t hwAvSync)369 Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
370 (void)hwAvSync;
371 return FAILURE(Result::NOT_SUPPORTED);
372 }
373
closeImpl(const bool fromDctor)374 Result StreamOut::closeImpl(const bool fromDctor) {
375 if (mDev) {
376 mWriteThread.reset();
377 mUnrefDevice(mDev.get());
378 mDev = nullptr;
379 return Result::OK;
380 } else if (fromDctor) {
381 // closeImpl is always called from the dctor, it is ok if mDev is null,
382 // we don't want to log the error in this case.
383 return Result::OK;
384 } else {
385 return FAILURE(Result::INVALID_STATE);
386 }
387 }
388
close()389 Return<Result> StreamOut::close() {
390 return closeImpl(false);
391 }
392
start()393 Return<Result> StreamOut::start() {
394 return FAILURE(Result::NOT_SUPPORTED);
395 }
396
stop()397 Return<Result> StreamOut::stop() {
398 return FAILURE(Result::NOT_SUPPORTED);
399 }
400
createMmapBuffer(int32_t minSizeFrames,createMmapBuffer_cb _hidl_cb)401 Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames,
402 createMmapBuffer_cb _hidl_cb) {
403 (void)minSizeFrames;
404 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
405 return Void();
406 }
407
getMmapPosition(getMmapPosition_cb _hidl_cb)408 Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
409 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
410 return Void();
411 }
412
getLatency()413 Return<uint32_t> StreamOut::getLatency() {
414 return mCommon.getFrameCount() * 1000 / mCommon.getSampleRate();
415 }
416
setVolume(float left,float right)417 Return<Result> StreamOut::setVolume(float left, float right) {
418 if (isnan(left) || left < 0.0f || left > 1.0f
419 || right < 0.0f || right > 1.0f || isnan(right)) {
420 return FAILURE(Result::INVALID_ARGUMENTS);
421 }
422
423 mVolumeNumerator = int16_t((left + right) * kVolumeDenominator / 2);
424 return Result::OK;
425 }
426
updateSourceMetadata(const SourceMetadata & sourceMetadata)427 Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
428 (void)sourceMetadata;
429 return Void();
430 }
431
prepareForWriting(uint32_t frameSize,uint32_t framesCount,prepareForWriting_cb _hidl_cb)432 Return<void> StreamOut::prepareForWriting(uint32_t frameSize,
433 uint32_t framesCount,
434 prepareForWriting_cb _hidl_cb) {
435 if (!frameSize || !framesCount || frameSize > 256 || framesCount > (1u << 20)) {
436 _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {});
437 return Void();
438 }
439
440 if (mWriteThread) { // INVALID_STATE if the method was already called.
441 _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {}, {}, {});
442 return Void();
443 }
444
445 auto t = std::make_unique<WriteThread>(this, frameSize * framesCount);
446
447 if (t->isRunning()) {
448 _hidl_cb(Result::OK,
449 *(t->mCommandMQ.getDesc()),
450 *(t->mDataMQ.getDesc()),
451 *(t->mStatusMQ.getDesc()),
452 {.pid = getpid(), .tid = t->getTid().get()});
453
454 mWriteThread = std::move(t);
455 } else {
456 _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, {});
457 }
458
459 return Void();
460 }
461
getRenderPosition(getRenderPosition_cb _hidl_cb)462 Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
463 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
464 return Void();
465 }
466
getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb)467 Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
468 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
469 return Void();
470 }
471
setCallback(const sp<IStreamOutCallback> & callback)472 Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
473 (void)callback;
474 return FAILURE(Result::NOT_SUPPORTED);
475 }
476
clearCallback()477 Return<Result> StreamOut::clearCallback() {
478 return FAILURE(Result::NOT_SUPPORTED);
479 }
480
setEventCallback(const sp<IStreamOutEventCallback> & callback)481 Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& callback) {
482 (void)callback;
483 return FAILURE(Result::NOT_SUPPORTED);
484 }
485
supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb)486 Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
487 _hidl_cb(false, false);
488 return Void();
489 }
490
pause()491 Return<Result> StreamOut::pause() {
492 return FAILURE(Result::NOT_SUPPORTED);
493 }
494
resume()495 Return<Result> StreamOut::resume() {
496 return FAILURE(Result::NOT_SUPPORTED);
497 }
498
supportsDrain()499 Return<bool> StreamOut::supportsDrain() {
500 return false;
501 }
502
drain(AudioDrain type)503 Return<Result> StreamOut::drain(AudioDrain type) {
504 (void)type;
505 return FAILURE(Result::NOT_SUPPORTED);
506 }
507
flush()508 Return<Result> StreamOut::flush() {
509 return FAILURE(Result::NOT_SUPPORTED);
510 }
511
getPresentationPosition(getPresentationPosition_cb _hidl_cb)512 Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
513 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {}, {}); // see WriteThread::doGetPresentationPosition
514 return Void();
515 }
516
selectPresentation(int32_t presentationId,int32_t programId)517 Return<Result> StreamOut::selectPresentation(int32_t presentationId,
518 int32_t programId) {
519 (void)presentationId;
520 (void)programId;
521 return FAILURE(Result::NOT_SUPPORTED);
522 }
523
getDualMonoMode(getDualMonoMode_cb _hidl_cb)524 Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
525 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
526 return Void();
527 }
528
setDualMonoMode(DualMonoMode mode)529 Return<Result> StreamOut::setDualMonoMode(DualMonoMode mode) {
530 (void)mode;
531 return FAILURE(Result::NOT_SUPPORTED);
532 }
533
getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb)534 Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) {
535 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
536 return Void();
537 }
538
setAudioDescriptionMixLevel(float leveldB)539 Return<Result> StreamOut::setAudioDescriptionMixLevel(float leveldB) {
540 (void)leveldB;
541 return FAILURE(Result::NOT_SUPPORTED);
542 }
543
getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb)544 Return<void> StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) {
545 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
546 return Void();
547 }
548
setPlaybackRateParameters(const PlaybackRate & playbackRate)549 Return<Result> StreamOut::setPlaybackRateParameters(const PlaybackRate &playbackRate) {
550 (void)playbackRate;
551 return FAILURE(Result::NOT_SUPPORTED);
552 }
553
554 } // namespace implementation
555 } // namespace V6_0
556 } // namespace audio
557 } // namespace hardware
558 } // namespace android
559