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