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