FastCapture.cpp revision f91df1b368a140abd37c80b204bd48d78778cc43
124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian/*
224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * Copyright (C) 2014 The Android Open Source Project
324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian *
424035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
524035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * you may not use this file except in compliance with the License.
624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * You may obtain a copy of the License at
724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian *
824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian *
1024035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * Unless required by applicable law or agreed to in writing, software
1124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
1224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * See the License for the specific language governing permissions and
1424035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian * limitations under the License.
1524035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian */
1624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
1724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#define LOG_TAG "FastCapture"
1824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian//#define LOG_NDEBUG 0
1924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
2024035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#define ATRACE_TAG ATRACE_TAG_AUDIO
2124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
2224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#include "Configuration.h"
231cadb25da1ed875bdd078270e642966724a0c39aMathias Agopian#include <linux/futex.h>
2424035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#include <sys/syscall.h>
2524035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#include <media/AudioBufferProvider.h>
2624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#include <utils/Log.h>
2724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#include <utils/Trace.h>
2824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian#include "FastCapture.h"
2924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
3024035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopiannamespace android {
317f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian
3224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian/*static*/ const FastCaptureState FastCapture::initial;
3324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
347f781d155221c4067c93f85b4153c204423f49f2Mathias AgopianFastCapture::FastCapture() : FastThread(),
357f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian    inputSource(NULL), inputSourceGen(0), pipeSink(NULL), pipeSinkGen(0),
367f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian    readBuffer(NULL), readBufferState(-1), format(Format_Invalid), sampleRate(0),
3724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    // dummyDumpState
381cadb25da1ed875bdd078270e642966724a0c39aMathias Agopian    totalNativeFramesRead(0)
3924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
40288870ebc3da8121b7a237a53280bd8b931b7a2fElliott Hughes    previous = &initial;
4124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    current = &initial;
4224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
4324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    mDummyDumpState = &dummyDumpState;
4424035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian}
4524035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
4624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias AgopianFastCapture::~FastCapture()
4724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
4824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian}
4924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
5024035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias AgopianFastCaptureStateQueue* FastCapture::sq()
5124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
5224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    return &mSQ;
5324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian}
5424035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
5524035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopianconst FastThreadState *FastCapture::poll()
5624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
5724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    return mSQ.poll();
5824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian}
5924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
607f781d155221c4067c93f85b4153c204423f49f2Mathias Agopianvoid FastCapture::setLog(NBLog::Writer *logWriter __unused)
6124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
6224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian}
6324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
6424035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopianvoid FastCapture::onIdle()
6524035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
6624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    preIdle = *(const FastCaptureState *)current;
6724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    current = &preIdle;
6824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian}
6924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian
7024035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopianvoid FastCapture::onExit()
7124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
7224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    delete[] readBuffer;
7324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian}
741cadb25da1ed875bdd078270e642966724a0c39aMathias Agopian
7524035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopianbool FastCapture::isSubClassCommand(FastThreadState::Command command)
7624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian{
7724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    switch ((FastCaptureState::Command) command) {
78a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    case FastCaptureState::READ:
797f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian    case FastCaptureState::WRITE:
80a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    case FastCaptureState::READ_WRITE:
81a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        return true;
82a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    default:
83a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        return false;
84a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    }
85a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian}
86a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian
87a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopianvoid FastCapture::onStateChange()
88a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian{
89a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    const FastCaptureState * const current = (const FastCaptureState *) this->current;
90a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    const FastCaptureState * const previous = (const FastCaptureState *) this->previous;
91a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
92a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    const size_t frameCount = current->mFrameCount;
93a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian
94a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    bool eitherChanged = false;
95a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian
96a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    // check for change in input HAL configuration
97a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    NBAIO_Format previousFormat = format;
98a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    if (current->mInputSourceGen != inputSourceGen) {
99a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        inputSource = current->mInputSource;
100a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        inputSourceGen = current->mInputSourceGen;
101a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        if (inputSource == NULL) {
102a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian            format = Format_Invalid;
103a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian            sampleRate = 0;
104a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        } else {
105a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian            format = inputSource->format();
106a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian            sampleRate = Format_sampleRate(format);
107a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian            unsigned channelCount = Format_channelCount(format);
108a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian            ALOG_ASSERT(channelCount == 1 || channelCount == 2);
109a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        }
110a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        dumpState->mSampleRate = sampleRate;
111a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian        eitherChanged = true;
112a6d86e5ea748a7bcde4ff30b0b1f882dca36a8f3Mathias Agopian    }
1137f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian
1147f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian    // check for change in pipe
1157f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian    if (current->mPipeSinkGen != pipeSinkGen) {
1167f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian        pipeSink = current->mPipeSink;
1177f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian        pipeSinkGen = current->mPipeSinkGen;
11824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian        eitherChanged = true;
11924035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    }
1207f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian
12124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    // input source and pipe sink must be compatible
12224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    if (eitherChanged && inputSource != NULL && pipeSink != NULL) {
1237f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian        ALOG_ASSERT(Format_isEqual(format, pipeSink->format()));
1247f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian    }
1257f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian
12624035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian    if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
12724035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian        // FIXME to avoid priority inversion, don't delete here
12824035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian        delete[] readBuffer;
1297f781d155221c4067c93f85b4153c204423f49f2Mathias Agopian        readBuffer = NULL;
13024035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian        if (frameCount > 0 && sampleRate > 0) {
13124035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian            // FIXME new may block for unbounded time at internal mutex of the heap
13224035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian            //       implementation; it would be better to have normal capture thread allocate for
13324035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian            //       us to avoid blocking here and to prevent possible priority inversion
13424035338ed6329e4d85fb00cf99a91e2cdd55ba5Mathias Agopian            unsigned channelCount = Format_channelCount(format);
135            // FIXME frameSize
136            readBuffer = new short[frameCount * channelCount];
137            periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
138            underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
139            overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
140            forceNs = (frameCount * 950000000LL) / sampleRate;      // 0.95
141            warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
142        } else {
143            periodNs = 0;
144            underrunNs = 0;
145            overrunNs = 0;
146            forceNs = 0;
147            warmupNs = 0;
148        }
149        readBufferState = -1;
150        dumpState->mFrameCount = frameCount;
151    }
152
153}
154
155void FastCapture::onWork()
156{
157    const FastCaptureState * const current = (const FastCaptureState *) this->current;
158    FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
159    const FastCaptureState::Command command = this->command;
160    const size_t frameCount = current->mFrameCount;
161
162    if ((command & FastCaptureState::READ) /*&& isWarm*/) {
163        ALOG_ASSERT(inputSource != NULL);
164        ALOG_ASSERT(readBuffer != NULL);
165        dumpState->mReadSequence++;
166        ATRACE_BEGIN("read");
167        ssize_t framesRead = inputSource->read(readBuffer, frameCount,
168                AudioBufferProvider::kInvalidPTS);
169        ATRACE_END();
170        dumpState->mReadSequence++;
171        if (framesRead >= 0) {
172            LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
173            totalNativeFramesRead += framesRead;
174            dumpState->mFramesRead = totalNativeFramesRead;
175            readBufferState = framesRead;
176        } else {
177            dumpState->mReadErrors++;
178            readBufferState = 0;
179        }
180        // FIXME rename to attemptedIO
181        attemptedWrite = true;
182    }
183
184    if (command & FastCaptureState::WRITE) {
185        ALOG_ASSERT(pipeSink != NULL);
186        ALOG_ASSERT(readBuffer != NULL);
187        if (readBufferState < 0) {
188            unsigned channelCount = Format_channelCount(format);
189            // FIXME frameSize
190            memset(readBuffer, 0, frameCount * channelCount * sizeof(short));
191            readBufferState = frameCount;
192        }
193        if (readBufferState > 0) {
194            ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState);
195            // FIXME This supports at most one fast capture client.
196            //       To handle multiple clients this could be converted to an array,
197            //       or with a lot more work the control block could be shared by all clients.
198            audio_track_cblk_t* cblk = current->mCblk;
199            if (cblk != NULL && framesWritten > 0) {
200                int32_t rear = cblk->u.mStreaming.mRear;
201                android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
202                cblk->mServer += framesWritten;
203                int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
204                if (!(old & CBLK_FUTEX_WAKE)) {
205                    // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
206                    (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
207                }
208            }
209        }
210    }
211}
212
213FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
214    mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
215{
216}
217
218FastCaptureDumpState::~FastCaptureDumpState()
219{
220}
221
222}   // namespace android
223