StreamOut.impl.h revision 72e50e2ef1480fc3d90f0d88c7e9e3595622e75c
110548295023bee99108e418499aff09fe578211eMikhail Naganov/* 210548295023bee99108e418499aff09fe578211eMikhail Naganov * Copyright (C) 2016 The Android Open Source Project 310548295023bee99108e418499aff09fe578211eMikhail Naganov * 410548295023bee99108e418499aff09fe578211eMikhail Naganov * Licensed under the Apache License, Version 2.0 (the "License"); 510548295023bee99108e418499aff09fe578211eMikhail Naganov * you may not use this file except in compliance with the License. 610548295023bee99108e418499aff09fe578211eMikhail Naganov * You may obtain a copy of the License at 710548295023bee99108e418499aff09fe578211eMikhail Naganov * 810548295023bee99108e418499aff09fe578211eMikhail Naganov * http://www.apache.org/licenses/LICENSE-2.0 910548295023bee99108e418499aff09fe578211eMikhail Naganov * 1010548295023bee99108e418499aff09fe578211eMikhail Naganov * Unless required by applicable law or agreed to in writing, software 1110548295023bee99108e418499aff09fe578211eMikhail Naganov * distributed under the License is distributed on an "AS IS" BASIS, 1210548295023bee99108e418499aff09fe578211eMikhail Naganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1310548295023bee99108e418499aff09fe578211eMikhail Naganov * See the License for the specific language governing permissions and 1410548295023bee99108e418499aff09fe578211eMikhail Naganov * limitations under the License. 1510548295023bee99108e418499aff09fe578211eMikhail Naganov */ 1610548295023bee99108e418499aff09fe578211eMikhail Naganov 1710548295023bee99108e418499aff09fe578211eMikhail Naganov#define LOG_TAG "StreamOutHAL" 18685f0e36a1185b24f473f0382ba2175685dbcdf9Mikhail Naganov//#define LOG_NDEBUG 0 19b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov#define ATRACE_TAG ATRACE_TAG_AUDIO 2010548295023bee99108e418499aff09fe578211eMikhail Naganov 2167d550888a021633cc33cb284bb0658b008887c6Kevin Rocard#include <memory> 2267d550888a021633cc33cb284bb0658b008887c6Kevin Rocard 23f9d303435d80161fabb16cdff3b8f2f75f362480Yifan Hong#include <android/log.h> 24b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov#include <hardware/audio.h> 25b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov#include <utils/Trace.h> 2610548295023bee99108e418499aff09fe578211eMikhail Naganov 2710548295023bee99108e418499aff09fe578211eMikhail Naganov#include "StreamOut.h" 2810548295023bee99108e418499aff09fe578211eMikhail Naganov 2910548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace android { 3010548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace hardware { 3110548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace audio { 3210548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace V2_0 { 3310548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace implementation { 3410548295023bee99108e418499aff09fe578211eMikhail Naganov 35a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganovusing ::android::hardware::audio::common::V2_0::ThreadInfo; 36a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov 37b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovnamespace { 38b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 39b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovclass WriteThread : public Thread { 4072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard public: 41b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // WriteThread's lifespan never exceeds StreamOut's lifespan. 4272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard WriteThread(std::atomic<bool>* stop, audio_stream_out_t* stream, 4372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard StreamOut::CommandMQ* commandMQ, StreamOut::DataMQ* dataMQ, 4472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard StreamOut::StatusMQ* statusMQ, EventFlag* efGroup) 4572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Thread(false /*canCallJava*/), 4672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStop(stop), 4772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream(stream), 4872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mCommandMQ(commandMQ), 4972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mDataMQ(dataMQ), 5072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStatusMQ(statusMQ), 5172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mEfGroup(efGroup), 5272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mBuffer(nullptr) {} 5367d550888a021633cc33cb284bb0658b008887c6Kevin Rocard bool init() { 5472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]); 5567d550888a021633cc33cb284bb0658b008887c6Kevin Rocard return mBuffer != nullptr; 56b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 57b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov virtual ~WriteThread() {} 58b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 5972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard private: 60b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::atomic<bool>* mStop; 61b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov audio_stream_out_t* mStream; 62a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov StreamOut::CommandMQ* mCommandMQ; 63b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::DataMQ* mDataMQ; 64b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::StatusMQ* mStatusMQ; 65b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov EventFlag* mEfGroup; 66b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<uint8_t[]> mBuffer; 67a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov IStreamOut::WriteStatus mStatus; 68b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 69b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov bool threadLoop() override; 70a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 71a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doGetLatency(); 72a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doGetPresentationPosition(); 73a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doWrite(); 74b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov}; 75b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 76a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doWrite() { 77a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov const size_t availToRead = mDataMQ->availableToRead(); 78a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::OK; 79a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.written = 0; 80a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (mDataMQ->read(&mBuffer[0], availToRead)) { 81a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead); 82a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (writeResult >= 0) { 83a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.written = writeResult; 84a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } else { 85a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Stream::analyzeStatus("write", writeResult); 86a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 87a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 88a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 89a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 90a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doGetPresentationPosition() { 91a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = StreamOut::getPresentationPositionImpl( 9272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream, &mStatus.reply.presentationPosition.frames, 9372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard &mStatus.reply.presentationPosition.timeStamp); 94a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 95a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 96a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doGetLatency() { 97a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::OK; 98a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.latencyMs = mStream->get_latency(mStream); 99a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 100a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 101b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovbool WriteThread::threadLoop() { 10272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // This implementation doesn't return control back to the Thread until it 10372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // decides to stop, 104b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // as the Thread uses mutexes, and this can lead to priority inversion. 10572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) { 106b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov uint32_t efState = 0; 10772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), 10872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard &efState); 10972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard if (!(efState & 11072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) { 111b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov continue; // Nothing to do. 112b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 113a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (!mCommandMQ->read(&mStatus.replyTo)) { 114a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov continue; // Nothing to do. 115a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 116a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov switch (mStatus.replyTo) { 117a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::WRITE: 118a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doWrite(); 119a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 120a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION: 121a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doGetPresentationPosition(); 122a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 123a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::GET_LATENCY: 124a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doGetLatency(); 125a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 126a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov default: 127a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE("Unknown write thread command code %d", mStatus.replyTo); 128a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::NOT_SUPPORTED; 129a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 130b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 131a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (!mStatusMQ->write(&mStatus)) { 132a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE("status message queue write failed"); 133b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 134b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); 135b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 136b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 137b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return false; 138b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 139b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 140b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} // namespace 141b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 142936279e1ffe6bf7e842c46f9a94d98a48dce6754Mikhail NaganovStreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream) 14372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : mIsClosed(false), 14472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mDevice(device), 14572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream(stream), 14672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStreamCommon(new Stream(&stream->common)), 14772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)), 14872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mEfGroup(nullptr), 14972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStopWriteThread(false) {} 15010548295023bee99108e418499aff09fe578211eMikhail Naganov 15110548295023bee99108e418499aff09fe578211eMikhail NaganovStreamOut::~StreamOut() { 152b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ATRACE_CALL(); 153b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov close(); 154b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov if (mWriteThread.get()) { 155b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ATRACE_NAME("mWriteThread->join"); 156b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov status_t status = mWriteThread->join(); 157b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ALOGE_IF(status, "write thread exit error: %s", strerror(-status)); 158b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov } 159b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov if (mEfGroup) { 160b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov status_t status = EventFlag::deleteEventFlag(&mEfGroup); 16172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ALOGE_IF(status, "write MQ event flag deletion error: %s", 16272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard strerror(-status)); 163b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov } 164b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov mCallback.clear(); 165936279e1ffe6bf7e842c46f9a94d98a48dce6754Mikhail Naganov mDevice->closeOutputStream(mStream); 16610548295023bee99108e418499aff09fe578211eMikhail Naganov mStream = nullptr; 16710548295023bee99108e418499aff09fe578211eMikhail Naganov} 16810548295023bee99108e418499aff09fe578211eMikhail Naganov 16910548295023bee99108e418499aff09fe578211eMikhail Naganov// Methods from ::android::hardware::audio::V2_0::IStream follow. 17072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getFrameSize() { 17110548295023bee99108e418499aff09fe578211eMikhail Naganov return audio_stream_out_frame_size(mStream); 17210548295023bee99108e418499aff09fe578211eMikhail Naganov} 17310548295023bee99108e418499aff09fe578211eMikhail Naganov 17472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getFrameCount() { 17510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFrameCount(); 17610548295023bee99108e418499aff09fe578211eMikhail Naganov} 17710548295023bee99108e418499aff09fe578211eMikhail Naganov 17872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getBufferSize() { 17910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getBufferSize(); 18010548295023bee99108e418499aff09fe578211eMikhail Naganov} 18110548295023bee99108e418499aff09fe578211eMikhail Naganov 18272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint32_t> StreamOut::getSampleRate() { 18310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSampleRate(); 18410548295023bee99108e418499aff09fe578211eMikhail Naganov} 18510548295023bee99108e418499aff09fe578211eMikhail Naganov 18672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getSupportedSampleRates( 18772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard getSupportedSampleRates_cb _hidl_cb) { 18810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedSampleRates(_hidl_cb); 18910548295023bee99108e418499aff09fe578211eMikhail Naganov} 19010548295023bee99108e418499aff09fe578211eMikhail Naganov 19172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) { 19210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setSampleRate(sampleRateHz); 19310548295023bee99108e418499aff09fe578211eMikhail Naganov} 19410548295023bee99108e418499aff09fe578211eMikhail Naganov 19572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<AudioChannelMask> StreamOut::getChannelMask() { 19610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getChannelMask(); 19710548295023bee99108e418499aff09fe578211eMikhail Naganov} 19810548295023bee99108e418499aff09fe578211eMikhail Naganov 19972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getSupportedChannelMasks( 20072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard getSupportedChannelMasks_cb _hidl_cb) { 20110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedChannelMasks(_hidl_cb); 20210548295023bee99108e418499aff09fe578211eMikhail Naganov} 20310548295023bee99108e418499aff09fe578211eMikhail Naganov 20472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setChannelMask(AudioChannelMask mask) { 20510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setChannelMask(mask); 20610548295023bee99108e418499aff09fe578211eMikhail Naganov} 20710548295023bee99108e418499aff09fe578211eMikhail Naganov 20872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<AudioFormat> StreamOut::getFormat() { 20910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFormat(); 21010548295023bee99108e418499aff09fe578211eMikhail Naganov} 21110548295023bee99108e418499aff09fe578211eMikhail Naganov 21272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { 21310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedFormats(_hidl_cb); 21410548295023bee99108e418499aff09fe578211eMikhail Naganov} 21510548295023bee99108e418499aff09fe578211eMikhail Naganov 21672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setFormat(AudioFormat format) { 21710548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setFormat(format); 21810548295023bee99108e418499aff09fe578211eMikhail Naganov} 21910548295023bee99108e418499aff09fe578211eMikhail Naganov 22072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) { 22110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getAudioProperties(_hidl_cb); 22210548295023bee99108e418499aff09fe578211eMikhail Naganov} 22310548295023bee99108e418499aff09fe578211eMikhail Naganov 22472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::addEffect(uint64_t effectId) { 22510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->addEffect(effectId); 22610548295023bee99108e418499aff09fe578211eMikhail Naganov} 22710548295023bee99108e418499aff09fe578211eMikhail Naganov 22872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::removeEffect(uint64_t effectId) { 22910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->removeEffect(effectId); 23010548295023bee99108e418499aff09fe578211eMikhail Naganov} 23110548295023bee99108e418499aff09fe578211eMikhail Naganov 23272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::standby() { 23310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->standby(); 23410548295023bee99108e418499aff09fe578211eMikhail Naganov} 23510548295023bee99108e418499aff09fe578211eMikhail Naganov 23672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<AudioDevice> StreamOut::getDevice() { 23710548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getDevice(); 23810548295023bee99108e418499aff09fe578211eMikhail Naganov} 23910548295023bee99108e418499aff09fe578211eMikhail Naganov 24072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setDevice(const DeviceAddress& address) { 24110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setDevice(address); 24210548295023bee99108e418499aff09fe578211eMikhail Naganov} 24310548295023bee99108e418499aff09fe578211eMikhail Naganov 24472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setConnectedState(const DeviceAddress& address, 24572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard bool connected) { 24610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setConnectedState(address, connected); 24710548295023bee99108e418499aff09fe578211eMikhail Naganov} 24810548295023bee99108e418499aff09fe578211eMikhail Naganov 24972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) { 25010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setHwAvSync(hwAvSync); 25110548295023bee99108e418499aff09fe578211eMikhail Naganov} 25210548295023bee99108e418499aff09fe578211eMikhail Naganov 25372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getParameters(const hidl_vec<hidl_string>& keys, 25472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard getParameters_cb _hidl_cb) { 25510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getParameters(keys, _hidl_cb); 25610548295023bee99108e418499aff09fe578211eMikhail Naganov} 25710548295023bee99108e418499aff09fe578211eMikhail Naganov 25872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setParameters( 25972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard const hidl_vec<ParameterValue>& parameters) { 26010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setParameters(parameters); 26110548295023bee99108e418499aff09fe578211eMikhail Naganov} 26210548295023bee99108e418499aff09fe578211eMikhail Naganov 26372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::debugDump(const hidl_handle& fd) { 26410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->debugDump(fd); 26510548295023bee99108e418499aff09fe578211eMikhail Naganov} 26610548295023bee99108e418499aff09fe578211eMikhail Naganov 26772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::close() { 268b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mIsClosed) return Result::INVALID_STATE; 269b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mIsClosed = true; 270b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mWriteThread.get()) { 271b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStopWriteThread.store(true, std::memory_order_release); 272b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 273b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mEfGroup) { 274b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); 275b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 276b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Result::OK; 277b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 278b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 27910548295023bee99108e418499aff09fe578211eMikhail Naganov// Methods from ::android::hardware::audio::V2_0::IStreamOut follow. 28072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint32_t> StreamOut::getLatency() { 28110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->get_latency(mStream); 28210548295023bee99108e418499aff09fe578211eMikhail Naganov} 28310548295023bee99108e418499aff09fe578211eMikhail Naganov 28472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setVolume(float left, float right) { 28510548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 28610548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->set_volume != NULL) { 2877deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent retval = Stream::analyzeStatus( 28872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard "set_volume", mStream->set_volume(mStream, left, right)); 28910548295023bee99108e418499aff09fe578211eMikhail Naganov } 29010548295023bee99108e418499aff09fe578211eMikhail Naganov return retval; 29110548295023bee99108e418499aff09fe578211eMikhail Naganov} 29210548295023bee99108e418499aff09fe578211eMikhail Naganov 29372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::prepareForWriting(uint32_t frameSize, 29472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard uint32_t framesCount, 29572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard prepareForWriting_cb _hidl_cb) { 296b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status_t status; 29772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ThreadInfo threadInfo = {0, 0}; 298b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create message queues. 299b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mDataMQ) { 300b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("the client attempts to call prepareForWriting twice"); 30172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard _hidl_cb(Result::INVALID_STATE, CommandMQ::Descriptor(), 30272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); 303b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 304b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 305a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1)); 306b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard 307b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard if (frameSize > std::numeric_limits<size_t>::max() / framesCount) { 30872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ALOGE("Requested buffer is too big, %d*%d can not fit in size_t", 30972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard frameSize, framesCount); 31072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard _hidl_cb(Result::INVALID_ARGUMENTS, CommandMQ::Descriptor(), 31172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); 312b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard return Void(); 313b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard } 31472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard std::unique_ptr<DataMQ> tempDataMQ( 31572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard new DataMQ(frameSize * framesCount, true /* EventFlag */)); 316b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard 317b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1)); 31872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || 31972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard !tempStatusMQ->isValid()) { 320a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid"); 321b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid"); 322b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid"); 32372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard _hidl_cb(Result::INVALID_ARGUMENTS, CommandMQ::Descriptor(), 32472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); 325b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 326b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 32740343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard EventFlag* tempRawEfGroup{}; 32872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), 32972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard &tempRawEfGroup); 33072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup( 33172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); }); 33240343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard if (status != OK || !tempElfGroup) { 333b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("failed creating event flag for data MQ: %s", strerror(-status)); 33472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard _hidl_cb(Result::INVALID_ARGUMENTS, CommandMQ::Descriptor(), 33572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); 336b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 337b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 338b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 339b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create and launch the thread. 34067d550888a021633cc33cb284bb0658b008887c6Kevin Rocard auto tempWriteThread = std::make_unique<WriteThread>( 34172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard &mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(), 34272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard tempStatusMQ.get(), tempElfGroup.get()); 34367d550888a021633cc33cb284bb0658b008887c6Kevin Rocard if (!tempWriteThread->init()) { 34472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard _hidl_cb(Result::INVALID_ARGUMENTS, CommandMQ::Descriptor(), 34572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); 34667d550888a021633cc33cb284bb0658b008887c6Kevin Rocard return Void(); 34767d550888a021633cc33cb284bb0658b008887c6Kevin Rocard } 34867d550888a021633cc33cb284bb0658b008887c6Kevin Rocard status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO); 349b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (status != OK) { 350b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGW("failed to start writer thread: %s", strerror(-status)); 35172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard _hidl_cb(Result::INVALID_ARGUMENTS, CommandMQ::Descriptor(), 35272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); 353b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 35410548295023bee99108e418499aff09fe578211eMikhail Naganov } 355b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 356a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mCommandMQ = std::move(tempCommandMQ); 357b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mDataMQ = std::move(tempDataMQ); 358b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStatusMQ = std::move(tempStatusMQ); 35967d550888a021633cc33cb284bb0658b008887c6Kevin Rocard mWriteThread = tempWriteThread.release(); 36040343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard mEfGroup = tempElfGroup.release(); 361a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov threadInfo.pid = getpid(); 362a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov threadInfo.tid = mWriteThread->getTid(); 36372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), 36472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard *mStatusMQ->getDesc(), threadInfo); 36510548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 36610548295023bee99108e418499aff09fe578211eMikhail Naganov} 36710548295023bee99108e418499aff09fe578211eMikhail Naganov 36872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { 36910548295023bee99108e418499aff09fe578211eMikhail Naganov uint32_t halDspFrames; 3707deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent Result retval = Stream::analyzeStatus( 37172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard "get_render_position", 37272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream->get_render_position(mStream, &halDspFrames)); 37310548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, halDspFrames); 37410548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 37510548295023bee99108e418499aff09fe578211eMikhail Naganov} 37610548295023bee99108e418499aff09fe578211eMikhail Naganov 37772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getNextWriteTimestamp( 37872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard getNextWriteTimestamp_cb _hidl_cb) { 37910548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 38010548295023bee99108e418499aff09fe578211eMikhail Naganov int64_t timestampUs = 0; 38110548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->get_next_write_timestamp != NULL) { 3827deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent retval = Stream::analyzeStatus( 38372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard "get_next_write_timestamp", 38472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream->get_next_write_timestamp(mStream, ×tampUs)); 38510548295023bee99108e418499aff09fe578211eMikhail Naganov } 38610548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, timestampUs); 38710548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 38810548295023bee99108e418499aff09fe578211eMikhail Naganov} 38910548295023bee99108e418499aff09fe578211eMikhail Naganov 39072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { 39110548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 39210548295023bee99108e418499aff09fe578211eMikhail Naganov int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); 39310548295023bee99108e418499aff09fe578211eMikhail Naganov if (result == 0) { 39410548295023bee99108e418499aff09fe578211eMikhail Naganov mCallback = callback; 39510548295023bee99108e418499aff09fe578211eMikhail Naganov } 3967deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return Stream::analyzeStatus("set_callback", result); 39710548295023bee99108e418499aff09fe578211eMikhail Naganov} 39810548295023bee99108e418499aff09fe578211eMikhail Naganov 39972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::clearCallback() { 4006e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 4016e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov mCallback.clear(); 4026e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov return Result::OK; 4036e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov} 4046e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov 40510548295023bee99108e418499aff09fe578211eMikhail Naganov// static 40672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocardint StreamOut::asyncCallback(stream_callback_event_t event, void*, 40772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard void* cookie) { 40810548295023bee99108e418499aff09fe578211eMikhail Naganov wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie)); 40910548295023bee99108e418499aff09fe578211eMikhail Naganov sp<StreamOut> self = weakSelf.promote(); 4106e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov if (self == nullptr || self->mCallback == nullptr) return 0; 41110548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGV("asyncCallback() event %d", event); 41210548295023bee99108e418499aff09fe578211eMikhail Naganov switch (event) { 41310548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_WRITE_READY: 4146e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov self->mCallback->onWriteReady(); 41510548295023bee99108e418499aff09fe578211eMikhail Naganov break; 41610548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_DRAIN_READY: 4176e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov self->mCallback->onDrainReady(); 41810548295023bee99108e418499aff09fe578211eMikhail Naganov break; 41910548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_ERROR: 4206e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov self->mCallback->onError(); 42110548295023bee99108e418499aff09fe578211eMikhail Naganov break; 42210548295023bee99108e418499aff09fe578211eMikhail Naganov default: 42310548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGW("asyncCallback() unknown event %d", event); 42410548295023bee99108e418499aff09fe578211eMikhail Naganov break; 42510548295023bee99108e418499aff09fe578211eMikhail Naganov } 42610548295023bee99108e418499aff09fe578211eMikhail Naganov return 0; 42710548295023bee99108e418499aff09fe578211eMikhail Naganov} 42810548295023bee99108e418499aff09fe578211eMikhail Naganov 42972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::supportsPauseAndResume( 43072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard supportsPauseAndResume_cb _hidl_cb) { 43110548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(mStream->pause != NULL, mStream->resume != NULL); 43210548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 43310548295023bee99108e418499aff09fe578211eMikhail Naganov} 43410548295023bee99108e418499aff09fe578211eMikhail Naganov 43572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::pause() { 43672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard return mStream->pause != NULL 43772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ? Stream::analyzeStatus("pause", mStream->pause(mStream)) 43872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Result::NOT_SUPPORTED; 43910548295023bee99108e418499aff09fe578211eMikhail Naganov} 44010548295023bee99108e418499aff09fe578211eMikhail Naganov 44172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::resume() { 44272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard return mStream->resume != NULL 44372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ? Stream::analyzeStatus("resume", mStream->resume(mStream)) 44472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Result::NOT_SUPPORTED; 44510548295023bee99108e418499aff09fe578211eMikhail Naganov} 44610548295023bee99108e418499aff09fe578211eMikhail Naganov 44772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<bool> StreamOut::supportsDrain() { 44810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->drain != NULL; 44910548295023bee99108e418499aff09fe578211eMikhail Naganov} 45010548295023bee99108e418499aff09fe578211eMikhail Naganov 45172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::drain(AudioDrain type) { 45272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard return mStream->drain != NULL 45372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ? Stream::analyzeStatus( 45472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard "drain", 45572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream->drain(mStream, 45672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard static_cast<audio_drain_type_t>(type))) 45772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Result::NOT_SUPPORTED; 45810548295023bee99108e418499aff09fe578211eMikhail Naganov} 45910548295023bee99108e418499aff09fe578211eMikhail Naganov 46072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::flush() { 46172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard return mStream->flush != NULL 46272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ? Stream::analyzeStatus("flush", mStream->flush(mStream)) 46372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Result::NOT_SUPPORTED; 46410548295023bee99108e418499aff09fe578211eMikhail Naganov} 46510548295023bee99108e418499aff09fe578211eMikhail Naganov 466ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov// static 46772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardResult StreamOut::getPresentationPositionImpl(audio_stream_out_t* stream, 46872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard uint64_t* frames, 46972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard TimeSpec* timeStamp) { 47010548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 471ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (stream->get_presentation_position == NULL) return retval; 472ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov struct timespec halTimeStamp; 473ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov retval = Stream::analyzeStatus( 47472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard "get_presentation_position", 47572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard stream->get_presentation_position(stream, frames, &halTimeStamp), 47672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // Don't logspam on EINVAL--it's normal for get_presentation_position 47772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // to return it sometimes. EAGAIN may be returned by A2DP audio HAL 47872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // implementation. 47972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard EINVAL, EAGAIN); 480ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (retval == Result::OK) { 481ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvSec = halTimeStamp.tv_sec; 482ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvNSec = halTimeStamp.tv_nsec; 483ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov } 484ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov return retval; 485ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov} 486ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov 48772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getPresentationPosition( 48872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard getPresentationPosition_cb _hidl_cb) { 48910548295023bee99108e418499aff09fe578211eMikhail Naganov uint64_t frames = 0; 49072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard TimeSpec timeStamp = {0, 0}; 491ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp); 49210548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, frames, timeStamp); 49310548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 49410548295023bee99108e418499aff09fe578211eMikhail Naganov} 49510548295023bee99108e418499aff09fe578211eMikhail Naganov 4967deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::start() { 4977deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->start(); 4987deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 4997deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 5007deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::stop() { 5017deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->stop(); 5027deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5037deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 50472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, 50572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard createMmapBuffer_cb _hidl_cb) { 5067deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->createMmapBuffer( 50772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb); 5087deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5097deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 5107deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) { 5117deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->getMmapPosition(_hidl_cb); 5127deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5137deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 51410548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace implementation 51510548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace V2_0 51610548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace audio 51710548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace hardware 51810548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace android 519