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 17e9e4e16564c2949960bf9dd3ab49c9dee2273f3cKevin Rocard#include <common/all-versions/IncludeGuard.h> 18e9e4e16564c2949960bf9dd3ab49c9dee2273f3cKevin Rocard 19685f0e36a1185b24f473f0382ba2175685dbcdf9Mikhail Naganov//#define LOG_NDEBUG 0 20b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov#define ATRACE_TAG ATRACE_TAG_AUDIO 2110548295023bee99108e418499aff09fe578211eMikhail Naganov 2267d550888a021633cc33cb284bb0658b008887c6Kevin Rocard#include <memory> 2367d550888a021633cc33cb284bb0658b008887c6Kevin Rocard 24f9d303435d80161fabb16cdff3b8f2f75f362480Yifan Hong#include <android/log.h> 25b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov#include <hardware/audio.h> 26b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov#include <utils/Trace.h> 2710548295023bee99108e418499aff09fe578211eMikhail Naganov 2810548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace android { 2910548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace hardware { 3010548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace audio { 31e9e4e16564c2949960bf9dd3ab49c9dee2273f3cKevin Rocardnamespace AUDIO_HAL_VERSION { 3210548295023bee99108e418499aff09fe578211eMikhail Naganovnamespace implementation { 3310548295023bee99108e418499aff09fe578211eMikhail Naganov 34e9e4e16564c2949960bf9dd3ab49c9dee2273f3cKevin Rocardusing ::android::hardware::audio::common::AUDIO_HAL_VERSION::ThreadInfo; 35a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov 36b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovnamespace { 37b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 38b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovclass WriteThread : public Thread { 3972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard public: 40b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // WriteThread's lifespan never exceeds StreamOut's lifespan. 4172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard WriteThread(std::atomic<bool>* stop, audio_stream_out_t* stream, 4272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard StreamOut::CommandMQ* commandMQ, StreamOut::DataMQ* dataMQ, 4372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard StreamOut::StatusMQ* statusMQ, EventFlag* efGroup) 4472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Thread(false /*canCallJava*/), 4572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStop(stop), 4672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream(stream), 4772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mCommandMQ(commandMQ), 4872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mDataMQ(dataMQ), 4972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStatusMQ(statusMQ), 5072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mEfGroup(efGroup), 5172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mBuffer(nullptr) {} 5267d550888a021633cc33cb284bb0658b008887c6Kevin Rocard bool init() { 5372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]); 5467d550888a021633cc33cb284bb0658b008887c6Kevin Rocard return mBuffer != nullptr; 55b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 56b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov virtual ~WriteThread() {} 57b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 5872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard private: 59b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::atomic<bool>* mStop; 60b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov audio_stream_out_t* mStream; 61a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov StreamOut::CommandMQ* mCommandMQ; 62b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::DataMQ* mDataMQ; 63b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov StreamOut::StatusMQ* mStatusMQ; 64b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov EventFlag* mEfGroup; 65b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<uint8_t[]> mBuffer; 66a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov IStreamOut::WriteStatus mStatus; 67b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 68b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov bool threadLoop() override; 69a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 70a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doGetLatency(); 71a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doGetPresentationPosition(); 72a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov void doWrite(); 73b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov}; 74b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 75a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doWrite() { 76a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov const size_t availToRead = mDataMQ->availableToRead(); 77a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::OK; 78a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.written = 0; 79a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (mDataMQ->read(&mBuffer[0], availToRead)) { 80a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead); 81a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (writeResult >= 0) { 82a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.written = writeResult; 83a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } else { 84a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Stream::analyzeStatus("write", writeResult); 85a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 86a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 87a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 88a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 89a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doGetPresentationPosition() { 9082cb03632c15976838407c231fd85804de9bf84cKevin Rocard mStatus.retval = 9182cb03632c15976838407c231fd85804de9bf84cKevin Rocard StreamOut::getPresentationPositionImpl(mStream, &mStatus.reply.presentationPosition.frames, 9282cb03632c15976838407c231fd85804de9bf84cKevin Rocard &mStatus.reply.presentationPosition.timeStamp); 93a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 94a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 95a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganovvoid WriteThread::doGetLatency() { 96a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::OK; 97a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.reply.latencyMs = mStream->get_latency(mStream); 98a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov} 99a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov 100b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganovbool WriteThread::threadLoop() { 10172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // This implementation doesn't return control back to the Thread until it 10272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard // decides to stop, 103b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // as the Thread uses mutexes, and this can lead to priority inversion. 10472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) { 105b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov uint32_t efState = 0; 10682cb03632c15976838407c231fd85804de9bf84cKevin Rocard mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); 10782cb03632c15976838407c231fd85804de9bf84cKevin Rocard if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) { 108b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov continue; // Nothing to do. 109b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 110a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (!mCommandMQ->read(&mStatus.replyTo)) { 111a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov continue; // Nothing to do. 112a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov } 113a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov switch (mStatus.replyTo) { 114a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::WRITE: 115a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doWrite(); 116a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 117a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION: 118a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doGetPresentationPosition(); 119a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 120a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov case IStreamOut::WriteCommand::GET_LATENCY: 121a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov doGetLatency(); 122a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 123a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov default: 124a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE("Unknown write thread command code %d", mStatus.replyTo); 125a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mStatus.retval = Result::NOT_SUPPORTED; 126a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov break; 127b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 128a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov if (!mStatusMQ->write(&mStatus)) { 129a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE("status message queue write failed"); 130b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 131b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); 132b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 133b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 134b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return false; 135b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 136b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 137b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} // namespace 138b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 139936279e1ffe6bf7e842c46f9a94d98a48dce6754Mikhail NaganovStreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream) 14072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : mIsClosed(false), 14172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mDevice(device), 14272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStream(stream), 14372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStreamCommon(new Stream(&stream->common)), 14472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)), 14572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mEfGroup(nullptr), 14672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard mStopWriteThread(false) {} 14710548295023bee99108e418499aff09fe578211eMikhail Naganov 14810548295023bee99108e418499aff09fe578211eMikhail NaganovStreamOut::~StreamOut() { 149b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ATRACE_CALL(); 150b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov close(); 151b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov if (mWriteThread.get()) { 152b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ATRACE_NAME("mWriteThread->join"); 153b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov status_t status = mWriteThread->join(); 154b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov ALOGE_IF(status, "write thread exit error: %s", strerror(-status)); 155b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov } 156b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov if (mEfGroup) { 157b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov status_t status = EventFlag::deleteEventFlag(&mEfGroup); 15882cb03632c15976838407c231fd85804de9bf84cKevin Rocard ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status)); 159b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov } 160b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov mCallback.clear(); 161936279e1ffe6bf7e842c46f9a94d98a48dce6754Mikhail Naganov mDevice->closeOutputStream(mStream); 162718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // Closing the output stream in the HAL waits for the callback to finish, 163718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // and joins the callback thread. Thus is it guaranteed that the callback 164718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // thread will not be accessing our object anymore. 16510548295023bee99108e418499aff09fe578211eMikhail Naganov mStream = nullptr; 16610548295023bee99108e418499aff09fe578211eMikhail Naganov} 16710548295023bee99108e418499aff09fe578211eMikhail Naganov 168e9e4e16564c2949960bf9dd3ab49c9dee2273f3cKevin Rocard// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow. 16972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getFrameSize() { 17010548295023bee99108e418499aff09fe578211eMikhail Naganov return audio_stream_out_frame_size(mStream); 17110548295023bee99108e418499aff09fe578211eMikhail Naganov} 17210548295023bee99108e418499aff09fe578211eMikhail Naganov 17372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getFrameCount() { 17410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFrameCount(); 17510548295023bee99108e418499aff09fe578211eMikhail Naganov} 17610548295023bee99108e418499aff09fe578211eMikhail Naganov 17772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint64_t> StreamOut::getBufferSize() { 17810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getBufferSize(); 17910548295023bee99108e418499aff09fe578211eMikhail Naganov} 18010548295023bee99108e418499aff09fe578211eMikhail Naganov 18172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint32_t> StreamOut::getSampleRate() { 18210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSampleRate(); 18310548295023bee99108e418499aff09fe578211eMikhail Naganov} 18410548295023bee99108e418499aff09fe578211eMikhail Naganov 1855ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard#ifdef AUDIO_HAL_VERSION_2_0 1865ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { 1875ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->getSupportedChannelMasks(_hidl_cb); 1885ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 18982cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { 19010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedSampleRates(_hidl_cb); 19110548295023bee99108e418499aff09fe578211eMikhail Naganov} 1925ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard#endif 1935ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard 1945ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<void> StreamOut::getSupportedChannelMasks(AudioFormat format, 1955ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard getSupportedChannelMasks_cb _hidl_cb) { 1965ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->getSupportedChannelMasks(format, _hidl_cb); 1975ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 1985ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<void> StreamOut::getSupportedSampleRates(AudioFormat format, 1995ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard getSupportedSampleRates_cb _hidl_cb) { 2005ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->getSupportedSampleRates(format, _hidl_cb); 2015ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 20210548295023bee99108e418499aff09fe578211eMikhail Naganov 20372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) { 20410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setSampleRate(sampleRateHz); 20510548295023bee99108e418499aff09fe578211eMikhail Naganov} 20610548295023bee99108e418499aff09fe578211eMikhail Naganov 2075ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<AudioChannelBitfield> StreamOut::getChannelMask() { 20810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getChannelMask(); 20910548295023bee99108e418499aff09fe578211eMikhail Naganov} 21010548295023bee99108e418499aff09fe578211eMikhail Naganov 2115ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<Result> StreamOut::setChannelMask(AudioChannelBitfield mask) { 21210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setChannelMask(mask); 21310548295023bee99108e418499aff09fe578211eMikhail Naganov} 21410548295023bee99108e418499aff09fe578211eMikhail Naganov 21572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<AudioFormat> StreamOut::getFormat() { 21610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getFormat(); 21710548295023bee99108e418499aff09fe578211eMikhail Naganov} 21810548295023bee99108e418499aff09fe578211eMikhail Naganov 21972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { 22010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getSupportedFormats(_hidl_cb); 22110548295023bee99108e418499aff09fe578211eMikhail Naganov} 22210548295023bee99108e418499aff09fe578211eMikhail Naganov 22372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setFormat(AudioFormat format) { 22410548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setFormat(format); 22510548295023bee99108e418499aff09fe578211eMikhail Naganov} 22610548295023bee99108e418499aff09fe578211eMikhail Naganov 22772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) { 22810548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getAudioProperties(_hidl_cb); 22910548295023bee99108e418499aff09fe578211eMikhail Naganov} 23010548295023bee99108e418499aff09fe578211eMikhail Naganov 23172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::addEffect(uint64_t effectId) { 23210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->addEffect(effectId); 23310548295023bee99108e418499aff09fe578211eMikhail Naganov} 23410548295023bee99108e418499aff09fe578211eMikhail Naganov 23572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::removeEffect(uint64_t effectId) { 23610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->removeEffect(effectId); 23710548295023bee99108e418499aff09fe578211eMikhail Naganov} 23810548295023bee99108e418499aff09fe578211eMikhail Naganov 23972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::standby() { 24010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->standby(); 24110548295023bee99108e418499aff09fe578211eMikhail Naganov} 24210548295023bee99108e418499aff09fe578211eMikhail Naganov 2435ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) { 2445ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->setHwAvSync(hwAvSync); 24510548295023bee99108e418499aff09fe578211eMikhail Naganov} 24610548295023bee99108e418499aff09fe578211eMikhail Naganov 2475ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard#ifdef AUDIO_HAL_VERSION_2_0 24882cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) { 24910548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setConnectedState(address, connected); 25010548295023bee99108e418499aff09fe578211eMikhail Naganov} 25110548295023bee99108e418499aff09fe578211eMikhail Naganov 2525ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<AudioDevice> StreamOut::getDevice() { 2535ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->getDevice(); 2545ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 2555ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard 2565ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<Result> StreamOut::setDevice(const DeviceAddress& address) { 2575ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->setDevice(address); 25810548295023bee99108e418499aff09fe578211eMikhail Naganov} 25910548295023bee99108e418499aff09fe578211eMikhail Naganov 26072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getParameters(const hidl_vec<hidl_string>& keys, 26172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard getParameters_cb _hidl_cb) { 26210548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->getParameters(keys, _hidl_cb); 26310548295023bee99108e418499aff09fe578211eMikhail Naganov} 26410548295023bee99108e418499aff09fe578211eMikhail Naganov 26582cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) { 26610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->setParameters(parameters); 26710548295023bee99108e418499aff09fe578211eMikhail Naganov} 26810548295023bee99108e418499aff09fe578211eMikhail Naganov 26972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::debugDump(const hidl_handle& fd) { 27010548295023bee99108e418499aff09fe578211eMikhail Naganov return mStreamCommon->debugDump(fd); 27110548295023bee99108e418499aff09fe578211eMikhail Naganov} 2725ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard#elif defined(AUDIO_HAL_VERSION_4_0) 2735ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<void> StreamOut::getDevices(getDevices_cb _hidl_cb) { 2745ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->getDevices(_hidl_cb); 2755ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 2765ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard 2775ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<Result> StreamOut::setDevices(const hidl_vec<DeviceAddress>& devices) { 2785ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->setDevices(devices); 2795ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 2805ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<void> StreamOut::getParameters(const hidl_vec<ParameterValue>& context, 2815ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard const hidl_vec<hidl_string>& keys, 2825ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard getParameters_cb _hidl_cb) { 2835ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->getParameters(context, keys, _hidl_cb); 2845ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 2855ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard 2865ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& context, 2875ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard const hidl_vec<ParameterValue>& parameters) { 2885ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->setParameters(context, parameters); 2895ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 2905ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard#endif 29110548295023bee99108e418499aff09fe578211eMikhail Naganov 29272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::close() { 293b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mIsClosed) return Result::INVALID_STATE; 294b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mIsClosed = true; 295b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mWriteThread.get()) { 296b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStopWriteThread.store(true, std::memory_order_release); 297b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 298b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mEfGroup) { 299b0abafbf0a6174e8c8933cc5fb19501a2d22c53bMikhail Naganov mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); 300b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 301b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Result::OK; 302b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov} 303b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 304e9e4e16564c2949960bf9dd3ab49c9dee2273f3cKevin Rocard// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut follow. 30572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<uint32_t> StreamOut::getLatency() { 30610548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->get_latency(mStream); 30710548295023bee99108e418499aff09fe578211eMikhail Naganov} 30810548295023bee99108e418499aff09fe578211eMikhail Naganov 30972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setVolume(float left, float right) { 3104c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard if (mStream->set_volume == NULL) { 3114c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard return Result::NOT_SUPPORTED; 31210548295023bee99108e418499aff09fe578211eMikhail Naganov } 3134c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard if (!isGainNormalized(left)) { 31482cb03632c15976838407c231fd85804de9bf84cKevin Rocard ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left, right); 3154c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard return Result::INVALID_ARGUMENTS; 3164c030024dfa9cdf924cb771580e13d237f1ec813Kevin Rocard } 31782cb03632c15976838407c231fd85804de9bf84cKevin Rocard return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right)); 31810548295023bee99108e418499aff09fe578211eMikhail Naganov} 31910548295023bee99108e418499aff09fe578211eMikhail Naganov 32082cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount, 32172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard prepareForWriting_cb _hidl_cb) { 322b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov status_t status; 32372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ThreadInfo threadInfo = {0, 0}; 324c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard 325c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard // Wrap the _hidl_cb to return an error 326b38c1aebc1e696b7bc8b5ec713388079cb677d25Chih-Hung Hsieh auto sendError = [&threadInfo, &_hidl_cb](Result result) { 32782cb03632c15976838407c231fd85804de9bf84cKevin Rocard _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), 32882cb03632c15976838407c231fd85804de9bf84cKevin Rocard threadInfo); 329c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard 330c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard }; 331c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard 332b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create message queues. 333b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (mDataMQ) { 334b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("the client attempts to call prepareForWriting twice"); 335c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_STATE); 336b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 337b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 338a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1)); 339b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard 340195205b323b7d93cf4d477445469759b27371f45Kevin Rocard // Check frameSize and framesCount 341195205b323b7d93cf4d477445469759b27371f45Kevin Rocard if (frameSize == 0 || framesCount == 0) { 34282cb03632c15976838407c231fd85804de9bf84cKevin Rocard ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize, framesCount); 343195205b323b7d93cf4d477445469759b27371f45Kevin Rocard sendError(Result::INVALID_ARGUMENTS); 344195205b323b7d93cf4d477445469759b27371f45Kevin Rocard return Void(); 345195205b323b7d93cf4d477445469759b27371f45Kevin Rocard } 34646cba442d25e16cce4d5f009f4700a88d53636b1Kevin Rocard if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) { 34746cba442d25e16cce4d5f009f4700a88d53636b1Kevin Rocard ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount, 34846cba442d25e16cce4d5f009f4700a88d53636b1Kevin Rocard Stream::MAX_BUFFER_SIZE); 349195205b323b7d93cf4d477445469759b27371f45Kevin Rocard sendError(Result::INVALID_ARGUMENTS); 350b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard return Void(); 351b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard } 35282cb03632c15976838407c231fd85804de9bf84cKevin Rocard std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */)); 353b6498cbdf6c04c631ccf6a6e65a1264b455e3088Kevin Rocard 354b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1)); 35582cb03632c15976838407c231fd85804de9bf84cKevin Rocard if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) { 356a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid"); 357b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid"); 358b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid"); 359c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 360b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 361b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 36240343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard EventFlag* tempRawEfGroup{}; 36382cb03632c15976838407c231fd85804de9bf84cKevin Rocard status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup); 36472e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup( 36572e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); }); 36640343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard if (status != OK || !tempElfGroup) { 367b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGE("failed creating event flag for data MQ: %s", strerror(-status)); 368c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 369b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 370b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov } 371b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 372b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov // Create and launch the thread. 37382cb03632c15976838407c231fd85804de9bf84cKevin Rocard auto tempWriteThread = 37482cb03632c15976838407c231fd85804de9bf84cKevin Rocard std::make_unique<WriteThread>(&mStopWriteThread, mStream, tempCommandMQ.get(), 37582cb03632c15976838407c231fd85804de9bf84cKevin Rocard tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get()); 37667d550888a021633cc33cb284bb0658b008887c6Kevin Rocard if (!tempWriteThread->init()) { 377c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard ALOGW("failed to start writer thread: %s", strerror(-status)); 378c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 37967d550888a021633cc33cb284bb0658b008887c6Kevin Rocard return Void(); 38067d550888a021633cc33cb284bb0658b008887c6Kevin Rocard } 38167d550888a021633cc33cb284bb0658b008887c6Kevin Rocard status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO); 382b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov if (status != OK) { 383b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov ALOGW("failed to start writer thread: %s", strerror(-status)); 384c07df49e455ef67f880a3ca29ce585a213bccddeKevin Rocard sendError(Result::INVALID_ARGUMENTS); 385b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov return Void(); 38610548295023bee99108e418499aff09fe578211eMikhail Naganov } 387b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov 388a468fa84d13b085b1808f20f70d22ed9dbe3f3ebMikhail Naganov mCommandMQ = std::move(tempCommandMQ); 389b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mDataMQ = std::move(tempDataMQ); 390b29438ef70549a331d11c0384c53cf1dc6e7f0beMikhail Naganov mStatusMQ = std::move(tempStatusMQ); 39167d550888a021633cc33cb284bb0658b008887c6Kevin Rocard mWriteThread = tempWriteThread.release(); 39240343061d5f6f309c68a54940e24d404e6cd620aKevin Rocard mEfGroup = tempElfGroup.release(); 393a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov threadInfo.pid = getpid(); 394a1db22a3e5b45b3bd3c2edf84c605ce211c89220Mikhail Naganov threadInfo.tid = mWriteThread->getTid(); 39582cb03632c15976838407c231fd85804de9bf84cKevin Rocard _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(), 39682cb03632c15976838407c231fd85804de9bf84cKevin Rocard threadInfo); 39710548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 39810548295023bee99108e418499aff09fe578211eMikhail Naganov} 39910548295023bee99108e418499aff09fe578211eMikhail Naganov 40072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { 40110548295023bee99108e418499aff09fe578211eMikhail Naganov uint32_t halDspFrames; 40282cb03632c15976838407c231fd85804de9bf84cKevin Rocard Result retval = Stream::analyzeStatus("get_render_position", 40382cb03632c15976838407c231fd85804de9bf84cKevin Rocard mStream->get_render_position(mStream, &halDspFrames)); 40410548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, halDspFrames); 40510548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 40610548295023bee99108e418499aff09fe578211eMikhail Naganov} 40710548295023bee99108e418499aff09fe578211eMikhail Naganov 40882cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) { 40910548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 41010548295023bee99108e418499aff09fe578211eMikhail Naganov int64_t timestampUs = 0; 41110548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->get_next_write_timestamp != NULL) { 41282cb03632c15976838407c231fd85804de9bf84cKevin Rocard retval = Stream::analyzeStatus("get_next_write_timestamp", 41382cb03632c15976838407c231fd85804de9bf84cKevin Rocard mStream->get_next_write_timestamp(mStream, ×tampUs)); 41410548295023bee99108e418499aff09fe578211eMikhail Naganov } 41510548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, timestampUs); 41610548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 41710548295023bee99108e418499aff09fe578211eMikhail Naganov} 41810548295023bee99108e418499aff09fe578211eMikhail Naganov 41972e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { 42010548295023bee99108e418499aff09fe578211eMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 421718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // Safe to pass 'this' because it is guaranteed that the callback thread 422718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // is joined prior to exit from StreamOut's destructor. 42310548295023bee99108e418499aff09fe578211eMikhail Naganov int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); 42410548295023bee99108e418499aff09fe578211eMikhail Naganov if (result == 0) { 42510548295023bee99108e418499aff09fe578211eMikhail Naganov mCallback = callback; 42610548295023bee99108e418499aff09fe578211eMikhail Naganov } 4277deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return Stream::analyzeStatus("set_callback", result); 42810548295023bee99108e418499aff09fe578211eMikhail Naganov} 42910548295023bee99108e418499aff09fe578211eMikhail Naganov 43072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::clearCallback() { 4316e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; 4326e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov mCallback.clear(); 4336e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov return Result::OK; 4346e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov} 4356e81e9bb3c13d8c51fde503cf8be2bfb56e1ca1dMikhail Naganov 43610548295023bee99108e418499aff09fe578211eMikhail Naganov// static 43782cb03632c15976838407c231fd85804de9bf84cKevin Rocardint StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie) { 438718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // It is guaranteed that the callback thread is joined prior 439718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // to exiting from StreamOut's destructor. Must *not* use sp<StreamOut> 440718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // here because it can make this code the last owner of StreamOut, 441718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // and an attempt to run the destructor on the callback thread 442718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // will cause a deadlock in the legacy HAL code. 44382cb03632c15976838407c231fd85804de9bf84cKevin Rocard StreamOut* self = reinterpret_cast<StreamOut*>(cookie); 444718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // It's correct to hold an sp<> to callback because the reference 445718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // in the StreamOut instance can be cleared in the meantime. There is 446718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov // no difference on which thread to run IStreamOutCallback's destructor. 447718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov sp<IStreamOutCallback> callback = self->mCallback; 448718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov if (callback.get() == nullptr) return 0; 44910548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGV("asyncCallback() event %d", event); 45010548295023bee99108e418499aff09fe578211eMikhail Naganov switch (event) { 45110548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_WRITE_READY: 452718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov callback->onWriteReady(); 45310548295023bee99108e418499aff09fe578211eMikhail Naganov break; 45410548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_DRAIN_READY: 455718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov callback->onDrainReady(); 45610548295023bee99108e418499aff09fe578211eMikhail Naganov break; 45710548295023bee99108e418499aff09fe578211eMikhail Naganov case STREAM_CBK_EVENT_ERROR: 458718b51008095493e2ba0f2a0e3b98d1b2decd794Mikhail Naganov callback->onError(); 45910548295023bee99108e418499aff09fe578211eMikhail Naganov break; 46010548295023bee99108e418499aff09fe578211eMikhail Naganov default: 46110548295023bee99108e418499aff09fe578211eMikhail Naganov ALOGW("asyncCallback() unknown event %d", event); 46210548295023bee99108e418499aff09fe578211eMikhail Naganov break; 46310548295023bee99108e418499aff09fe578211eMikhail Naganov } 46410548295023bee99108e418499aff09fe578211eMikhail Naganov return 0; 46510548295023bee99108e418499aff09fe578211eMikhail Naganov} 46610548295023bee99108e418499aff09fe578211eMikhail Naganov 46782cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) { 46810548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(mStream->pause != NULL, mStream->resume != NULL); 46910548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 47010548295023bee99108e418499aff09fe578211eMikhail Naganov} 47110548295023bee99108e418499aff09fe578211eMikhail Naganov 47272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::pause() { 47382cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStream->pause != NULL ? Stream::analyzeStatus("pause", mStream->pause(mStream)) 47482cb03632c15976838407c231fd85804de9bf84cKevin Rocard : Result::NOT_SUPPORTED; 47510548295023bee99108e418499aff09fe578211eMikhail Naganov} 47610548295023bee99108e418499aff09fe578211eMikhail Naganov 47772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::resume() { 47882cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStream->resume != NULL ? Stream::analyzeStatus("resume", mStream->resume(mStream)) 47982cb03632c15976838407c231fd85804de9bf84cKevin Rocard : Result::NOT_SUPPORTED; 48010548295023bee99108e418499aff09fe578211eMikhail Naganov} 48110548295023bee99108e418499aff09fe578211eMikhail Naganov 48272e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<bool> StreamOut::supportsDrain() { 48310548295023bee99108e418499aff09fe578211eMikhail Naganov return mStream->drain != NULL; 48410548295023bee99108e418499aff09fe578211eMikhail Naganov} 48510548295023bee99108e418499aff09fe578211eMikhail Naganov 48672e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::drain(AudioDrain type) { 48772e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard return mStream->drain != NULL 48872e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard ? Stream::analyzeStatus( 48982cb03632c15976838407c231fd85804de9bf84cKevin Rocard "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) 49072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard : Result::NOT_SUPPORTED; 49110548295023bee99108e418499aff09fe578211eMikhail Naganov} 49210548295023bee99108e418499aff09fe578211eMikhail Naganov 49372e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin RocardReturn<Result> StreamOut::flush() { 49482cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStream->flush != NULL ? Stream::analyzeStatus("flush", mStream->flush(mStream)) 49582cb03632c15976838407c231fd85804de9bf84cKevin Rocard : Result::NOT_SUPPORTED; 49610548295023bee99108e418499aff09fe578211eMikhail Naganov} 49710548295023bee99108e418499aff09fe578211eMikhail Naganov 498ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov// static 49982cb03632c15976838407c231fd85804de9bf84cKevin RocardResult StreamOut::getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames, 50072e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard TimeSpec* timeStamp) { 50196a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // Don't logspam on EINVAL--it's normal for get_presentation_position 50296a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // to return it sometimes. EAGAIN may be returned by A2DP audio HAL 50396a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // implementation. ENODATA can also be reported while the writer is 50496a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov // continuously querying it, but the stream has been stopped. 50596a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA}; 50610548295023bee99108e418499aff09fe578211eMikhail Naganov Result retval(Result::NOT_SUPPORTED); 507ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (stream->get_presentation_position == NULL) return retval; 508ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov struct timespec halTimeStamp; 50996a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov retval = Stream::analyzeStatus("get_presentation_position", 51096a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov stream->get_presentation_position(stream, frames, &halTimeStamp), 51196a3a19beda45bef7c34fc06a0048174f3a7e362Mikhail Naganov ignoredErrors); 512ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov if (retval == Result::OK) { 513ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvSec = halTimeStamp.tv_sec; 514ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov timeStamp->tvNSec = halTimeStamp.tv_nsec; 515ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov } 516ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov return retval; 517ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov} 518ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov 51982cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) { 52010548295023bee99108e418499aff09fe578211eMikhail Naganov uint64_t frames = 0; 52172e50e2ef1480fc3d90f0d88c7e9e3595622e75cKevin Rocard TimeSpec timeStamp = {0, 0}; 522ee901e3fd885709abc9b9e2b8e521022e27522d3Mikhail Naganov Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp); 52310548295023bee99108e418499aff09fe578211eMikhail Naganov _hidl_cb(retval, frames, timeStamp); 52410548295023bee99108e418499aff09fe578211eMikhail Naganov return Void(); 52510548295023bee99108e418499aff09fe578211eMikhail Naganov} 52610548295023bee99108e418499aff09fe578211eMikhail Naganov 5277deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::start() { 5287deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->start(); 5297deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5307deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 5317deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<Result> StreamOut::stop() { 5327deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->stop(); 5337deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5347deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 53582cb03632c15976838407c231fd85804de9bf84cKevin RocardReturn<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { 53682cb03632c15976838407c231fd85804de9bf84cKevin Rocard return mStreamMmap->createMmapBuffer(minSizeFrames, audio_stream_out_frame_size(mStream), 53782cb03632c15976838407c231fd85804de9bf84cKevin Rocard _hidl_cb); 5387deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5397deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 5407deb7dad39e58b6e5de812075950adc27cd51d95Eric LaurentReturn<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) { 5417deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent return mStreamMmap->getMmapPosition(_hidl_cb); 5427deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent} 5437deb7dad39e58b6e5de812075950adc27cd51d95Eric Laurent 5445ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<void> StreamOut::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) { 5455ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return mStreamCommon->debug(fd, options); 5465ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 5475ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard 5485ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard#ifdef AUDIO_HAL_VERSION_4_0 54960c1ad7797cc64d428d043250a55cdc6189a19c8Kevin RocardReturn<void> StreamOut::updateSourceMetadata(const SourceMetadata& sourceMetadata) { 55060c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard if (mStream->update_source_metadata == nullptr) { 55160c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard return Void(); // not supported by the HAL 55260c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard } 55360c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard std::vector<playback_track_metadata> halTracks; 55460c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard halTracks.reserve(sourceMetadata.tracks.size()); 55560c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard for (auto& metadata : sourceMetadata.tracks) { 55660c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard halTracks.push_back({ 55760c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard .usage = static_cast<audio_usage_t>(metadata.usage), 55860c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard .content_type = static_cast<audio_content_type_t>(metadata.contentType), 55960c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard .gain = metadata.gain, 56060c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard }); 56160c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard } 56260c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard const source_metadata_t halMetadata = { 56360c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard .track_count = halTracks.size(), .tracks = halTracks.data(), 56460c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard }; 56560c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard mStream->update_source_metadata(mStream, &halMetadata); 56660c1ad7797cc64d428d043250a55cdc6189a19c8Kevin Rocard return Void(); 5675ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 5685ec293316e7ea1f768161695a113e50b0ea41d45Kevin RocardReturn<Result> StreamOut::selectPresentation(int32_t /*presentationId*/, int32_t /*programId*/) { 5695ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard return Result::NOT_SUPPORTED; // TODO: propagate to legacy 5705ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard} 5715ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard#endif 5725ec293316e7ea1f768161695a113e50b0ea41d45Kevin Rocard 57310548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace implementation 574e9e4e16564c2949960bf9dd3ab49c9dee2273f3cKevin Rocard} // namespace AUDIO_HAL_VERSION 57510548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace audio 57610548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace hardware 57710548295023bee99108e418499aff09fe578211eMikhail Naganov} // namespace android 578