StreamOut.impl.h revision 82cb03632c15976838407c231fd85804de9bf84c
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" 284c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard#include "Util.h" 2910548295023bee99108e418499aff09fe578211eMikhail Naganov 3010548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace android { 3110548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace hardware { 3210548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace audio { 3310548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace V2_0 { 3410548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace implementation { 3510548295023bee99108e418499aff09fe578211eMikhail Naganov 36a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganovusing ::android::hardware::audio::common::V2_0::ThreadInfo; 37a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov 38b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovnamespace { 39b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 40b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovclass WriteThread : public Thread { 4172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard public: 42b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // WriteThread's lifespan never exceeds StreamOut's lifespan. 4372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard WriteThread(std::atomic<bool>* stop, audio_stream_out_t* stream, 4472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard StreamOut::CommandMQ* commandMQ, StreamOut::DataMQ* dataMQ, 4572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard StreamOut::StatusMQ* statusMQ, EventFlag* efGroup) 4672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Thread(false /*canCallJava*/), 4772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStop(stop), 4872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream(stream), 4972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mCommandMQ(commandMQ), 5072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mDataMQ(dataMQ), 5172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStatusMQ(statusMQ), 5272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mEfGroup(efGroup), 5372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mBuffer(nullptr) {} 5467d550888a021633cc33cb284bb0658b008887c6Kevin Rocard bool init() { 5572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]); 5667d550888a021633cc33cb284bb0658b008887c6Kevin Rocard return mBuffer != nullptr; 57b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 58b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov virtual ~WriteThread() {} 59b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 6072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard private: 61b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::atomic<bool>* mStop; 62b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov audio_stream_out_t* mStream; 63a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov StreamOut::CommandMQ* mCommandMQ; 64b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::DataMQ* mDataMQ; 65b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::StatusMQ* mStatusMQ; 66b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov EventFlag* mEfGroup; 67b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<uint8_t[]> mBuffer; 68a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov IStreamOut::WriteStatus mStatus; 69b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 70b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov bool threadLoop() override; 71a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 72a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doGetLatency(); 73a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doGetPresentationPosition(); 74a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doWrite(); 75b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov}; 76b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 77a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doWrite() { 78a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov const size_t availToRead = mDataMQ->availableToRead(); 79a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::OK; 80a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.written = 0; 81a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (mDataMQ->read(&mBuffer[0], availToRead)) { 82a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead); 83a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (writeResult >= 0) { 84a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.written = writeResult; 85a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } else { 86a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Stream::analyzeStatus("write", writeResult); 87a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 88a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 89a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 90a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 91a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doGetPresentationPosition() { 9282cb03632c15976838407c231fd85804de9bf84cKevin Rocard mStatus.retval = 9382cb03632c15976838407c231fd85804de9bf84cKevin Rocard StreamOut::getPresentationPositionImpl(mStream, &mStatus.reply.presentationPosition.frames, 9482cb03632c15976838407c231fd85804de9bf84cKevin Rocard &mStatus.reply.presentationPosition.timeStamp); 95a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 96a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 97a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doGetLatency() { 98a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::OK; 99a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.latencyMs = mStream->get_latency(mStream); 100a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 101a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 102b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovbool WriteThread::threadLoop() { 10372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // This implementation doesn't return control back to the Thread until it 10472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // decides to stop, 105b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // as the Thread uses mutexes, and this can lead to priority inversion. 10672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) { 107b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov uint32_t efState = 0; 10882cb03632c15976838407c231fd85804de9bf84cKevin Rocard mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); 10982cb03632c15976838407c231fd85804de9bf84cKevin Rocard if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) { 110b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov continue; // Nothing to do. 111b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 112a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (!mCommandMQ->read(&mStatus.replyTo)) { 113a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov continue; // Nothing to do. 114a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 115a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov switch (mStatus.replyTo) { 116a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::WRITE: 117a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doWrite(); 118a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 119a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION: 120a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doGetPresentationPosition(); 121a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 122a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::GET_LATENCY: 123a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doGetLatency(); 124a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 125a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov default: 126a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE("Unknown write thread command code %d", mStatus.replyTo); 127a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::NOT_SUPPORTED; 128a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 129b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 130a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (!mStatusMQ->write(&mStatus)) { 131a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE("status message queue write failed"); 132b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 133b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); 134b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 135b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 136b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return false; 137b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 138b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 139b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} // namespace 140b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 141936279e1ffe6bf7e842c46f9a94d98a48dce6754Mikhail NaganovStreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream) 14272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : mIsClosed(false), 14372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mDevice(device), 14472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream(stream), 14572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStreamCommon(new Stream(&stream->common)), 14672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)), 14772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mEfGroup(nullptr), 14872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStopWriteThread(false) {} 14910548295023bee99108e418499aff09fe578211eMikhail Naganov 15010548295023bee99108e418499aff09fe578211eMikhail NaganovStreamOut::~StreamOut() { 151b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ATRACE_CALL(); 152b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov close(); 153b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov if (mWriteThread.get()) { 154b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ATRACE_NAME("mWriteThread->join"); 155b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov status_t status = mWriteThread->join(); 156b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ALOGE_IF(status, "write thread exit error: %s", strerror(-status)); 157b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov } 158b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov if (mEfGroup) { 159b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov status_t status = EventFlag::deleteEventFlag(&mEfGroup); 16082cb03632c15976838407c231fd85804de9bf84cKevin Rocard ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status)); 161b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov } 162b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov mCallback.clear(); 163936279e1ffe6bf7e842c46f9a94d98a48dce6754Mikhail Naganov mDevice->closeOutputStream(mStream); 164718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // Closing the output stream in the HAL waits for the callback to finish, 165718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // and joins the callback thread. Thus is it guaranteed that the callback 166718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // thread will not be accessing our object anymore. 16710548295023bee99108e418499aff09fe578211eMikhail Naganov mStream = nullptr; 16810548295023bee99108e418499aff09fe578211eMikhail Naganov} 16910548295023bee99108e418499aff09fe578211eMikhail Naganov 17010548295023bee99108e418499aff09fe578211eMikhail Naganov// Methods from ::android::hardware::audio::V2_0::IStream follow. 17172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getFrameSize() { 17210548295023bee99108e418499aff09fe578211eMikhail Naganov return audio_stream_out_frame_size(mStream); 17310548295023bee99108e418499aff09fe578211eMikhail Naganov} 17410548295023bee99108e418499aff09fe578211eMikhail Naganov 17572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getFrameCount() { 17610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFrameCount(); 17710548295023bee99108e418499aff09fe578211eMikhail Naganov} 17810548295023bee99108e418499aff09fe578211eMikhail Naganov 17972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getBufferSize() { 18010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getBufferSize(); 18110548295023bee99108e418499aff09fe578211eMikhail Naganov} 18210548295023bee99108e418499aff09fe578211eMikhail Naganov 18372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint32_t> StreamOut::getSampleRate() { 18410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSampleRate(); 18510548295023bee99108e418499aff09fe578211eMikhail Naganov} 18610548295023bee99108e418499aff09fe578211eMikhail Naganov 18782cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::getSupportedSampleRates(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 19982cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { 20010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedChannelMasks(_hidl_cb); 20110548295023bee99108e418499aff09fe578211eMikhail Naganov} 20210548295023bee99108e418499aff09fe578211eMikhail Naganov 20372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setChannelMask(AudioChannelMask mask) { 20410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setChannelMask(mask); 20510548295023bee99108e418499aff09fe578211eMikhail Naganov} 20610548295023bee99108e418499aff09fe578211eMikhail Naganov 20772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<AudioFormat> StreamOut::getFormat() { 20810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFormat(); 20910548295023bee99108e418499aff09fe578211eMikhail Naganov} 21010548295023bee99108e418499aff09fe578211eMikhail Naganov 21172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { 21210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedFormats(_hidl_cb); 21310548295023bee99108e418499aff09fe578211eMikhail Naganov} 21410548295023bee99108e418499aff09fe578211eMikhail Naganov 21572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setFormat(AudioFormat format) { 21610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setFormat(format); 21710548295023bee99108e418499aff09fe578211eMikhail Naganov} 21810548295023bee99108e418499aff09fe578211eMikhail Naganov 21972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) { 22010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getAudioProperties(_hidl_cb); 22110548295023bee99108e418499aff09fe578211eMikhail Naganov} 22210548295023bee99108e418499aff09fe578211eMikhail Naganov 22372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::addEffect(uint64_t effectId) { 22410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->addEffect(effectId); 22510548295023bee99108e418499aff09fe578211eMikhail Naganov} 22610548295023bee99108e418499aff09fe578211eMikhail Naganov 22772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::removeEffect(uint64_t effectId) { 22810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->removeEffect(effectId); 22910548295023bee99108e418499aff09fe578211eMikhail Naganov} 23010548295023bee99108e418499aff09fe578211eMikhail Naganov 23172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::standby() { 23210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->standby(); 23310548295023bee99108e418499aff09fe578211eMikhail Naganov} 23410548295023bee99108e418499aff09fe578211eMikhail Naganov 23572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<AudioDevice> StreamOut::getDevice() { 23610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getDevice(); 23710548295023bee99108e418499aff09fe578211eMikhail Naganov} 23810548295023bee99108e418499aff09fe578211eMikhail Naganov 23972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setDevice(const DeviceAddress& address) { 24010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setDevice(address); 24110548295023bee99108e418499aff09fe578211eMikhail Naganov} 24210548295023bee99108e418499aff09fe578211eMikhail Naganov 24382cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) { 24410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setConnectedState(address, connected); 24510548295023bee99108e418499aff09fe578211eMikhail Naganov} 24610548295023bee99108e418499aff09fe578211eMikhail Naganov 24772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) { 24810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setHwAvSync(hwAvSync); 24910548295023bee99108e418499aff09fe578211eMikhail Naganov} 25010548295023bee99108e418499aff09fe578211eMikhail Naganov 25172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getParameters(const hidl_vec<hidl_string>& keys, 25272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard getParameters_cb _hidl_cb) { 25310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getParameters(keys, _hidl_cb); 25410548295023bee99108e418499aff09fe578211eMikhail Naganov} 25510548295023bee99108e418499aff09fe578211eMikhail Naganov 25682cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) { 25710548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setParameters(parameters); 25810548295023bee99108e418499aff09fe578211eMikhail Naganov} 25910548295023bee99108e418499aff09fe578211eMikhail Naganov 26072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::debugDump(const hidl_handle& fd) { 26110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->debugDump(fd); 26210548295023bee99108e418499aff09fe578211eMikhail Naganov} 26310548295023bee99108e418499aff09fe578211eMikhail Naganov 26472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::close() { 265b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mIsClosed) return Result::INVALID_STATE; 266b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mIsClosed = true; 267b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mWriteThread.get()) { 268b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStopWriteThread.store(true, std::memory_order_release); 269b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 270b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mEfGroup) { 271b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); 272b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 273b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Result::OK; 274b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 275b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 27610548295023bee99108e418499aff09fe578211eMikhail Naganov// Methods from ::android::hardware::audio::V2_0::IStreamOut follow. 27772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint32_t> StreamOut::getLatency() { 27810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->get_latency(mStream); 27910548295023bee99108e418499aff09fe578211eMikhail Naganov} 28010548295023bee99108e418499aff09fe578211eMikhail Naganov 28172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setVolume(float left, float right) { 2824c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard if (mStream->set_volume == NULL) { 2834c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard return Result::NOT_SUPPORTED; 28410548295023bee99108e418499aff09fe578211eMikhail Naganov } 2854c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard if (!isGainNormalized(left)) { 28682cb03632c15976838407c231fd85804de9bf84cKevin Rocard ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left, right); 2874c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard return Result::INVALID_ARGUMENTS; 2884c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard } 28982cb03632c15976838407c231fd85804de9bf84cKevin Rocard return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right)); 29010548295023bee99108e418499aff09fe578211eMikhail Naganov} 29110548295023bee99108e418499aff09fe578211eMikhail Naganov 29282cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount, 29372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard prepareForWriting_cb _hidl_cb) { 294b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status_t status; 29572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ThreadInfo threadInfo = {0, 0}; 296c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard 297c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard // Wrap the _hidl_cb to return an error 298b38c1aebc1e696b7bc8b5ec713388079cb677d25Chih-Hung Hsieh auto sendError = [&threadInfo, &_hidl_cb](Result result) { 29982cb03632c15976838407c231fd85804de9bf84cKevin Rocard _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), 30082cb03632c15976838407c231fd85804de9bf84cKevin Rocard threadInfo); 301c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard 302c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard }; 303c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard 304b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create message queues. 305b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mDataMQ) { 306b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("the client attempts to call prepareForWriting twice"); 307c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_STATE); 308b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 309b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 310a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1)); 311b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard 312195205b323b7d93cf4d477445469759b27371f45Kevin Rocard // Check frameSize and framesCount 313195205b323b7d93cf4d477445469759b27371f45Kevin Rocard if (frameSize == 0 || framesCount == 0) { 31482cb03632c15976838407c231fd85804de9bf84cKevin Rocard ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize, framesCount); 315195205b323b7d93cf4d477445469759b27371f45Kevin Rocard sendError(Result::INVALID_ARGUMENTS); 316195205b323b7d93cf4d477445469759b27371f45Kevin Rocard return Void(); 317195205b323b7d93cf4d477445469759b27371f45Kevin Rocard } 31846cba442d25e16cce4d5f009f4700a88d53636b1Kevin Rocard if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) { 31946cba442d25e16cce4d5f009f4700a88d53636b1Kevin Rocard ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount, 32046cba442d25e16cce4d5f009f4700a88d53636b1Kevin Rocard Stream::MAX_BUFFER_SIZE); 321195205b323b7d93cf4d477445469759b27371f45Kevin Rocard sendError(Result::INVALID_ARGUMENTS); 322b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard return Void(); 323b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard } 32482cb03632c15976838407c231fd85804de9bf84cKevin Rocard std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */)); 325b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard 326b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1)); 32782cb03632c15976838407c231fd85804de9bf84cKevin Rocard if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) { 328a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid"); 329b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid"); 330b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid"); 331c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 332b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 333b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 33440343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard EventFlag* tempRawEfGroup{}; 33582cb03632c15976838407c231fd85804de9bf84cKevin Rocard status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup); 33672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup( 33772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); }); 33840343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard if (status != OK || !tempElfGroup) { 339b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("failed creating event flag for data MQ: %s", strerror(-status)); 340c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 341b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 342b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 343b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 344b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create and launch the thread. 34582cb03632c15976838407c231fd85804de9bf84cKevin Rocard auto tempWriteThread = 34682cb03632c15976838407c231fd85804de9bf84cKevin Rocard std::make_unique<WriteThread>(&mStopWriteThread, mStream, tempCommandMQ.get(), 34782cb03632c15976838407c231fd85804de9bf84cKevin Rocard tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get()); 34867d550888a021633cc33cb284bb0658b008887c6Kevin Rocard if (!tempWriteThread->init()) { 349c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard ALOGW("failed to start writer thread: %s", strerror(-status)); 350c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 35167d550888a021633cc33cb284bb0658b008887c6Kevin Rocard return Void(); 35267d550888a021633cc33cb284bb0658b008887c6Kevin Rocard } 35367d550888a021633cc33cb284bb0658b008887c6Kevin Rocard status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO); 354b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (status != OK) { 355b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGW("failed to start writer thread: %s", strerror(-status)); 356c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 357b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 35810548295023bee99108e418499aff09fe578211eMikhail Naganov } 359b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 360a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mCommandMQ = std::move(tempCommandMQ); 361b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mDataMQ = std::move(tempDataMQ); 362b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStatusMQ = std::move(tempStatusMQ); 36367d550888a021633cc33cb284bb0658b008887c6Kevin Rocard mWriteThread = tempWriteThread.release(); 36440343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard mEfGroup = tempElfGroup.release(); 365a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov threadInfo.pid = getpid(); 366a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov threadInfo.tid = mWriteThread->getTid(); 36782cb03632c15976838407c231fd85804de9bf84cKevin Rocard _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(), 36882cb03632c15976838407c231fd85804de9bf84cKevin Rocard threadInfo); 36910548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 37010548295023bee99108e418499aff09fe578211eMikhail Naganov} 37110548295023bee99108e418499aff09fe578211eMikhail Naganov 37272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { 37310548295023bee99108e418499aff09fe578211eMikhail Naganov uint32_t halDspFrames; 37482cb03632c15976838407c231fd85804de9bf84cKevin Rocard Result retval = Stream::analyzeStatus("get_render_position", 37582cb03632c15976838407c231fd85804de9bf84cKevin Rocard mStream->get_render_position(mStream, &halDspFrames)); 37610548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, halDspFrames); 37710548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 37810548295023bee99108e418499aff09fe578211eMikhail Naganov} 37910548295023bee99108e418499aff09fe578211eMikhail Naganov 38082cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) { 38110548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 38210548295023bee99108e418499aff09fe578211eMikhail Naganov int64_t timestampUs = 0; 38310548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->get_next_write_timestamp != NULL) { 38482cb03632c15976838407c231fd85804de9bf84cKevin Rocard retval = Stream::analyzeStatus("get_next_write_timestamp", 38582cb03632c15976838407c231fd85804de9bf84cKevin Rocard mStream->get_next_write_timestamp(mStream, ×tampUs)); 38610548295023bee99108e418499aff09fe578211eMikhail Naganov } 38710548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, timestampUs); 38810548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 38910548295023bee99108e418499aff09fe578211eMikhail Naganov} 39010548295023bee99108e418499aff09fe578211eMikhail Naganov 39172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { 39210548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 393718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // Safe to pass 'this' because it is guaranteed that the callback thread 394718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // is joined prior to exit from StreamOut's destructor. 39510548295023bee99108e418499aff09fe578211eMikhail Naganov int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); 39610548295023bee99108e418499aff09fe578211eMikhail Naganov if (result == 0) { 39710548295023bee99108e418499aff09fe578211eMikhail Naganov mCallback = callback; 39810548295023bee99108e418499aff09fe578211eMikhail Naganov } 3997deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return Stream::analyzeStatus("set_callback", result); 40010548295023bee99108e418499aff09fe578211eMikhail Naganov} 40110548295023bee99108e418499aff09fe578211eMikhail Naganov 40272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::clearCallback() { 4036e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 4046e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov mCallback.clear(); 4056e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov return Result::OK; 4066e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov} 4076e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov 40810548295023bee99108e418499aff09fe578211eMikhail Naganov// static 40982cb03632c15976838407c231fd85804de9bf84cKevin Rocardint StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie) { 410718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // It is guaranteed that the callback thread is joined prior 411718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // to exiting from StreamOut's destructor. Must *not* use sp<StreamOut> 412718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // here because it can make this code the last owner of StreamOut, 413718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // and an attempt to run the destructor on the callback thread 414718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // will cause a deadlock in the legacy HAL code. 41582cb03632c15976838407c231fd85804de9bf84cKevin Rocard StreamOut* self = reinterpret_cast<StreamOut*>(cookie); 416718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // It's correct to hold an sp<> to callback because the reference 417718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // in the StreamOut instance can be cleared in the meantime. There is 418718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // no difference on which thread to run IStreamOutCallback's destructor. 419718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov sp<IStreamOutCallback> callback = self->mCallback; 420718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov if (callback.get() == nullptr) return 0; 42110548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGV("asyncCallback() event %d", event); 42210548295023bee99108e418499aff09fe578211eMikhail Naganov switch (event) { 42310548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_WRITE_READY: 424718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov callback->onWriteReady(); 42510548295023bee99108e418499aff09fe578211eMikhail Naganov break; 42610548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_DRAIN_READY: 427718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov callback->onDrainReady(); 42810548295023bee99108e418499aff09fe578211eMikhail Naganov break; 42910548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_ERROR: 430718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov callback->onError(); 43110548295023bee99108e418499aff09fe578211eMikhail Naganov break; 43210548295023bee99108e418499aff09fe578211eMikhail Naganov default: 43310548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGW("asyncCallback() unknown event %d", event); 43410548295023bee99108e418499aff09fe578211eMikhail Naganov break; 43510548295023bee99108e418499aff09fe578211eMikhail Naganov } 43610548295023bee99108e418499aff09fe578211eMikhail Naganov return 0; 43710548295023bee99108e418499aff09fe578211eMikhail Naganov} 43810548295023bee99108e418499aff09fe578211eMikhail Naganov 43982cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) { 44010548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(mStream->pause != NULL, mStream->resume != NULL); 44110548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 44210548295023bee99108e418499aff09fe578211eMikhail Naganov} 44310548295023bee99108e418499aff09fe578211eMikhail Naganov 44472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::pause() { 44582cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStream->pause != NULL ? Stream::analyzeStatus("pause", mStream->pause(mStream)) 44682cb03632c15976838407c231fd85804de9bf84cKevin Rocard : Result::NOT_SUPPORTED; 44710548295023bee99108e418499aff09fe578211eMikhail Naganov} 44810548295023bee99108e418499aff09fe578211eMikhail Naganov 44972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::resume() { 45082cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStream->resume != NULL ? Stream::analyzeStatus("resume", mStream->resume(mStream)) 45182cb03632c15976838407c231fd85804de9bf84cKevin Rocard : Result::NOT_SUPPORTED; 45210548295023bee99108e418499aff09fe578211eMikhail Naganov} 45310548295023bee99108e418499aff09fe578211eMikhail Naganov 45472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<bool> StreamOut::supportsDrain() { 45510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->drain != NULL; 45610548295023bee99108e418499aff09fe578211eMikhail Naganov} 45710548295023bee99108e418499aff09fe578211eMikhail Naganov 45872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::drain(AudioDrain type) { 45972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard return mStream->drain != NULL 46072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ? Stream::analyzeStatus( 46182cb03632c15976838407c231fd85804de9bf84cKevin Rocard "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) 46272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Result::NOT_SUPPORTED; 46310548295023bee99108e418499aff09fe578211eMikhail Naganov} 46410548295023bee99108e418499aff09fe578211eMikhail Naganov 46572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::flush() { 46682cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStream->flush != NULL ? Stream::analyzeStatus("flush", mStream->flush(mStream)) 46782cb03632c15976838407c231fd85804de9bf84cKevin Rocard : Result::NOT_SUPPORTED; 46810548295023bee99108e418499aff09fe578211eMikhail Naganov} 46910548295023bee99108e418499aff09fe578211eMikhail Naganov 470ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov// static 47182cb03632c15976838407c231fd85804de9bf84cKevin RocardResult StreamOut::getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames, 47272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard TimeSpec* timeStamp) { 47396a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // Don't logspam on EINVAL--it's normal for get_presentation_position 47496a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // to return it sometimes. EAGAIN may be returned by A2DP audio HAL 47596a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // implementation. ENODATA can also be reported while the writer is 47696a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // continuously querying it, but the stream has been stopped. 47796a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA}; 47810548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 479ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (stream->get_presentation_position == NULL) return retval; 480ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov struct timespec halTimeStamp; 48196a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov retval = Stream::analyzeStatus("get_presentation_position", 48296a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov stream->get_presentation_position(stream, frames, &halTimeStamp), 48396a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov ignoredErrors); 484ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (retval == Result::OK) { 485ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvSec = halTimeStamp.tv_sec; 486ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvNSec = halTimeStamp.tv_nsec; 487ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov } 488ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov return retval; 489ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov} 490ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov 49182cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) { 49210548295023bee99108e418499aff09fe578211eMikhail Naganov uint64_t frames = 0; 49372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard TimeSpec timeStamp = {0, 0}; 494ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp); 49510548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, frames, timeStamp); 49610548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 49710548295023bee99108e418499aff09fe578211eMikhail Naganov} 49810548295023bee99108e418499aff09fe578211eMikhail Naganov 4997deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::start() { 5007deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->start(); 5017deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5027deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 5037deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::stop() { 5047deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->stop(); 5057deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5067deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 50782cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { 50882cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStreamMmap->createMmapBuffer(minSizeFrames, audio_stream_out_frame_size(mStream), 50982cb03632c15976838407c231fd85804de9bf84cKevin Rocard _hidl_cb); 5107deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5117deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 5127deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) { 5137deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->getMmapPosition(_hidl_cb); 5147deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5157deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 51610548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace implementation 51710548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace V2_0 51810548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace audio 51910548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace hardware 52010548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace android 521