StreamOut.impl.h revision ee901e3fd885709abc9b9e2b8e521022e27522d3
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 1910548295023bee99108e418499aff09fe578211eMikhail Naganov 20f9d303435d80161fabb16cdff3b8f2f75f362480Yifan Hong#include <android/log.h> 21b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov#include <hardware/audio.h> 22b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov#include <mediautils/SchedulingPolicyService.h> 2310548295023bee99108e418499aff09fe578211eMikhail Naganov 2410548295023bee99108e418499aff09fe578211eMikhail Naganov#include "StreamOut.h" 2510548295023bee99108e418499aff09fe578211eMikhail Naganov 2610548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace android { 2710548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace hardware { 2810548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace audio { 2910548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace V2_0 { 3010548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace implementation { 3110548295023bee99108e418499aff09fe578211eMikhail Naganov 32b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovnamespace { 33b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 34b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovclass WriteThread : public Thread { 35b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov public: 36b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // WriteThread's lifespan never exceeds StreamOut's lifespan. 37b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov WriteThread(std::atomic<bool>* stop, 38b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov audio_stream_out_t* stream, 39b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::DataMQ* dataMQ, 40b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::StatusMQ* statusMQ, 41b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov EventFlag* efGroup, 42b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ThreadPriority threadPriority) 43b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov : Thread(false /*canCallJava*/), 44b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStop(stop), 45b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStream(stream), 46b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mDataMQ(dataMQ), 47b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStatusMQ(statusMQ), 48b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup(efGroup), 49b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mThreadPriority(threadPriority), 50b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mBuffer(new uint8_t[dataMQ->getQuantumCount()]) { 51b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 52b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov virtual ~WriteThread() {} 53b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 54b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status_t readyToRun() override; 55b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 56b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov private: 57b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::atomic<bool>* mStop; 58b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov audio_stream_out_t* mStream; 59b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::DataMQ* mDataMQ; 60b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::StatusMQ* mStatusMQ; 61b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov EventFlag* mEfGroup; 62b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ThreadPriority mThreadPriority; 63b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<uint8_t[]> mBuffer; 64b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 65b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov bool threadLoop() override; 66b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov}; 67b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 68b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovstatus_t WriteThread::readyToRun() { 69b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mThreadPriority != ThreadPriority::NORMAL) { 70b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov int err = requestPriority( 71b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov getpid(), getTid(), static_cast<int>(mThreadPriority), true /*asynchronous*/); 72b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGW_IF(err, "failed to set priority %d for pid %d tid %d; error %d", 73b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov static_cast<int>(mThreadPriority), getpid(), getTid(), err); 74b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 75b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return OK; 76b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 77b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 78b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovbool WriteThread::threadLoop() { 79b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // This implementation doesn't return control back to the Thread until it decides to stop, 80b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // as the Thread uses mutexes, and this can lead to priority inversion. 81b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) { 82b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 83b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov uint32_t efState = 0; 84b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup->wait( 85b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC); 86b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) { 87b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov continue; // Nothing to do. 88b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 89b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 90b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov const size_t availToRead = mDataMQ->availableToRead(); 91ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov IStreamOut::WriteStatus status; 92ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov status.writeRetval = Result::OK; 93ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov status.written = 0; 94b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mDataMQ->read(&mBuffer[0], availToRead)) { 95b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead); 96b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (writeResult >= 0) { 97ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov status.written = writeResult; 98b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } else { 99ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov status.writeRetval = Stream::analyzeStatus("write", writeResult); 100b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 101b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 102ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov status.presentationPositionRetval = status.writeRetval == Result::OK ? 103ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov StreamOut::getPresentationPositionImpl(mStream, &status.frames, &status.timeStamp) : 104ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov Result::OK; 105b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (!mStatusMQ->write(&status)) { 106b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGW("status message queue write failed"); 107b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 108b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); 109b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 110b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 111b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return false; 112b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 113b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 114b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} // namespace 115b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 11610548295023bee99108e418499aff09fe578211eMikhail NaganovStreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream) 117b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov : mIsClosed(false), mDevice(device), mStream(stream), 1187deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent mStreamCommon(new Stream(&stream->common)), 119b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)), 120b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup(nullptr), mStopWriteThread(false) { 12110548295023bee99108e418499aff09fe578211eMikhail Naganov} 12210548295023bee99108e418499aff09fe578211eMikhail Naganov 12310548295023bee99108e418499aff09fe578211eMikhail NaganovStreamOut::~StreamOut() { 124b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov close(); 12510548295023bee99108e418499aff09fe578211eMikhail Naganov mStream = nullptr; 12610548295023bee99108e418499aff09fe578211eMikhail Naganov mDevice = nullptr; 12710548295023bee99108e418499aff09fe578211eMikhail Naganov} 12810548295023bee99108e418499aff09fe578211eMikhail Naganov 12910548295023bee99108e418499aff09fe578211eMikhail Naganov// Methods from ::android::hardware::audio::V2_0::IStream follow. 13010548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<uint64_t> StreamOut::getFrameSize() { 13110548295023bee99108e418499aff09fe578211eMikhail Naganov return audio_stream_out_frame_size(mStream); 13210548295023bee99108e418499aff09fe578211eMikhail Naganov} 13310548295023bee99108e418499aff09fe578211eMikhail Naganov 13410548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<uint64_t> StreamOut::getFrameCount() { 13510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFrameCount(); 13610548295023bee99108e418499aff09fe578211eMikhail Naganov} 13710548295023bee99108e418499aff09fe578211eMikhail Naganov 13810548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<uint64_t> StreamOut::getBufferSize() { 13910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getBufferSize(); 14010548295023bee99108e418499aff09fe578211eMikhail Naganov} 14110548295023bee99108e418499aff09fe578211eMikhail Naganov 14210548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<uint32_t> StreamOut::getSampleRate() { 14310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSampleRate(); 14410548295023bee99108e418499aff09fe578211eMikhail Naganov} 14510548295023bee99108e418499aff09fe578211eMikhail Naganov 14610548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { 14710548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedSampleRates(_hidl_cb); 14810548295023bee99108e418499aff09fe578211eMikhail Naganov} 14910548295023bee99108e418499aff09fe578211eMikhail Naganov 15010548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) { 15110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setSampleRate(sampleRateHz); 15210548295023bee99108e418499aff09fe578211eMikhail Naganov} 15310548295023bee99108e418499aff09fe578211eMikhail Naganov 15410548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<AudioChannelMask> StreamOut::getChannelMask() { 15510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getChannelMask(); 15610548295023bee99108e418499aff09fe578211eMikhail Naganov} 15710548295023bee99108e418499aff09fe578211eMikhail Naganov 15810548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { 15910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedChannelMasks(_hidl_cb); 16010548295023bee99108e418499aff09fe578211eMikhail Naganov} 16110548295023bee99108e418499aff09fe578211eMikhail Naganov 16210548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setChannelMask(AudioChannelMask mask) { 16310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setChannelMask(mask); 16410548295023bee99108e418499aff09fe578211eMikhail Naganov} 16510548295023bee99108e418499aff09fe578211eMikhail Naganov 16610548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<AudioFormat> StreamOut::getFormat() { 16710548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFormat(); 16810548295023bee99108e418499aff09fe578211eMikhail Naganov} 16910548295023bee99108e418499aff09fe578211eMikhail Naganov 17010548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { 17110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedFormats(_hidl_cb); 17210548295023bee99108e418499aff09fe578211eMikhail Naganov} 17310548295023bee99108e418499aff09fe578211eMikhail Naganov 17410548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setFormat(AudioFormat format) { 17510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setFormat(format); 17610548295023bee99108e418499aff09fe578211eMikhail Naganov} 17710548295023bee99108e418499aff09fe578211eMikhail Naganov 17810548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) { 17910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getAudioProperties(_hidl_cb); 18010548295023bee99108e418499aff09fe578211eMikhail Naganov} 18110548295023bee99108e418499aff09fe578211eMikhail Naganov 18210548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::addEffect(uint64_t effectId) { 18310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->addEffect(effectId); 18410548295023bee99108e418499aff09fe578211eMikhail Naganov} 18510548295023bee99108e418499aff09fe578211eMikhail Naganov 18610548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::removeEffect(uint64_t effectId) { 18710548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->removeEffect(effectId); 18810548295023bee99108e418499aff09fe578211eMikhail Naganov} 18910548295023bee99108e418499aff09fe578211eMikhail Naganov 19010548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::standby() { 19110548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->standby(); 19210548295023bee99108e418499aff09fe578211eMikhail Naganov} 19310548295023bee99108e418499aff09fe578211eMikhail Naganov 19410548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<AudioDevice> StreamOut::getDevice() { 19510548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getDevice(); 19610548295023bee99108e418499aff09fe578211eMikhail Naganov} 19710548295023bee99108e418499aff09fe578211eMikhail Naganov 19810548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setDevice(const DeviceAddress& address) { 19910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setDevice(address); 20010548295023bee99108e418499aff09fe578211eMikhail Naganov} 20110548295023bee99108e418499aff09fe578211eMikhail Naganov 20210548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) { 20310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setConnectedState(address, connected); 20410548295023bee99108e418499aff09fe578211eMikhail Naganov} 20510548295023bee99108e418499aff09fe578211eMikhail Naganov 20610548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) { 20710548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setHwAvSync(hwAvSync); 20810548295023bee99108e418499aff09fe578211eMikhail Naganov} 20910548295023bee99108e418499aff09fe578211eMikhail Naganov 21010548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::getParameters( 21110548295023bee99108e418499aff09fe578211eMikhail Naganov const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { 21210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getParameters(keys, _hidl_cb); 21310548295023bee99108e418499aff09fe578211eMikhail Naganov} 21410548295023bee99108e418499aff09fe578211eMikhail Naganov 21510548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) { 21610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setParameters(parameters); 21710548295023bee99108e418499aff09fe578211eMikhail Naganov} 21810548295023bee99108e418499aff09fe578211eMikhail Naganov 21970b9a15df00a42b319279d903bf5923564920e3bMartijn CoenenReturn<void> StreamOut::debugDump(const hidl_handle& fd) { 22010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->debugDump(fd); 22110548295023bee99108e418499aff09fe578211eMikhail Naganov} 22210548295023bee99108e418499aff09fe578211eMikhail Naganov 223b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail NaganovReturn<Result> StreamOut::close() { 224b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mIsClosed) return Result::INVALID_STATE; 225b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mIsClosed = true; 226b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mWriteThread.get()) { 227b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStopWriteThread.store(true, std::memory_order_release); 228b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status_t status = mWriteThread->requestExitAndWait(); 229b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(status, "write thread exit error: %s", strerror(-status)); 230b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 231b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mEfGroup) { 232b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status_t status = EventFlag::deleteEventFlag(&mEfGroup); 233b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status)); 234b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 235b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mCallback.clear(); 236b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mDevice->close_output_stream(mDevice, mStream); 237b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Result::OK; 238b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 239b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 24010548295023bee99108e418499aff09fe578211eMikhail Naganov// Methods from ::android::hardware::audio::V2_0::IStreamOut follow. 24110548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<uint32_t> StreamOut::getLatency() { 24210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->get_latency(mStream); 24310548295023bee99108e418499aff09fe578211eMikhail Naganov} 24410548295023bee99108e418499aff09fe578211eMikhail Naganov 24510548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setVolume(float left, float right) { 24610548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 24710548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->set_volume != NULL) { 2487deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent retval = Stream::analyzeStatus( 24910548295023bee99108e418499aff09fe578211eMikhail Naganov "set_volume", mStream->set_volume(mStream, left, right)); 25010548295023bee99108e418499aff09fe578211eMikhail Naganov } 25110548295023bee99108e418499aff09fe578211eMikhail Naganov return retval; 25210548295023bee99108e418499aff09fe578211eMikhail Naganov} 25310548295023bee99108e418499aff09fe578211eMikhail Naganov 254b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail NaganovReturn<void> StreamOut::prepareForWriting( 255b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority, 256b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov prepareForWriting_cb _hidl_cb) { 257b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status_t status; 258b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create message queues. 259b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mDataMQ) { 260b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("the client attempts to call prepareForWriting twice"); 261b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov _hidl_cb(Result::INVALID_STATE, 262b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>()); 263b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 264b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 265b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<DataMQ> tempDataMQ( 266b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov new DataMQ(frameSize * framesCount, true /* EventFlag */)); 267b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1)); 268b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (!tempDataMQ->isValid() || !tempStatusMQ->isValid()) { 269b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid"); 270b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid"); 271b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov _hidl_cb(Result::INVALID_ARGUMENTS, 272b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>()); 273b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 274b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 275b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // TODO: Remove event flag management once blocking MQ is implemented. b/33815422 276b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); 277b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (status != OK || !mEfGroup) { 278b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("failed creating event flag for data MQ: %s", strerror(-status)); 279b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov _hidl_cb(Result::INVALID_ARGUMENTS, 280b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>()); 281b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 282b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 283b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 284b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create and launch the thread. 285b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mWriteThread = new WriteThread( 286b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov &mStopWriteThread, 287b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStream, 288b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov tempDataMQ.get(), 289b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov tempStatusMQ.get(), 290b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup, 291b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov threadPriority); 292b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status = mWriteThread->run("writer", PRIORITY_URGENT_AUDIO); 293b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (status != OK) { 294b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGW("failed to start writer thread: %s", strerror(-status)); 295b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov _hidl_cb(Result::INVALID_ARGUMENTS, 296b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>()); 297b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 29810548295023bee99108e418499aff09fe578211eMikhail Naganov } 299b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 300b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mDataMQ = std::move(tempDataMQ); 301b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStatusMQ = std::move(tempStatusMQ); 302b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov _hidl_cb(Result::OK, *mDataMQ->getDesc(), *mStatusMQ->getDesc()); 30310548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 30410548295023bee99108e418499aff09fe578211eMikhail Naganov} 30510548295023bee99108e418499aff09fe578211eMikhail Naganov 30610548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { 30710548295023bee99108e418499aff09fe578211eMikhail Naganov uint32_t halDspFrames; 3087deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent Result retval = Stream::analyzeStatus( 30910548295023bee99108e418499aff09fe578211eMikhail Naganov "get_render_position", mStream->get_render_position(mStream, &halDspFrames)); 31010548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, halDspFrames); 31110548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 31210548295023bee99108e418499aff09fe578211eMikhail Naganov} 31310548295023bee99108e418499aff09fe578211eMikhail Naganov 31410548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) { 31510548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 31610548295023bee99108e418499aff09fe578211eMikhail Naganov int64_t timestampUs = 0; 31710548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->get_next_write_timestamp != NULL) { 3187deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent retval = Stream::analyzeStatus( 31910548295023bee99108e418499aff09fe578211eMikhail Naganov "get_next_write_timestamp", 32010548295023bee99108e418499aff09fe578211eMikhail Naganov mStream->get_next_write_timestamp(mStream, ×tampUs)); 32110548295023bee99108e418499aff09fe578211eMikhail Naganov } 32210548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, timestampUs); 32310548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 32410548295023bee99108e418499aff09fe578211eMikhail Naganov} 32510548295023bee99108e418499aff09fe578211eMikhail Naganov 32610548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { 32710548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 32810548295023bee99108e418499aff09fe578211eMikhail Naganov int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); 32910548295023bee99108e418499aff09fe578211eMikhail Naganov if (result == 0) { 33010548295023bee99108e418499aff09fe578211eMikhail Naganov mCallback = callback; 33110548295023bee99108e418499aff09fe578211eMikhail Naganov } 3327deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return Stream::analyzeStatus("set_callback", result); 33310548295023bee99108e418499aff09fe578211eMikhail Naganov} 33410548295023bee99108e418499aff09fe578211eMikhail Naganov 3356e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail NaganovReturn<Result> StreamOut::clearCallback() { 3366e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 3376e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov mCallback.clear(); 3386e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov return Result::OK; 3396e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov} 3406e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov 34110548295023bee99108e418499aff09fe578211eMikhail Naganov// static 34210548295023bee99108e418499aff09fe578211eMikhail Naganovint StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie) { 34310548295023bee99108e418499aff09fe578211eMikhail Naganov wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie)); 34410548295023bee99108e418499aff09fe578211eMikhail Naganov sp<StreamOut> self = weakSelf.promote(); 3456e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov if (self == nullptr || self->mCallback == nullptr) return 0; 34610548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGV("asyncCallback() event %d", event); 34710548295023bee99108e418499aff09fe578211eMikhail Naganov switch (event) { 34810548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_WRITE_READY: 3496e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov self->mCallback->onWriteReady(); 35010548295023bee99108e418499aff09fe578211eMikhail Naganov break; 35110548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_DRAIN_READY: 3526e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov self->mCallback->onDrainReady(); 35310548295023bee99108e418499aff09fe578211eMikhail Naganov break; 35410548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_ERROR: 3556e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov self->mCallback->onError(); 35610548295023bee99108e418499aff09fe578211eMikhail Naganov break; 35710548295023bee99108e418499aff09fe578211eMikhail Naganov default: 35810548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGW("asyncCallback() unknown event %d", event); 35910548295023bee99108e418499aff09fe578211eMikhail Naganov break; 36010548295023bee99108e418499aff09fe578211eMikhail Naganov } 36110548295023bee99108e418499aff09fe578211eMikhail Naganov return 0; 36210548295023bee99108e418499aff09fe578211eMikhail Naganov} 36310548295023bee99108e418499aff09fe578211eMikhail Naganov 36410548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) { 36510548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(mStream->pause != NULL, mStream->resume != NULL); 36610548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 36710548295023bee99108e418499aff09fe578211eMikhail Naganov} 36810548295023bee99108e418499aff09fe578211eMikhail Naganov 36910548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::pause() { 37010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->pause != NULL ? 3717deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent Stream::analyzeStatus("pause", mStream->pause(mStream)) : 37210548295023bee99108e418499aff09fe578211eMikhail Naganov Result::NOT_SUPPORTED; 37310548295023bee99108e418499aff09fe578211eMikhail Naganov} 37410548295023bee99108e418499aff09fe578211eMikhail Naganov 37510548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::resume() { 37610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->resume != NULL ? 3777deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent Stream::analyzeStatus("resume", mStream->resume(mStream)) : 37810548295023bee99108e418499aff09fe578211eMikhail Naganov Result::NOT_SUPPORTED; 37910548295023bee99108e418499aff09fe578211eMikhail Naganov} 38010548295023bee99108e418499aff09fe578211eMikhail Naganov 38110548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<bool> StreamOut::supportsDrain() { 38210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->drain != NULL; 38310548295023bee99108e418499aff09fe578211eMikhail Naganov} 38410548295023bee99108e418499aff09fe578211eMikhail Naganov 38510548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::drain(AudioDrain type) { 38610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->drain != NULL ? 3877deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent Stream::analyzeStatus( 38810548295023bee99108e418499aff09fe578211eMikhail Naganov "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) : 38910548295023bee99108e418499aff09fe578211eMikhail Naganov Result::NOT_SUPPORTED; 39010548295023bee99108e418499aff09fe578211eMikhail Naganov} 39110548295023bee99108e418499aff09fe578211eMikhail Naganov 39210548295023bee99108e418499aff09fe578211eMikhail NaganovReturn<Result> StreamOut::flush() { 39310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->flush != NULL ? 3947deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent Stream::analyzeStatus("flush", mStream->flush(mStream)) : 39510548295023bee99108e418499aff09fe578211eMikhail Naganov Result::NOT_SUPPORTED; 39610548295023bee99108e418499aff09fe578211eMikhail Naganov} 39710548295023bee99108e418499aff09fe578211eMikhail Naganov 398ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov// static 399ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail NaganovResult StreamOut::getPresentationPositionImpl( 400ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov audio_stream_out_t *stream, uint64_t *frames, TimeSpec *timeStamp) { 40110548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 402ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (stream->get_presentation_position == NULL) return retval; 403ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov struct timespec halTimeStamp; 404ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov retval = Stream::analyzeStatus( 405ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov "get_presentation_position", 406ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov stream->get_presentation_position(stream, frames, &halTimeStamp), 407ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov // Don't logspam on EINVAL--it's normal for get_presentation_position 408ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov // to return it sometimes. 409ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov EINVAL); 410ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (retval == Result::OK) { 411ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvSec = halTimeStamp.tv_sec; 412ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvNSec = halTimeStamp.tv_nsec; 413ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov } 414ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov return retval; 415ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov} 416ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov 417ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail NaganovReturn<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) { 41810548295023bee99108e418499aff09fe578211eMikhail Naganov uint64_t frames = 0; 41910548295023bee99108e418499aff09fe578211eMikhail Naganov TimeSpec timeStamp = { 0, 0 }; 420ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp); 42110548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, frames, timeStamp); 42210548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 42310548295023bee99108e418499aff09fe578211eMikhail Naganov} 42410548295023bee99108e418499aff09fe578211eMikhail Naganov 4257deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::start() { 4267deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->start(); 4277deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 4287deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 4297deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::stop() { 4307deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->stop(); 4317deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 4327deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 4337deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { 4347deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->createMmapBuffer( 4357deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb); 4367deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 4377deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 4387deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) { 4397deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->getMmapPosition(_hidl_cb); 4407deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 4417deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 44210548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace implementation 44310548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace V2_0 44410548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace audio 44510548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace hardware 44610548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace android 447