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 PATH(APM_XSD_ENUMS_H_FILENAME)
24 #include <future>
25 #include <thread>
26 #include "stream_out.h"
27 #include "device_port_sink.h"
28 #include "deleters.h"
29 #include "audio_ops.h"
30 #include "util.h"
31 #include "debug.h"
32
33 namespace xsd {
34 using namespace ::android::audio::policy::configuration::CPP_VERSION;
35 }
36
37 namespace android {
38 namespace hardware {
39 namespace audio {
40 namespace CPP_VERSION {
41 namespace implementation {
42
43 using ::android::hardware::Void;
44 using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
45 using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
46
47 namespace {
48
49 struct WriteThread : public IOThread {
50 typedef MessageQueue<IStreamOut::WriteCommand, kSynchronizedReadWrite> CommandMQ;
51 typedef MessageQueue<IStreamOut::WriteStatus, kSynchronizedReadWrite> StatusMQ;
52 typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
53
WriteThreadandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread54 WriteThread(StreamOut *stream, const size_t mqBufferSize)
55 : mStream(stream)
56 , mCommandMQ(1)
57 , mStatusMQ(1)
58 , mDataMQ(mqBufferSize, true /* EventFlag */) {
59 if (!mCommandMQ.isValid()) {
60 ALOGE("WriteThread::%s:%d: mCommandMQ is invalid", __func__, __LINE__);
61 return;
62 }
63 if (!mDataMQ.isValid()) {
64 ALOGE("WriteThread::%s:%d: mDataMQ is invalid", __func__, __LINE__);
65 return;
66 }
67 if (!mStatusMQ.isValid()) {
68 ALOGE("WriteThread::%s:%d: mStatusMQ is invalid", __func__, __LINE__);
69 return;
70 }
71
72 status_t status;
73
74 EventFlag* rawEfGroup = nullptr;
75 status = EventFlag::createEventFlag(mDataMQ.getEventFlagWord(), &rawEfGroup);
76 if (status != OK || !rawEfGroup) {
77 ALOGE("WriteThread::%s:%d: rawEfGroup is invalid", __func__, __LINE__);
78 return;
79 } else {
80 mEfGroup.reset(rawEfGroup);
81 }
82
83 mThread = std::thread(&WriteThread::threadLoop, this);
84 }
85
~WriteThreadandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread86 ~WriteThread() {
87 if (mThread.joinable()) {
88 requestExit();
89 mThread.join();
90 }
91 }
92
getEventFlagandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread93 EventFlag *getEventFlag() override {
94 return mEfGroup.get();
95 }
96
isRunningandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread97 bool isRunning() const {
98 return mThread.joinable();
99 }
100
getTidandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread101 std::future<pthread_t> getTid() {
102 return mTid.get_future();
103 }
104
105
threadLoopandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread106 void threadLoop() {
107 util::setThreadPriority(PRIORITY_URGENT_AUDIO);
108 mTid.set_value(pthread_self());
109
110 while (true) {
111 uint32_t efState = 0;
112 mEfGroup->wait(MessageQueueFlagBits::NOT_EMPTY | STAND_BY_REQUEST | EXIT_REQUEST,
113 &efState);
114 if (efState & EXIT_REQUEST) {
115 return;
116 }
117
118 if (efState & STAND_BY_REQUEST) {
119 mSink.reset();
120 }
121
122 if (efState & (MessageQueueFlagBits::NOT_EMPTY | 0)) {
123 if (!mSink) {
124 mSink = DevicePortSink::create(mDataMQ.getQuantumCount(),
125 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::CPP_VERSION::implementation::__anon06eeb58a0111::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::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread174 IStreamOut::WriteStatus doWrite() {
175 struct MQReader : public IReader {
176 explicit MQReader(DataMQ &mq) : dataMQ(mq) {}
177
178 size_t operator()(void *dst, size_t sz) override {
179 if (dataMQ.read(static_cast<uint8_t *>(dst), sz)) {
180 totalRead += sz;
181 return sz;
182 } else {
183 ALOGE("WriteThread::%s:%d: DataMQ::read failed",
184 __func__, __LINE__);
185 return 0;
186 }
187 }
188
189 size_t totalRead = 0;
190 DataMQ &dataMQ;
191 };
192
193 MQReader reader(mDataMQ);
194 mSink->write(mStream->getEffectiveVolume(), mDataMQ.availableToRead(), reader);
195
196 IStreamOut::WriteStatus status;
197 status.retval = Result::OK;
198 status.reply.written = reader.totalRead;
199 return status;
200 }
201
doGetPresentationPositionandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread202 IStreamOut::WriteStatus doGetPresentationPosition() {
203 IStreamOut::WriteStatus status;
204
205 status.retval = mSink->getPresentationPosition(
206 status.reply.presentationPosition.frames,
207 status.reply.presentationPosition.timeStamp);
208
209 return status;
210 }
211
doGetLatencyandroid::hardware::audio::CPP_VERSION::implementation::__anon06eeb58a0111::WriteThread212 IStreamOut::WriteStatus doGetLatency() {
213 IStreamOut::WriteStatus status;
214
215 const int latencyMs =
216 DevicePortSink::getLatencyMs(mStream->getDeviceAddress(),
217 mStream->getAudioConfig());
218
219 if (latencyMs >= 0) {
220 status.retval = Result::OK;
221 status.reply.latencyMs = latencyMs;
222 } else {
223 status.retval = Result::INVALID_STATE;
224 }
225
226 return status;
227 }
228
229 StreamOut *const mStream;
230 CommandMQ mCommandMQ;
231 StatusMQ mStatusMQ;
232 DataMQ mDataMQ;
233 std::unique_ptr<EventFlag, deleters::forEventFlag> mEfGroup;
234 std::unique_ptr<DevicePortSink> mSink;
235 std::thread mThread;
236 std::promise<pthread_t> mTid;
237 };
238
239 } // namespace
240
StreamOut(sp<Device> dev,int32_t ioHandle,const DeviceAddress & device,const AudioConfig & config,hidl_vec<AudioInOutFlag> flags,const SourceMetadata & sourceMetadata)241 StreamOut::StreamOut(sp<Device> dev,
242 int32_t ioHandle,
243 const DeviceAddress& device,
244 const AudioConfig& config,
245 hidl_vec<AudioInOutFlag> flags,
246 const SourceMetadata& sourceMetadata)
247 : mDev(std::move(dev))
248 , mCommon(ioHandle, device, config, std::move(flags))
249 , mSourceMetadata(sourceMetadata) {}
250
~StreamOut()251 StreamOut::~StreamOut() {
252 closeImpl(true);
253 }
254
getFrameSize()255 Return<uint64_t> StreamOut::getFrameSize() {
256 return mCommon.getFrameSize();
257 }
258
getFrameCount()259 Return<uint64_t> StreamOut::getFrameCount() {
260 return mCommon.getFrameCount();
261 }
262
getBufferSize()263 Return<uint64_t> StreamOut::getBufferSize() {
264 return mCommon.getBufferSize();
265 }
266
getSupportedProfiles(getSupportedProfiles_cb _hidl_cb)267 Return<void> StreamOut::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) {
268 mCommon.getSupportedProfiles(_hidl_cb);
269 return Void();
270 }
271
getAudioProperties(getAudioProperties_cb _hidl_cb)272 Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
273 mCommon.getAudioProperties(_hidl_cb);
274 return Void();
275 }
276
setAudioProperties(const AudioConfigBaseOptional & config)277 Return<Result> StreamOut::setAudioProperties(const AudioConfigBaseOptional& config) {
278 (void)config;
279 return FAILURE(Result::NOT_SUPPORTED);
280 }
281
addEffect(uint64_t effectId)282 Return<Result> StreamOut::addEffect(uint64_t effectId) {
283 (void)effectId;
284 return FAILURE(Result::INVALID_ARGUMENTS);
285 }
286
removeEffect(uint64_t effectId)287 Return<Result> StreamOut::removeEffect(uint64_t effectId) {
288 (void)effectId;
289 return FAILURE(Result::INVALID_ARGUMENTS);
290 }
291
standby()292 Return<Result> StreamOut::standby() {
293 if (mWriteThread) {
294 LOG_ALWAYS_FATAL_IF(!mWriteThread->standby());
295 }
296
297 return Result::OK;
298 }
299
getDevices(getDevices_cb _hidl_cb)300 Return<void> StreamOut::getDevices(getDevices_cb _hidl_cb) {
301 mCommon.getDevices(_hidl_cb);
302 return Void();
303 }
304
setDevices(const hidl_vec<DeviceAddress> & devices)305 Return<Result> StreamOut::setDevices(const hidl_vec<DeviceAddress>& devices) {
306 return mCommon.setDevices(devices);
307 }
308
getParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)309 Return<void> StreamOut::getParameters(const hidl_vec<ParameterValue>& context,
310 const hidl_vec<hidl_string>& keys,
311 getParameters_cb _hidl_cb) {
312 (void)context;
313 _hidl_cb((keys.size() > 0) ? Result::NOT_SUPPORTED : Result::OK, {});
314 return Void();
315 }
316
setParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<ParameterValue> & parameters)317 Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& context,
318 const hidl_vec<ParameterValue>& parameters) {
319 (void)context;
320 (void)parameters;
321 return Result::OK;
322 }
323
setHwAvSync(uint32_t hwAvSync)324 Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
325 (void)hwAvSync;
326 return FAILURE(Result::NOT_SUPPORTED);
327 }
328
closeImpl(const bool fromDctor)329 Result StreamOut::closeImpl(const bool fromDctor) {
330 if (mDev) {
331 mWriteThread.reset();
332 mDev->unrefDevice(this);
333 mDev = nullptr;
334 return Result::OK;
335 } else if (fromDctor) {
336 // closeImpl is always called from the dctor, it is ok if mDev is null,
337 // we don't want to log the error in this case.
338 return Result::OK;
339 } else {
340 return FAILURE(Result::INVALID_STATE);
341 }
342 }
343
close()344 Return<Result> StreamOut::close() {
345 return closeImpl(false);
346 }
347
start()348 Return<Result> StreamOut::start() {
349 return FAILURE(Result::NOT_SUPPORTED);
350 }
351
stop()352 Return<Result> StreamOut::stop() {
353 return FAILURE(Result::NOT_SUPPORTED);
354 }
355
createMmapBuffer(int32_t minSizeFrames,createMmapBuffer_cb _hidl_cb)356 Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames,
357 createMmapBuffer_cb _hidl_cb) {
358 (void)minSizeFrames;
359 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
360 return Void();
361 }
362
getMmapPosition(getMmapPosition_cb _hidl_cb)363 Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
364 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
365 return Void();
366 }
367
getLatency()368 Return<uint32_t> StreamOut::getLatency() {
369 const int latencyMs = DevicePortSink::getLatencyMs(getDeviceAddress(), getAudioConfig());
370
371 return (latencyMs >= 0) ? latencyMs :
372 (mCommon.getFrameCount() * 1000 / mCommon.getSampleRate());
373 }
374
setVolume(float left,float right)375 Return<Result> StreamOut::setVolume(float left, float right) {
376 if (isnan(left) || left < 0.0f || left > 1.0f
377 || right < 0.0f || right > 1.0f || isnan(right)) {
378 return FAILURE(Result::INVALID_ARGUMENTS);
379 }
380
381 std::lock_guard<std::mutex> guard(mMutex);
382 mStreamVolume = (left + right) / 2.0f;
383 updateEffectiveVolumeLocked();
384 return Result::OK;
385 }
386
updateSourceMetadata(const SourceMetadata & sourceMetadata)387 Return<Result> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
388 (void)sourceMetadata;
389 return Result::NOT_SUPPORTED;
390 }
391
prepareForWriting(uint32_t frameSize,uint32_t framesCount,prepareForWriting_cb _hidl_cb)392 Return<void> StreamOut::prepareForWriting(uint32_t frameSize,
393 uint32_t framesCount,
394 prepareForWriting_cb _hidl_cb) {
395 if (!frameSize || !framesCount || frameSize > 256 || framesCount > (1u << 20)) {
396 _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, -1);
397 return Void();
398 }
399
400 if (mWriteThread) { // INVALID_STATE if the method was already called.
401 _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {}, {}, -1);
402 return Void();
403 }
404
405 auto t = std::make_unique<WriteThread>(this, frameSize * framesCount);
406
407 if (t->isRunning()) {
408 _hidl_cb(Result::OK,
409 *(t->mCommandMQ.getDesc()),
410 *(t->mDataMQ.getDesc()),
411 *(t->mStatusMQ.getDesc()),
412 t->getTid().get());
413
414 mWriteThread = std::move(t);
415 } else {
416 _hidl_cb(FAILURE(Result::INVALID_ARGUMENTS), {}, {}, {}, -1);
417 }
418
419 return Void();
420 }
421
getRenderPosition(getRenderPosition_cb _hidl_cb)422 Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
423 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
424 return Void();
425 }
426
getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb)427 Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
428 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
429 return Void();
430 }
431
setCallback(const sp<IStreamOutCallback> & callback)432 Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
433 (void)callback;
434 return FAILURE(Result::NOT_SUPPORTED);
435 }
436
clearCallback()437 Return<Result> StreamOut::clearCallback() {
438 return FAILURE(Result::NOT_SUPPORTED);
439 }
440
setEventCallback(const sp<IStreamOutEventCallback> & callback)441 Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& callback) {
442 (void)callback;
443 return Result::NOT_SUPPORTED;
444 }
445
supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb)446 Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
447 _hidl_cb(false, false);
448 return Void();
449 }
450
pause()451 Return<Result> StreamOut::pause() {
452 return FAILURE(Result::NOT_SUPPORTED);
453 }
454
resume()455 Return<Result> StreamOut::resume() {
456 return FAILURE(Result::NOT_SUPPORTED);
457 }
458
supportsDrain()459 Return<bool> StreamOut::supportsDrain() {
460 return false;
461 }
462
drain(AudioDrain type)463 Return<Result> StreamOut::drain(AudioDrain type) {
464 (void)type;
465 return FAILURE(Result::NOT_SUPPORTED);
466 }
467
flush()468 Return<Result> StreamOut::flush() {
469 return FAILURE(Result::NOT_SUPPORTED);
470 }
471
getPresentationPosition(getPresentationPosition_cb _hidl_cb)472 Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
473 const auto w = static_cast<WriteThread*>(mWriteThread.get());
474 if (!w) {
475 _hidl_cb(FAILURE(Result::INVALID_STATE), {}, {});
476 return Void();
477 }
478
479 const auto s = w->mSink.get();
480 if (!s) {
481 _hidl_cb(Result::OK, mFrames, util::nsecs2TimeSpec(systemTime(SYSTEM_TIME_MONOTONIC)));
482 } else {
483 uint64_t frames;
484 TimeSpec ts;
485 const Result r = s->getPresentationPosition(frames, ts);
486 _hidl_cb(r, frames, ts);
487 }
488
489 return Void();
490 }
491
selectPresentation(int32_t presentationId,int32_t programId)492 Return<Result> StreamOut::selectPresentation(int32_t presentationId,
493 int32_t programId) {
494 (void)presentationId;
495 (void)programId;
496 return FAILURE(Result::NOT_SUPPORTED);
497 }
498
getDualMonoMode(getDualMonoMode_cb _hidl_cb)499 Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
500 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
501 return Void();
502 }
503
setDualMonoMode(DualMonoMode mode)504 Return<Result> StreamOut::setDualMonoMode(DualMonoMode mode) {
505 (void)mode;
506 return FAILURE(Result::NOT_SUPPORTED);
507 }
508
getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb)509 Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) {
510 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), 0);
511 return Void();
512 }
513
setAudioDescriptionMixLevel(float leveldB)514 Return<Result> StreamOut::setAudioDescriptionMixLevel(float leveldB) {
515 (void)leveldB;
516 return FAILURE(Result::NOT_SUPPORTED);
517 }
518
getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb)519 Return<void> StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) {
520 _hidl_cb(FAILURE(Result::NOT_SUPPORTED), {});
521 return Void();
522 }
523
setPlaybackRateParameters(const PlaybackRate & playbackRate)524 Return<Result> StreamOut::setPlaybackRateParameters(const PlaybackRate &playbackRate) {
525 (void)playbackRate;
526 return FAILURE(Result::NOT_SUPPORTED);
527 }
528
529 #if MAJOR_VERSION == 7 && MINOR_VERSION == 1
setLatencyMode(LatencyMode mode __unused)530 Return<Result> StreamOut::setLatencyMode(LatencyMode mode __unused) {
531 return FAILURE(Result::NOT_SUPPORTED);
532 };
533
getRecommendedLatencyModes(getRecommendedLatencyModes_cb _hidl_cb)534 Return<void> StreamOut::getRecommendedLatencyModes(getRecommendedLatencyModes_cb _hidl_cb) {
535 hidl_vec<LatencyMode> hidlModes;
536 _hidl_cb(Result::NOT_SUPPORTED, hidlModes);
537 return Void();
538 };
539
setLatencyModeCallback(const sp<IStreamOutLatencyModeCallback> & callback __unused)540 Return<Result> StreamOut::setLatencyModeCallback(
541 const sp<IStreamOutLatencyModeCallback>& callback __unused) {
542 return FAILURE(Result::NOT_SUPPORTED);
543 };
544 #endif
545
setMasterVolume(float masterVolume)546 void StreamOut::setMasterVolume(float masterVolume) {
547 std::lock_guard<std::mutex> guard(mMutex);
548 mMasterVolume = masterVolume;
549 updateEffectiveVolumeLocked();
550 }
551
updateEffectiveVolumeLocked()552 void StreamOut::updateEffectiveVolumeLocked() {
553 mEffectiveVolume = mMasterVolume * mStreamVolume;
554 }
555
validateDeviceAddress(const DeviceAddress & device)556 bool StreamOut::validateDeviceAddress(const DeviceAddress& device) {
557 return DevicePortSink::validateDeviceAddress(device);
558 }
559
validateFlags(const hidl_vec<AudioInOutFlag> & flags)560 bool StreamOut::validateFlags(const hidl_vec<AudioInOutFlag>& flags) {
561 return std::all_of(flags.begin(), flags.end(), [](const AudioInOutFlag& flag){
562 return xsd::stringToAudioInOutFlag(flag) != xsd::AudioInOutFlag::UNKNOWN;
563 });
564 }
565
validateSourceMetadata(const SourceMetadata & sourceMetadata)566 bool StreamOut::validateSourceMetadata(const SourceMetadata& sourceMetadata) {
567 for (const auto& track : sourceMetadata.tracks) {
568 if (xsd::isUnknownAudioUsage(track.usage)
569 || xsd::isUnknownAudioContentType(track.contentType)
570 || xsd::isUnknownAudioChannelMask(track.channelMask)) {
571 return false;
572 }
573 for (const auto& tag : track.tags) {
574 if (!xsd::isVendorExtension(tag)) {
575 return false;
576 }
577 }
578 }
579 return true;
580 }
581
582 } // namespace implementation
583 } // namespace CPP_VERSION
584 } // namespace audio
585 } // namespace hardware
586 } // namespace android
587