1 /*
2  * Copyright (C) 2018 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 #define LOG_TAG "StreamOutHAL"
18 
19 #include "core/default/StreamOut.h"
20 #include "core/default/Util.h"
21 
22 //#define LOG_NDEBUG 0
23 #define ATRACE_TAG ATRACE_TAG_AUDIO
24 
25 #include <string.h>
26 
27 #include <memory>
28 
29 #include <HidlUtils.h>
30 #include <android/log.h>
31 #include <audio_utils/Metadata.h>
32 #include <hardware/audio.h>
33 #include <util/CoreUtils.h>
34 #include <utils/Trace.h>
35 
36 namespace android {
37 namespace hardware {
38 namespace audio {
39 namespace CPP_VERSION {
40 namespace implementation {
41 
42 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
43 
44 namespace {
45 
46 class WriteThread : public Thread {
47    public:
48     // WriteThread's lifespan never exceeds StreamOut's lifespan.
WriteThread(std::atomic<bool> * stop,audio_stream_out_t * stream,StreamOut::CommandMQ * commandMQ,StreamOut::DataMQ * dataMQ,StreamOut::StatusMQ * statusMQ,EventFlag * efGroup)49     WriteThread(std::atomic<bool>* stop, audio_stream_out_t* stream,
50                 StreamOut::CommandMQ* commandMQ, StreamOut::DataMQ* dataMQ,
51                 StreamOut::StatusMQ* statusMQ, EventFlag* efGroup)
52         : Thread(false /*canCallJava*/),
53           mStop(stop),
54           mStream(stream),
55           mCommandMQ(commandMQ),
56           mDataMQ(dataMQ),
57           mStatusMQ(statusMQ),
58           mEfGroup(efGroup),
59           mBuffer(nullptr) {}
init()60     bool init() {
61         mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
62         return mBuffer != nullptr;
63     }
~WriteThread()64     virtual ~WriteThread() {}
65 
66    private:
67     std::atomic<bool>* mStop;
68     audio_stream_out_t* mStream;
69     StreamOut::CommandMQ* mCommandMQ;
70     StreamOut::DataMQ* mDataMQ;
71     StreamOut::StatusMQ* mStatusMQ;
72     EventFlag* mEfGroup;
73     std::unique_ptr<uint8_t[]> mBuffer;
74     IStreamOut::WriteStatus mStatus;
75 
76     bool threadLoop() override;
77 
78     void doGetLatency();
79     void doGetPresentationPosition();
80     void doWrite();
81 };
82 
doWrite()83 void WriteThread::doWrite() {
84     const size_t availToRead = mDataMQ->availableToRead();
85     mStatus.retval = Result::OK;
86     mStatus.reply.written = 0;
87     if (mDataMQ->read(&mBuffer[0], availToRead)) {
88         ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
89         if (writeResult >= 0) {
90             mStatus.reply.written = writeResult;
91         } else {
92             mStatus.retval = Stream::analyzeStatus("write", writeResult);
93         }
94     }
95 }
96 
doGetPresentationPosition()97 void WriteThread::doGetPresentationPosition() {
98     mStatus.retval =
99         StreamOut::getPresentationPositionImpl(mStream, &mStatus.reply.presentationPosition.frames,
100                                                &mStatus.reply.presentationPosition.timeStamp);
101 }
102 
doGetLatency()103 void WriteThread::doGetLatency() {
104     mStatus.retval = Result::OK;
105     mStatus.reply.latencyMs = mStream->get_latency(mStream);
106 }
107 
threadLoop()108 bool WriteThread::threadLoop() {
109     // This implementation doesn't return control back to the Thread until it
110     // decides to stop,
111     // as the Thread uses mutexes, and this can lead to priority inversion.
112     while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
113         uint32_t efState = 0;
114         mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
115         if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
116             continue;  // Nothing to do.
117         }
118         if (!mCommandMQ->read(&mStatus.replyTo)) {
119             continue;  // Nothing to do.
120         }
121         switch (mStatus.replyTo) {
122             case IStreamOut::WriteCommand::WRITE:
123                 doWrite();
124                 break;
125             case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION:
126                 doGetPresentationPosition();
127                 break;
128             case IStreamOut::WriteCommand::GET_LATENCY:
129                 doGetLatency();
130                 break;
131             default:
132                 ALOGE("Unknown write thread command code %d", mStatus.replyTo);
133                 mStatus.retval = Result::NOT_SUPPORTED;
134                 break;
135         }
136         if (!mStatusMQ->write(&mStatus)) {
137             ALOGE("status message queue write failed");
138         }
139         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
140     }
141 
142     return false;
143 }
144 
145 }  // namespace
146 
StreamOut(const sp<Device> & device,audio_stream_out_t * stream)147 StreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream)
148     : mDevice(device),
149       mStream(stream),
150       mStreamCommon(new Stream(false /*isInput*/, &stream->common)),
151       mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
152       mEfGroup(nullptr),
153       mStopWriteThread(false) {}
154 
~StreamOut()155 StreamOut::~StreamOut() {
156     ATRACE_CALL();
157     (void)close();
158     if (mWriteThread.get()) {
159         ATRACE_NAME("mWriteThread->join");
160         status_t status = mWriteThread->join();
161         ALOGE_IF(status, "write thread exit error: %s", strerror(-status));
162     }
163     if (mEfGroup) {
164         status_t status = EventFlag::deleteEventFlag(&mEfGroup);
165         ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
166     }
167     mCallback = nullptr;
168 #if MAJOR_VERSION <= 5
169     mDevice->closeOutputStream(mStream);
170     // Closing the output stream in the HAL waits for the callback to finish,
171     // and joins the callback thread. Thus is it guaranteed that the callback
172     // thread will not be accessing our object anymore.
173 #endif
174     mStream = nullptr;
175 }
176 
177 // Methods from ::android::hardware::audio::CPP_VERSION::IStream follow.
getFrameSize()178 Return<uint64_t> StreamOut::getFrameSize() {
179     return audio_stream_out_frame_size(mStream);
180 }
181 
getFrameCount()182 Return<uint64_t> StreamOut::getFrameCount() {
183     return mStreamCommon->getFrameCount();
184 }
185 
getBufferSize()186 Return<uint64_t> StreamOut::getBufferSize() {
187     return mStreamCommon->getBufferSize();
188 }
189 
190 #if MAJOR_VERSION <= 6
getSampleRate()191 Return<uint32_t> StreamOut::getSampleRate() {
192     return mStreamCommon->getSampleRate();
193 }
194 
195 #if MAJOR_VERSION == 2
getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb)196 Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
197     return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
198 }
getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb)199 Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
200     return mStreamCommon->getSupportedSampleRates(_hidl_cb);
201 }
202 #endif
203 
getSupportedChannelMasks(AudioFormat format,getSupportedChannelMasks_cb _hidl_cb)204 Return<void> StreamOut::getSupportedChannelMasks(AudioFormat format,
205                                                  getSupportedChannelMasks_cb _hidl_cb) {
206     return mStreamCommon->getSupportedChannelMasks(format, _hidl_cb);
207 }
getSupportedSampleRates(AudioFormat format,getSupportedSampleRates_cb _hidl_cb)208 Return<void> StreamOut::getSupportedSampleRates(AudioFormat format,
209                                                 getSupportedSampleRates_cb _hidl_cb) {
210     return mStreamCommon->getSupportedSampleRates(format, _hidl_cb);
211 }
212 
setSampleRate(uint32_t sampleRateHz)213 Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
214     return mStreamCommon->setSampleRate(sampleRateHz);
215 }
216 
getChannelMask()217 Return<AudioChannelBitfield> StreamOut::getChannelMask() {
218     return mStreamCommon->getChannelMask();
219 }
220 
setChannelMask(AudioChannelBitfield mask)221 Return<Result> StreamOut::setChannelMask(AudioChannelBitfield mask) {
222     return mStreamCommon->setChannelMask(mask);
223 }
224 
getFormat()225 Return<AudioFormat> StreamOut::getFormat() {
226     return mStreamCommon->getFormat();
227 }
228 
getSupportedFormats(getSupportedFormats_cb _hidl_cb)229 Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
230     return mStreamCommon->getSupportedFormats(_hidl_cb);
231 }
232 
setFormat(AudioFormat format)233 Return<Result> StreamOut::setFormat(AudioFormat format) {
234     return mStreamCommon->setFormat(format);
235 }
236 
237 #else
238 
getSupportedProfiles(getSupportedProfiles_cb _hidl_cb)239 Return<void> StreamOut::getSupportedProfiles(getSupportedProfiles_cb _hidl_cb) {
240     return mStreamCommon->getSupportedProfiles(_hidl_cb);
241 }
242 
setAudioProperties(const AudioConfigBaseOptional & config)243 Return<Result> StreamOut::setAudioProperties(const AudioConfigBaseOptional& config) {
244     return mStreamCommon->setAudioProperties(config);
245 }
246 
247 #endif  // MAJOR_VERSION <= 6
248 
getAudioProperties(getAudioProperties_cb _hidl_cb)249 Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
250     return mStreamCommon->getAudioProperties(_hidl_cb);
251 }
252 
addEffect(uint64_t effectId)253 Return<Result> StreamOut::addEffect(uint64_t effectId) {
254     return mStreamCommon->addEffect(effectId);
255 }
256 
removeEffect(uint64_t effectId)257 Return<Result> StreamOut::removeEffect(uint64_t effectId) {
258     return mStreamCommon->removeEffect(effectId);
259 }
260 
standby()261 Return<Result> StreamOut::standby() {
262     return mStreamCommon->standby();
263 }
264 
setHwAvSync(uint32_t hwAvSync)265 Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
266     return mStreamCommon->setHwAvSync(hwAvSync);
267 }
268 
269 #if MAJOR_VERSION == 2
setConnectedState(const DeviceAddress & address,bool connected)270 Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) {
271     return mStreamCommon->setConnectedState(address, connected);
272 }
273 
getDevice()274 Return<AudioDevice> StreamOut::getDevice() {
275     return mStreamCommon->getDevice();
276 }
277 
setDevice(const DeviceAddress & address)278 Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
279     return mStreamCommon->setDevice(address);
280 }
281 
getParameters(const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)282 Return<void> StreamOut::getParameters(const hidl_vec<hidl_string>& keys,
283                                       getParameters_cb _hidl_cb) {
284     return mStreamCommon->getParameters(keys, _hidl_cb);
285 }
286 
setParameters(const hidl_vec<ParameterValue> & parameters)287 Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) {
288     return mStreamCommon->setParameters(parameters);
289 }
290 
debugDump(const hidl_handle & fd)291 Return<void> StreamOut::debugDump(const hidl_handle& fd) {
292     return mStreamCommon->debugDump(fd);
293 }
294 #elif MAJOR_VERSION >= 4
getDevices(getDevices_cb _hidl_cb)295 Return<void> StreamOut::getDevices(getDevices_cb _hidl_cb) {
296     return mStreamCommon->getDevices(_hidl_cb);
297 }
298 
setDevices(const hidl_vec<DeviceAddress> & devices)299 Return<Result> StreamOut::setDevices(const hidl_vec<DeviceAddress>& devices) {
300     return mStreamCommon->setDevices(devices);
301 }
getParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<hidl_string> & keys,getParameters_cb _hidl_cb)302 Return<void> StreamOut::getParameters(const hidl_vec<ParameterValue>& context,
303                                       const hidl_vec<hidl_string>& keys,
304                                       getParameters_cb _hidl_cb) {
305     return mStreamCommon->getParameters(context, keys, _hidl_cb);
306 }
307 
setParameters(const hidl_vec<ParameterValue> & context,const hidl_vec<ParameterValue> & parameters)308 Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& context,
309                                         const hidl_vec<ParameterValue>& parameters) {
310     return mStreamCommon->setParameters(context, parameters);
311 }
312 #endif
313 
close()314 Return<Result> StreamOut::close() {
315     if (mStopWriteThread.load(std::memory_order_relaxed)) {  // only this thread writes
316         return Result::INVALID_STATE;
317     }
318     mStopWriteThread.store(true, std::memory_order_release);
319     if (mEfGroup) {
320         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
321     }
322 #if MAJOR_VERSION >= 6
323     mDevice->closeOutputStream(mStream);
324 #endif
325     return Result::OK;
326 }
327 
328 // Methods from ::android::hardware::audio::CPP_VERSION::IStreamOut follow.
getLatency()329 Return<uint32_t> StreamOut::getLatency() {
330     return mStream->get_latency(mStream);
331 }
332 
setVolume(float left,float right)333 Return<Result> StreamOut::setVolume(float left, float right) {
334     if (mStream->set_volume == NULL) {
335         return Result::NOT_SUPPORTED;
336     }
337     if (!isGainNormalized(left)) {
338         ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left, right);
339         return Result::INVALID_ARGUMENTS;
340     }
341     return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right),
342                                  {ENOSYS} /*ignore*/);
343 }
344 
prepareForWriting(uint32_t frameSize,uint32_t framesCount,prepareForWriting_cb _hidl_cb)345 Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount,
346                                           prepareForWriting_cb _hidl_cb) {
347     status_t status;
348 #if MAJOR_VERSION <= 6
349     ThreadInfo threadInfo = {0, 0};
350 #else
351     int32_t threadInfo = 0;
352 #endif
353 
354     // Wrap the _hidl_cb to return an error
355     auto sendError = [&threadInfo, &_hidl_cb](Result result) {
356         _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(),
357                  threadInfo);
358     };
359 
360     // Create message queues.
361     if (mDataMQ) {
362         ALOGE("the client attempts to call prepareForWriting twice");
363         sendError(Result::INVALID_STATE);
364         return Void();
365     }
366     std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
367 
368     // Check frameSize and framesCount
369     if (frameSize == 0 || framesCount == 0) {
370         ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize, framesCount);
371         sendError(Result::INVALID_ARGUMENTS);
372         return Void();
373     }
374     if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) {
375         ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount,
376               Stream::MAX_BUFFER_SIZE);
377         sendError(Result::INVALID_ARGUMENTS);
378         return Void();
379     }
380     std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */));
381 
382     std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
383     if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
384         ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
385         ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
386         ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
387         sendError(Result::INVALID_ARGUMENTS);
388         return Void();
389     }
390     EventFlag* tempRawEfGroup{};
391     status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup);
392     std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
393         tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
394     if (status != OK || !tempElfGroup) {
395         ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
396         sendError(Result::INVALID_ARGUMENTS);
397         return Void();
398     }
399 
400     // Create and launch the thread.
401     auto tempWriteThread =
402             sp<WriteThread>::make(&mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
403                                   tempStatusMQ.get(), tempElfGroup.get());
404     if (!tempWriteThread->init()) {
405         ALOGW("failed to start writer thread: %s", strerror(-status));
406         sendError(Result::INVALID_ARGUMENTS);
407         return Void();
408     }
409     status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO);
410     if (status != OK) {
411         ALOGW("failed to start writer thread: %s", strerror(-status));
412         sendError(Result::INVALID_ARGUMENTS);
413         return Void();
414     }
415 
416     mCommandMQ = std::move(tempCommandMQ);
417     mDataMQ = std::move(tempDataMQ);
418     mStatusMQ = std::move(tempStatusMQ);
419     mWriteThread = tempWriteThread;
420     mEfGroup = tempElfGroup.release();
421 #if MAJOR_VERSION <= 6
422     threadInfo.pid = getpid();
423     threadInfo.tid = mWriteThread->getTid();
424 #else
425     threadInfo = mWriteThread->getTid();
426 #endif
427     _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
428              threadInfo);
429     return Void();
430 }
431 
getRenderPosition(getRenderPosition_cb _hidl_cb)432 Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
433     uint32_t halDspFrames;
434     Result retval = Stream::analyzeStatus("get_render_position",
435                                           mStream->get_render_position(mStream, &halDspFrames),
436                                           {ENOSYS} /*ignore*/);
437     _hidl_cb(retval, halDspFrames);
438     return Void();
439 }
440 
getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb)441 Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
442     Result retval(Result::NOT_SUPPORTED);
443     int64_t timestampUs = 0;
444     if (mStream->get_next_write_timestamp != NULL) {
445         retval = Stream::analyzeStatus("get_next_write_timestamp",
446                                        mStream->get_next_write_timestamp(mStream, &timestampUs),
447                                        {ENOSYS} /*ignore*/);
448     }
449     _hidl_cb(retval, timestampUs);
450     return Void();
451 }
452 
setCallback(const sp<IStreamOutCallback> & callback)453 Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
454     if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
455     // Safe to pass 'this' because it is guaranteed that the callback thread
456     // is joined prior to exit from StreamOut's destructor.
457     int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this);
458     if (result == 0) {
459         mCallback = callback;
460     }
461     return Stream::analyzeStatus("set_callback", result, {ENOSYS} /*ignore*/);
462 }
463 
clearCallback()464 Return<Result> StreamOut::clearCallback() {
465     if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
466     mCallback = nullptr;
467     return Result::OK;
468 }
469 
470 // static
asyncCallback(stream_callback_event_t event,void *,void * cookie)471 int StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie) {
472     // It is guaranteed that the callback thread is joined prior
473     // to exiting from StreamOut's destructor. Must *not* use sp<StreamOut>
474     // here because it can make this code the last owner of StreamOut,
475     // and an attempt to run the destructor on the callback thread
476     // will cause a deadlock in the legacy HAL code.
477     StreamOut* self = reinterpret_cast<StreamOut*>(cookie);
478     // It's correct to hold an sp<> to callback because the reference
479     // in the StreamOut instance can be cleared in the meantime. There is
480     // no difference on which thread to run IStreamOutCallback's destructor.
481     sp<IStreamOutCallback> callback = self->mCallback.load();
482     if (callback.get() == nullptr) return 0;
483     ALOGV("asyncCallback() event %d", event);
484     Return<void> result;
485     switch (event) {
486         case STREAM_CBK_EVENT_WRITE_READY:
487             result = callback->onWriteReady();
488             break;
489         case STREAM_CBK_EVENT_DRAIN_READY:
490             result = callback->onDrainReady();
491             break;
492         case STREAM_CBK_EVENT_ERROR:
493             result = callback->onError();
494             break;
495         default:
496             ALOGW("asyncCallback() unknown event %d", event);
497             break;
498     }
499     ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
500     return 0;
501 }
502 
supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb)503 Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
504     _hidl_cb(mStream->pause != NULL, mStream->resume != NULL);
505     return Void();
506 }
507 
pause()508 Return<Result> StreamOut::pause() {
509     return mStream->pause != NULL
510                    ? Stream::analyzeStatus("pause", mStream->pause(mStream), {ENOSYS} /*ignore*/)
511                    : Result::NOT_SUPPORTED;
512 }
513 
resume()514 Return<Result> StreamOut::resume() {
515     return mStream->resume != NULL
516                    ? Stream::analyzeStatus("resume", mStream->resume(mStream), {ENOSYS} /*ignore*/)
517                    : Result::NOT_SUPPORTED;
518 }
519 
supportsDrain()520 Return<bool> StreamOut::supportsDrain() {
521     return mStream->drain != NULL;
522 }
523 
drain(AudioDrain type)524 Return<Result> StreamOut::drain(AudioDrain type) {
525     audio_drain_type_t halDrainType =
526             type == AudioDrain::EARLY_NOTIFY ? AUDIO_DRAIN_EARLY_NOTIFY : AUDIO_DRAIN_ALL;
527     return mStream->drain != NULL
528                    ? Stream::analyzeStatus("drain", mStream->drain(mStream, halDrainType),
529                                            {ENOSYS} /*ignore*/)
530                    : Result::NOT_SUPPORTED;
531 }
532 
flush()533 Return<Result> StreamOut::flush() {
534     return mStream->flush != NULL
535                    ? Stream::analyzeStatus("flush", mStream->flush(mStream), {ENOSYS} /*ignore*/)
536                    : Result::NOT_SUPPORTED;
537 }
538 
539 // static
getPresentationPositionImpl(audio_stream_out_t * stream,uint64_t * frames,TimeSpec * timeStamp)540 Result StreamOut::getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames,
541                                               TimeSpec* timeStamp) {
542     // Don't logspam on EINVAL--it's normal for get_presentation_position
543     // to return it sometimes. EAGAIN may be returned by A2DP audio HAL
544     // implementation. ENODATA can also be reported while the writer is
545     // continuously querying it, but the stream has been stopped.
546     static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA, ENOSYS};
547     Result retval(Result::NOT_SUPPORTED);
548     if (stream->get_presentation_position == NULL) return retval;
549     struct timespec halTimeStamp;
550     retval = Stream::analyzeStatus("get_presentation_position",
551                                    stream->get_presentation_position(stream, frames, &halTimeStamp),
552                                    ignoredErrors);
553     if (retval == Result::OK) {
554         timeStamp->tvSec = halTimeStamp.tv_sec;
555         timeStamp->tvNSec = halTimeStamp.tv_nsec;
556     }
557     return retval;
558 }
559 
getPresentationPosition(getPresentationPosition_cb _hidl_cb)560 Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
561     uint64_t frames = 0;
562     TimeSpec timeStamp = {0, 0};
563     Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp);
564     _hidl_cb(retval, frames, timeStamp);
565     return Void();
566 }
567 
start()568 Return<Result> StreamOut::start() {
569     return mStreamMmap->start();
570 }
571 
stop()572 Return<Result> StreamOut::stop() {
573     return mStreamMmap->stop();
574 }
575 
createMmapBuffer(int32_t minSizeFrames,createMmapBuffer_cb _hidl_cb)576 Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
577     return mStreamMmap->createMmapBuffer(minSizeFrames, audio_stream_out_frame_size(mStream),
578                                          _hidl_cb);
579 }
580 
getMmapPosition(getMmapPosition_cb _hidl_cb)581 Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
582     return mStreamMmap->getMmapPosition(_hidl_cb);
583 }
584 
debug(const hidl_handle & fd,const hidl_vec<hidl_string> & options)585 Return<void> StreamOut::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
586     return mStreamCommon->debug(fd, options);
587 }
588 
589 #if MAJOR_VERSION >= 4
doUpdateSourceMetadata(const SourceMetadata & sourceMetadata)590 Result StreamOut::doUpdateSourceMetadata(const SourceMetadata& sourceMetadata) {
591     std::vector<playback_track_metadata_t> halTracks;
592 #if MAJOR_VERSION <= 6
593     (void)CoreUtils::sourceMetadataToHal(sourceMetadata, &halTracks);
594 #else
595     // Validate whether a conversion to V7 is possible. This is needed
596     // to have a consistent behavior of the HAL regardless of the API
597     // version of the legacy HAL (and also to be consistent with openOutputStream).
598     std::vector<playback_track_metadata_v7> halTracksV7;
599     if (status_t status = CoreUtils::sourceMetadataToHalV7(
600                 sourceMetadata, false /*ignoreNonVendorTags*/, &halTracksV7);
601         status == NO_ERROR) {
602         halTracks.reserve(halTracksV7.size());
603         for (auto metadata_v7 : halTracksV7) {
604             halTracks.push_back(std::move(metadata_v7.base));
605         }
606     } else {
607         return Stream::analyzeStatus("sourceMetadataToHal", status);
608     }
609 #endif  // MAJOR_VERSION <= 6
610     const source_metadata_t halMetadata = {
611         .track_count = halTracks.size(),
612         .tracks = halTracks.data(),
613     };
614     mStream->update_source_metadata(mStream, &halMetadata);
615     return Result::OK;
616 }
617 
618 #if MAJOR_VERSION >= 7
doUpdateSourceMetadataV7(const SourceMetadata & sourceMetadata)619 Result StreamOut::doUpdateSourceMetadataV7(const SourceMetadata& sourceMetadata) {
620     std::vector<playback_track_metadata_v7> halTracks;
621     if (status_t status = CoreUtils::sourceMetadataToHalV7(
622                 sourceMetadata, false /*ignoreNonVendorTags*/, &halTracks);
623         status != NO_ERROR) {
624         return Stream::analyzeStatus("sourceMetadataToHal", status);
625     }
626     const source_metadata_v7_t halMetadata = {
627             .track_count = halTracks.size(),
628             .tracks = halTracks.data(),
629     };
630     mStream->update_source_metadata_v7(mStream, &halMetadata);
631     return Result::OK;
632 }
633 #endif  //  MAJOR_VERSION >= 7
634 
635 #if MAJOR_VERSION <= 6
updateSourceMetadata(const SourceMetadata & sourceMetadata)636 Return<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
637     if (mStream->update_source_metadata == nullptr) {
638         return Void();  // not supported by the HAL
639     }
640     (void)doUpdateSourceMetadata(sourceMetadata);
641     return Void();
642 }
643 #elif MAJOR_VERSION >= 7
updateSourceMetadata(const SourceMetadata & sourceMetadata)644 Return<Result> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) {
645     if (mDevice->version() < AUDIO_DEVICE_API_VERSION_3_2) {
646         if (mStream->update_source_metadata == nullptr) {
647             return Result::NOT_SUPPORTED;
648         }
649         return doUpdateSourceMetadata(sourceMetadata);
650     } else {
651         if (mStream->update_source_metadata_v7 == nullptr) {
652             return Result::NOT_SUPPORTED;
653         }
654         return doUpdateSourceMetadataV7(sourceMetadata);
655     }
656 }
657 #endif
658 
selectPresentation(int32_t,int32_t)659 Return<Result> StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t /*programId*/) {
660     return Result::NOT_SUPPORTED;  // TODO: propagate to legacy
661 }
662 #endif
663 
664 #if MAJOR_VERSION >= 6
getDualMonoMode(getDualMonoMode_cb _hidl_cb)665 Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
666     audio_dual_mono_mode_t mode = AUDIO_DUAL_MONO_MODE_OFF;
667     Result retval = mStream->get_dual_mono_mode != nullptr
668                             ? Stream::analyzeStatus("get_dual_mono_mode",
669                                                     mStream->get_dual_mono_mode(mStream, &mode))
670                             : Result::NOT_SUPPORTED;
671     _hidl_cb(retval, DualMonoMode(mode));
672     return Void();
673 }
674 
setDualMonoMode(DualMonoMode mode)675 Return<Result> StreamOut::setDualMonoMode(DualMonoMode mode) {
676     return mStream->set_dual_mono_mode != nullptr
677                    ? Stream::analyzeStatus(
678                              "set_dual_mono_mode",
679                              mStream->set_dual_mono_mode(mStream,
680                                                          static_cast<audio_dual_mono_mode_t>(mode)))
681                    : Result::NOT_SUPPORTED;
682 }
683 
getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb)684 Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) {
685     float leveldB = -std::numeric_limits<float>::infinity();
686     Result retval = mStream->get_audio_description_mix_level != nullptr
687                             ? Stream::analyzeStatus(
688                                       "get_audio_description_mix_level",
689                                       mStream->get_audio_description_mix_level(mStream, &leveldB))
690                             : Result::NOT_SUPPORTED;
691     _hidl_cb(retval, leveldB);
692     return Void();
693 }
694 
setAudioDescriptionMixLevel(float leveldB)695 Return<Result> StreamOut::setAudioDescriptionMixLevel(float leveldB) {
696     return mStream->set_audio_description_mix_level != nullptr
697                    ? Stream::analyzeStatus(
698                              "set_audio_description_mix_level",
699                              mStream->set_audio_description_mix_level(mStream, leveldB))
700                    : Result::NOT_SUPPORTED;
701 }
702 
getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb)703 Return<void> StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) {
704     audio_playback_rate_t rate = AUDIO_PLAYBACK_RATE_INITIALIZER;
705     Result retval =
706             mStream->get_playback_rate_parameters != nullptr
707                     ? Stream::analyzeStatus("get_playback_rate_parameters",
708                                             mStream->get_playback_rate_parameters(mStream, &rate))
709                     : Result::NOT_SUPPORTED;
710     _hidl_cb(retval,
711              PlaybackRate{rate.mSpeed, rate.mPitch, static_cast<TimestretchMode>(rate.mStretchMode),
712                           static_cast<TimestretchFallbackMode>(rate.mFallbackMode)});
713     return Void();
714 }
715 
setPlaybackRateParameters(const PlaybackRate & playbackRate)716 Return<Result> StreamOut::setPlaybackRateParameters(const PlaybackRate& playbackRate) {
717     audio_playback_rate_t rate = {
718             playbackRate.speed, playbackRate.pitch,
719             static_cast<audio_timestretch_stretch_mode_t>(playbackRate.timestretchMode),
720             static_cast<audio_timestretch_fallback_mode_t>(playbackRate.fallbackMode)};
721     return mStream->set_playback_rate_parameters != nullptr
722                    ? Stream::analyzeStatus("set_playback_rate_parameters",
723                                            mStream->set_playback_rate_parameters(mStream, &rate))
724                    : Result::NOT_SUPPORTED;
725 }
726 
setEventCallback(const sp<IStreamOutEventCallback> & callback)727 Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& callback) {
728     if (mStream->set_event_callback == nullptr) return Result::NOT_SUPPORTED;
729     int result = mStream->set_event_callback(mStream, StreamOut::asyncEventCallback, this);
730     if (result == 0) {
731         mEventCallback = callback;
732     }
733     return Stream::analyzeStatus("set_stream_out_callback", result, {ENOSYS} /*ignore*/);
734 }
735 
736 // static
asyncEventCallback(stream_event_callback_type_t event,void * param,void * cookie)737 int StreamOut::asyncEventCallback(stream_event_callback_type_t event, void* param, void* cookie) {
738     StreamOut* self = reinterpret_cast<StreamOut*>(cookie);
739     sp<IStreamOutEventCallback> eventCallback = self->mEventCallback.load();
740     if (eventCallback.get() == nullptr) return 0;
741     ALOGV("%s event %d", __func__, event);
742     Return<void> result;
743     switch (event) {
744         case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED: {
745             hidl_vec<uint8_t> audioMetadata;
746             // void* param is the byte string buffer from byte_string_from_audio_metadata().
747             // As the byte string buffer may have embedded zeroes, we cannot use strlen()
748             // but instead use audio_utils::metadata::dataByteStringLen().
749             audioMetadata.setToExternal((uint8_t*)param, audio_utils::metadata::dataByteStringLen(
750                                                                  (const uint8_t*)param));
751             result = eventCallback->onCodecFormatChanged(audioMetadata);
752         } break;
753         default:
754             ALOGW("%s unknown event %d", __func__, event);
755             break;
756     }
757     ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
758     return 0;
759 }
760 #endif
761 
762 }  // namespace implementation
763 }  // namespace CPP_VERSION
764 }  // namespace audio
765 }  // namespace hardware
766 }  // namespace android
767