1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "StreamOutImpl.h"
16
17 #include <android-base/logging.h>
18 #include <inttypes.h>
19 #include <math.h>
20 #include <system/audio-hal-enums.h>
21 #include <time.h>
22 #include <utils/Log.h>
23
24 #include <cstring>
25
26 #include "AidlTypes.h"
27 #include "BusOutputStream.h"
28 #include "WriteThread.h"
29
30 using android::status_t;
31
32 namespace audio_proxy::service {
33
34 namespace {
35
36 // 1GB
37 constexpr uint32_t kMaxBufferSize = 1 << 30;
38
39 constexpr int64_t kOneSecInNs = 1'000'000'000;
40
deleteEventFlag(EventFlag * obj)41 void deleteEventFlag(EventFlag* obj) {
42 if (!obj) {
43 return;
44 }
45
46 status_t status = EventFlag::deleteEventFlag(&obj);
47 if (status) {
48 LOG(ERROR) << "Write MQ event flag deletion error: " << strerror(-status);
49 }
50 }
51
estimatePlayedFramesSince(const TimeSpec & timestamp,uint32_t sampleRateHz)52 uint64_t estimatePlayedFramesSince(const TimeSpec& timestamp,
53 uint32_t sampleRateHz) {
54 timespec now = {0, 0};
55 clock_gettime(CLOCK_MONOTONIC, &now);
56 int64_t deltaSec = 0;
57 int64_t deltaNSec = 0;
58 if (now.tv_nsec >= timestamp.tvNSec) {
59 deltaSec = now.tv_sec - timestamp.tvSec;
60 deltaNSec = now.tv_nsec - timestamp.tvNSec;
61 } else {
62 deltaSec = now.tv_sec - timestamp.tvSec - 1;
63 deltaNSec = kOneSecInNs + now.tv_nsec - timestamp.tvNSec;
64 }
65
66 if (deltaSec < 0 || deltaNSec < 0) {
67 return 0;
68 }
69
70 return deltaSec * sampleRateHz + deltaNSec * sampleRateHz / kOneSecInNs;
71 }
72
73 } // namespace
74
StreamOutImpl(std::shared_ptr<BusOutputStream> stream,const StreamOutConfig & config,uint32_t bufferSizeMs,uint32_t latencyMs)75 StreamOutImpl::StreamOutImpl(std::shared_ptr<BusOutputStream> stream,
76 const StreamOutConfig& config,
77 uint32_t bufferSizeMs, uint32_t latencyMs)
78 : mStream(std::move(stream)),
79 mConfig(config),
80 mBufferSizeMs(bufferSizeMs),
81 mLatencyMs(latencyMs),
82 mEventFlag(nullptr, deleteEventFlag) {}
83
~StreamOutImpl()84 StreamOutImpl::~StreamOutImpl() {
85 if (mWriteThread) {
86 mWriteThread->stop();
87 status_t status = mWriteThread->join();
88 if (status) {
89 LOG(ERROR) << "write thread exit error " << strerror(-status);
90 }
91 }
92
93 mEventFlag.reset();
94 }
95
getFrameSize()96 Return<uint64_t> StreamOutImpl::getFrameSize() {
97 return mStream->getFrameSize();
98 }
99
getFrameCount()100 Return<uint64_t> StreamOutImpl::getFrameCount() {
101 return mBufferSizeMs * mConfig.sampleRateHz / 1000;
102 }
103
getBufferSize()104 Return<uint64_t> StreamOutImpl::getBufferSize() {
105 return mBufferSizeMs * mConfig.sampleRateHz * mStream->getFrameSize() / 1000;
106 }
107
108 #if MAJOR_VERSION >= 7
getSupportedProfiles(getSupportedProfiles_cb _hidl_cb)109 Return<void> StreamOutImpl::getSupportedProfiles(
110 getSupportedProfiles_cb _hidl_cb) {
111 // For devices with fixed configuration, this method can return NOT_SUPPORTED.
112 _hidl_cb(Result::NOT_SUPPORTED, {});
113 return Void();
114 }
115
getAudioProperties(getAudioProperties_cb _hidl_cb)116 Return<void> StreamOutImpl::getAudioProperties(getAudioProperties_cb _hidl_cb) {
117 _hidl_cb(Result::OK, mConfig);
118 return Void();
119 }
120
setAudioProperties(const AudioConfigBaseOptional & config)121 Return<Result> StreamOutImpl::setAudioProperties(
122 const AudioConfigBaseOptional& config) {
123 return Result::NOT_SUPPORTED;
124 }
125 #else
getSampleRate()126 Return<uint32_t> StreamOutImpl::getSampleRate() { return mConfig.sampleRateHz; }
127
getSupportedSampleRates(AudioFormat format,getSupportedSampleRates_cb _hidl_cb)128 Return<void> StreamOutImpl::getSupportedSampleRates(
129 AudioFormat format, getSupportedSampleRates_cb _hidl_cb) {
130 _hidl_cb(Result::NOT_SUPPORTED, {});
131 return Void();
132 }
133
getSupportedChannelMasks(AudioFormat format,getSupportedChannelMasks_cb _hidl_cb)134 Return<void> StreamOutImpl::getSupportedChannelMasks(
135 AudioFormat format, getSupportedChannelMasks_cb _hidl_cb) {
136 _hidl_cb(Result::NOT_SUPPORTED, {});
137 return Void();
138 }
139
setSampleRate(uint32_t sampleRateHz)140 Return<Result> StreamOutImpl::setSampleRate(uint32_t sampleRateHz) {
141 return Result::NOT_SUPPORTED;
142 }
143
getChannelMask()144 Return<hidl_bitfield<AudioChannelMask>> StreamOutImpl::getChannelMask() {
145 return mConfig.channelMask;
146 }
147
setChannelMask(hidl_bitfield<AudioChannelMask> mask)148 Return<Result> StreamOutImpl::setChannelMask(
149 hidl_bitfield<AudioChannelMask> mask) {
150 return Result::NOT_SUPPORTED;
151 }
152
getFormat()153 Return<AudioFormat> StreamOutImpl::getFormat() { return mConfig.format; }
154
getSupportedFormats(getSupportedFormats_cb _hidl_cb)155 Return<void> StreamOutImpl::getSupportedFormats(
156 getSupportedFormats_cb _hidl_cb) {
157 #if MAJOR_VERSION >= 6
158 _hidl_cb(Result::NOT_SUPPORTED, {});
159 #else
160 _hidl_cb({});
161 #endif
162 return Void();
163 }
164
setFormat(AudioFormat format)165 Return<Result> StreamOutImpl::setFormat(AudioFormat format) {
166 return Result::NOT_SUPPORTED;
167 }
168
getAudioProperties(getAudioProperties_cb _hidl_cb)169 Return<void> StreamOutImpl::getAudioProperties(getAudioProperties_cb _hidl_cb) {
170 _hidl_cb(mConfig.sampleRateHz, mConfig.channelMask, mConfig.format);
171 return Void();
172 }
173 #endif
174
175 // We don't support effects. So any effectId is invalid.
addEffect(uint64_t effectId)176 Return<Result> StreamOutImpl::addEffect(uint64_t effectId) {
177 return Result::INVALID_ARGUMENTS;
178 }
179
removeEffect(uint64_t effectId)180 Return<Result> StreamOutImpl::removeEffect(uint64_t effectId) {
181 return Result::INVALID_ARGUMENTS;
182 }
183
standby()184 Return<Result> StreamOutImpl::standby() {
185 bool success = mStream->standby();
186 if (!success) {
187 return Result::INVALID_STATE;
188 }
189
190 mTotalPlayedFramesSinceStandby = estimateTotalPlayedFrames();
191 return Result::OK;
192 }
193
getDevices(getDevices_cb _hidl_cb)194 Return<void> StreamOutImpl::getDevices(getDevices_cb _hidl_cb) {
195 _hidl_cb(Result::NOT_SUPPORTED, {});
196 return Void();
197 }
198
setDevices(const hidl_vec<DeviceAddress> & devices)199 Return<Result> StreamOutImpl::setDevices(
200 const hidl_vec<DeviceAddress>& devices) {
201 return Result::NOT_SUPPORTED;
202 }
203
getParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)204 Return<void> StreamOutImpl::getParameters(
205 const hidl_vec<ParameterValue>& context, const hidl_vec<hidl_string>& keys,
206 getParameters_cb _hidl_cb) {
207 _hidl_cb(keys.size() > 0 ? Result::NOT_SUPPORTED : Result::OK, {});
208 return Void();
209 }
210
setParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<ParameterValue> & parameters)211 Return<Result> StreamOutImpl::setParameters(
212 const hidl_vec<ParameterValue>& context,
213 const hidl_vec<ParameterValue>& parameters) {
214 return Result::OK;
215 }
216
setHwAvSync(uint32_t hwAvSync)217 Return<Result> StreamOutImpl::setHwAvSync(uint32_t hwAvSync) {
218 return Result::NOT_SUPPORTED;
219 }
220
close()221 Return<Result> StreamOutImpl::close() {
222 if (!mStream) {
223 return Result::INVALID_STATE;
224 }
225
226 if (mWriteThread) {
227 mWriteThread->stop();
228 }
229
230 if (!mStream->close()) {
231 LOG(WARNING) << "Failed to close stream.";
232 }
233
234 mStream = nullptr;
235
236 return Result::OK;
237 }
238
getLatency()239 Return<uint32_t> StreamOutImpl::getLatency() { return mLatencyMs; }
240
setVolume(float left,float right)241 Return<Result> StreamOutImpl::setVolume(float left, float right) {
242 if (isnan(left) || left < 0.f || left > 1.f || isnan(right) || right < 0.f ||
243 right > 1.f) {
244 return Result::INVALID_ARGUMENTS;
245 }
246 return mStream->setVolume(left, right) ? Result::OK : Result::INVALID_STATE;
247 }
248
prepareForWriting(uint32_t frameSize,uint32_t framesCount,prepareForWriting_cb _hidl_cb)249 Return<void> StreamOutImpl::prepareForWriting(uint32_t frameSize,
250 uint32_t framesCount,
251 prepareForWriting_cb _hidl_cb) {
252 #if MAJOR_VERSION >= 7
253 int32_t threadInfo = 0;
254 #else
255 ThreadInfo threadInfo = {0, 0};
256 #endif
257
258 // Wrap the _hidl_cb to return an error
259 auto sendError = [&threadInfo, &_hidl_cb](Result result) -> Return<void> {
260 _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(),
261 StatusMQ::Descriptor(), threadInfo);
262 return Void();
263 };
264
265 if (mDataMQ) {
266 LOG(ERROR) << "The client attempted to call prepareForWriting twice";
267 return sendError(Result::INVALID_STATE);
268 }
269
270 if (frameSize == 0 || framesCount == 0) {
271 LOG(ERROR) << "Invalid frameSize (" << frameSize << ") or framesCount ("
272 << framesCount << ")";
273 return sendError(Result::INVALID_ARGUMENTS);
274 }
275
276 if (frameSize > kMaxBufferSize / framesCount) {
277 LOG(ERROR) << "Buffer too big: " << frameSize << "*" << framesCount
278 << " bytes > MAX_BUFFER_SIZE (" << kMaxBufferSize << ")";
279 return sendError(Result::INVALID_ARGUMENTS);
280 }
281
282 auto commandMQ = std::make_unique<CommandMQ>(1);
283 if (!commandMQ->isValid()) {
284 LOG(ERROR) << "Command MQ is invalid";
285 return sendError(Result::INVALID_ARGUMENTS);
286 }
287
288 auto dataMQ =
289 std::make_unique<DataMQ>(frameSize * framesCount, true /* EventFlag */);
290 if (!dataMQ->isValid()) {
291 LOG(ERROR) << "Data MQ is invalid";
292 return sendError(Result::INVALID_ARGUMENTS);
293 }
294
295 auto statusMQ = std::make_unique<StatusMQ>(1);
296 if (!statusMQ->isValid()) {
297 LOG(ERROR) << "Status MQ is invalid";
298 return sendError(Result::INVALID_ARGUMENTS);
299 }
300
301 EventFlag* rawEventFlag = nullptr;
302 status_t status =
303 EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &rawEventFlag);
304 std::unique_ptr<EventFlag, EventFlagDeleter> eventFlag(rawEventFlag,
305 deleteEventFlag);
306 if (status != ::android::OK || !eventFlag) {
307 LOG(ERROR) << "Failed creating event flag for data MQ: "
308 << strerror(-status);
309 return sendError(Result::INVALID_ARGUMENTS);
310 }
311
312 if (!mStream->prepareForWriting(frameSize, framesCount)) {
313 LOG(ERROR) << "Failed to prepare writing channel.";
314 return sendError(Result::INVALID_ARGUMENTS);
315 }
316
317 sp<WriteThread> writeThread =
318 sp<WriteThread>::make(mStream, commandMQ.get(), dataMQ.get(),
319 statusMQ.get(), eventFlag.get(), mLatencyMs);
320 status = writeThread->run("writer", ::android::PRIORITY_URGENT_AUDIO);
321 if (status != ::android::OK) {
322 LOG(ERROR) << "Failed to start writer thread: " << strerror(-status);
323 return sendError(Result::INVALID_ARGUMENTS);
324 }
325
326 mCommandMQ = std::move(commandMQ);
327 mDataMQ = std::move(dataMQ);
328 mStatusMQ = std::move(statusMQ);
329 mEventFlag = std::move(eventFlag);
330 mWriteThread = std::move(writeThread);
331
332 #if MAJOR_VERSION >= 7
333 threadInfo = mWriteThread->getTid();
334 #else
335 threadInfo.pid = getpid();
336 threadInfo.tid = mWriteThread->getTid();
337 #endif
338
339 _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(),
340 *mStatusMQ->getDesc(), threadInfo);
341
342 return Void();
343 }
344
getRenderPosition(getRenderPosition_cb _hidl_cb)345 Return<void> StreamOutImpl::getRenderPosition(getRenderPosition_cb _hidl_cb) {
346 uint64_t totalPlayedFrames = estimateTotalPlayedFrames();
347 if (totalPlayedFrames == 0) {
348 _hidl_cb(Result::OK, 0);
349 return Void();
350 }
351
352 // getRenderPosition returns the number of frames played since the output has
353 // exited standby.
354 DCHECK_GE(totalPlayedFrames, mTotalPlayedFramesSinceStandby);
355 uint64_t position = totalPlayedFrames - mTotalPlayedFramesSinceStandby;
356
357 if (position > std::numeric_limits<uint32_t>::max()) {
358 _hidl_cb(Result::INVALID_STATE, 0);
359 return Void();
360 }
361
362 _hidl_cb(Result::OK, position);
363 return Void();
364 }
365
getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb)366 Return<void> StreamOutImpl::getNextWriteTimestamp(
367 getNextWriteTimestamp_cb _hidl_cb) {
368 _hidl_cb(Result::NOT_SUPPORTED, 0);
369 return Void();
370 }
371
setCallback(const sp<IStreamOutCallback> & callback)372 Return<Result> StreamOutImpl::setCallback(
373 const sp<IStreamOutCallback>& callback) {
374 return Result::NOT_SUPPORTED;
375 }
376
clearCallback()377 Return<Result> StreamOutImpl::clearCallback() { return Result::NOT_SUPPORTED; }
378
supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb)379 Return<void> StreamOutImpl::supportsPauseAndResume(
380 supportsPauseAndResume_cb _hidl_cb) {
381 _hidl_cb(true, true);
382 return Void();
383 }
384
385 // pause should not be called before starting the playback.
pause()386 Return<Result> StreamOutImpl::pause() {
387 if (!mWriteThread) {
388 return Result::INVALID_STATE;
389 }
390
391 if (!mStream->pause()) {
392 return Result::INVALID_STATE;
393 }
394
395 mIsPaused = true;
396 return Result::OK;
397 }
398
399 // Resume should onl be called after pause.
resume()400 Return<Result> StreamOutImpl::resume() {
401 if (!mIsPaused) {
402 return Result::INVALID_STATE;
403 }
404
405 if (!mStream->resume()) {
406 return Result::INVALID_STATE;
407 }
408
409 mIsPaused = false;
410 return Result::OK;
411 }
412
413 // Drain and flush should always succeed if supported.
supportsDrain()414 Return<bool> StreamOutImpl::supportsDrain() { return true; }
415
drain(AudioDrain type)416 Return<Result> StreamOutImpl::drain(AudioDrain type) {
417 if (!mStream->drain(static_cast<AidlAudioDrain>(type))) {
418 LOG(WARNING) << "Failed to drain the stream.";
419 }
420
421 return Result::OK;
422 }
423
flush()424 Return<Result> StreamOutImpl::flush() {
425 if (!mStream->flush()) {
426 LOG(WARNING) << "Failed to flush the stream.";
427 }
428
429 return Result::OK;
430 }
431
getPresentationPosition(getPresentationPosition_cb _hidl_cb)432 Return<void> StreamOutImpl::getPresentationPosition(
433 getPresentationPosition_cb _hidl_cb) {
434 if (!mWriteThread) {
435 _hidl_cb(Result::INVALID_STATE, 0, {});
436 return Void();
437 }
438
439 auto [frames, timestamp] = mWriteThread->getPresentationPosition();
440 _hidl_cb(Result::OK, frames, timestamp);
441 return Void();
442 }
443
start()444 Return<Result> StreamOutImpl::start() { return Result::NOT_SUPPORTED; }
445
stop()446 Return<Result> StreamOutImpl::stop() { return Result::NOT_SUPPORTED; }
447
createMmapBuffer(int32_t minSizeFrames,createMmapBuffer_cb _hidl_cb)448 Return<void> StreamOutImpl::createMmapBuffer(int32_t minSizeFrames,
449 createMmapBuffer_cb _hidl_cb) {
450 _hidl_cb(Result::NOT_SUPPORTED, MmapBufferInfo());
451 return Void();
452 }
453
getMmapPosition(getMmapPosition_cb _hidl_cb)454 Return<void> StreamOutImpl::getMmapPosition(getMmapPosition_cb _hidl_cb) {
455 _hidl_cb(Result::NOT_SUPPORTED, MmapPosition());
456 return Void();
457 }
458
459 #if MAJOR_VERSION >= 7
updateSourceMetadata(const SourceMetadata & sourceMetadata)460 Return<Result> StreamOutImpl::updateSourceMetadata(
461 const SourceMetadata& sourceMetadata) {
462 return Result::NOT_SUPPORTED;
463 }
464 #else
updateSourceMetadata(const SourceMetadata & sourceMetadata)465 Return<void> StreamOutImpl::updateSourceMetadata(
466 const SourceMetadata& sourceMetadata) {
467 return Void();
468 }
469 #endif
470
selectPresentation(int32_t presentationId,int32_t programId)471 Return<Result> StreamOutImpl::selectPresentation(int32_t presentationId,
472 int32_t programId) {
473 return Result::NOT_SUPPORTED;
474 }
475
getOutputStream()476 std::shared_ptr<BusOutputStream> StreamOutImpl::getOutputStream() {
477 return mStream;
478 }
479
updateOutputStream(std::shared_ptr<BusOutputStream> stream)480 void StreamOutImpl::updateOutputStream(
481 std::shared_ptr<BusOutputStream> stream) {
482 DCHECK(stream);
483 DCHECK(mStream);
484 if (stream->getConfig() != mStream->getConfig()) {
485 LOG(ERROR) << "New stream's config doesn't match the old stream's config.";
486 return;
487 }
488
489 if (mWriteThread) {
490 if (!stream->prepareForWriting(mStream->getWritingFrameSize(),
491 mStream->getWritingFrameCount())) {
492 LOG(ERROR) << "Failed to prepare writing channel.";
493 return;
494 }
495
496 mWriteThread->updateOutputStream(stream);
497 }
498
499 mStream = std::move(stream);
500 }
501
estimateTotalPlayedFrames() const502 uint64_t StreamOutImpl::estimateTotalPlayedFrames() const {
503 if (!mWriteThread) {
504 return 0;
505 }
506
507 auto [frames, timestamp] = mWriteThread->getPresentationPosition();
508 return frames + estimatePlayedFramesSince(timestamp, mConfig.sampleRateHz);
509 }
510
511 #if MAJOR_VERSION >= 6
setEventCallback(const sp<IStreamOutEventCallback> & callback)512 Return<Result> StreamOutImpl::setEventCallback(
513 const sp<IStreamOutEventCallback>& callback) {
514 return Result::NOT_SUPPORTED;
515 }
516
getDualMonoMode(getDualMonoMode_cb _hidl_cb)517 Return<void> StreamOutImpl::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
518 _hidl_cb(Result::NOT_SUPPORTED, DualMonoMode::OFF);
519 return Void();
520 }
521
setDualMonoMode(DualMonoMode mode)522 Return<Result> StreamOutImpl::setDualMonoMode(DualMonoMode mode) {
523 return Result::NOT_SUPPORTED;
524 }
525
getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb)526 Return<void> StreamOutImpl::getAudioDescriptionMixLevel(
527 getAudioDescriptionMixLevel_cb _hidl_cb) {
528 _hidl_cb(Result::NOT_SUPPORTED, 0.f);
529 return Void();
530 }
531
setAudioDescriptionMixLevel(float leveldB)532 Return<Result> StreamOutImpl::setAudioDescriptionMixLevel(float leveldB) {
533 return Result::NOT_SUPPORTED;
534 }
535
getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb)536 Return<void> StreamOutImpl::getPlaybackRateParameters(
537 getPlaybackRateParameters_cb _hidl_cb) {
538 _hidl_cb(Result::NOT_SUPPORTED, {});
539 return Void();
540 }
541
setPlaybackRateParameters(const PlaybackRate & playbackRate)542 Return<Result> StreamOutImpl::setPlaybackRateParameters(
543 const PlaybackRate& playbackRate) {
544 return Result::NOT_SUPPORTED;
545 }
546 #endif
547
548 #if MAJOR_VERSION == 7 && MINOR_VERSION == 1
setLatencyMode(android::hardware::audio::V7_1::LatencyMode mode)549 Return<Result> StreamOutImpl::setLatencyMode(
550 android::hardware::audio::V7_1::LatencyMode mode) {
551 return Result::NOT_SUPPORTED;
552 }
553
getRecommendedLatencyModes(getRecommendedLatencyModes_cb _hidl_cb)554 Return<void> StreamOutImpl::getRecommendedLatencyModes(
555 getRecommendedLatencyModes_cb _hidl_cb) {
556 _hidl_cb(Result::NOT_SUPPORTED, {});
557 return Void();
558 }
559
setLatencyModeCallback(const sp<android::hardware::audio::V7_1::IStreamOutLatencyModeCallback> & cb)560 Return<Result> StreamOutImpl::setLatencyModeCallback(
561 const sp<android::hardware::audio::V7_1::IStreamOutLatencyModeCallback>&
562 cb) {
563 return Result::NOT_SUPPORTED;
564 }
565 #endif
566
567 } // namespace audio_proxy::service
568