• 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 <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