• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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