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