Start adding FastCapture based on FastThread WIP

This version supports at most one fast capture client.

Change-Id: Idf609bfc80ae22433433d66a5232c043c65506df
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 8d0a705..3b128cf 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -63,6 +63,7 @@
 
 LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp AudioWatchdog.cpp
 LOCAL_SRC_FILES += FastThread.cpp FastThreadState.cpp
+LOCAL_SRC_FILES += FastCapture.cpp FastCaptureState.cpp
 
 LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
 
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
new file mode 100644
index 0000000..0c9b976
--- /dev/null
+++ b/services/audioflinger/FastCapture.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "FastCapture"
+//#define LOG_NDEBUG 0
+
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include "Configuration.h"
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <media/AudioBufferProvider.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include "FastCapture.h"
+
+namespace android {
+
+/*static*/ const FastCaptureState FastCapture::initial;
+
+FastCapture::FastCapture() : FastThread(),
+    inputSource(NULL), inputSourceGen(0), pipeSink(NULL), pipeSinkGen(0),
+    readBuffer(NULL), readBufferState(-1), format(Format_Invalid), sampleRate(0),
+    // dummyDumpState
+    totalNativeFramesRead(0)
+{
+    previous = &initial;
+    current = &initial;
+
+    mDummyDumpState = &dummyDumpState;
+}
+
+FastCapture::~FastCapture()
+{
+}
+
+FastCaptureStateQueue* FastCapture::sq()
+{
+    return &mSQ;
+}
+
+const FastThreadState *FastCapture::poll()
+{
+    return mSQ.poll();
+}
+
+void FastCapture::setLog(NBLog::Writer *logWriter __unused)
+{
+}
+
+void FastCapture::onIdle()
+{
+    preIdle = *(const FastCaptureState *)current;
+    current = &preIdle;
+}
+
+void FastCapture::onExit()
+{
+    delete[] readBuffer;
+}
+
+bool FastCapture::isSubClassCommand(FastThreadState::Command command)
+{
+    switch ((FastCaptureState::Command) command) {
+    case FastCaptureState::READ:
+    case FastCaptureState::WRITE:
+    case FastCaptureState::READ_WRITE:
+        return true;
+    default:
+        return false;
+    }
+}
+
+void FastCapture::onStateChange()
+{
+    const FastCaptureState * const current = (const FastCaptureState *) this->current;
+    const FastCaptureState * const previous = (const FastCaptureState *) this->previous;
+    FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
+    const size_t frameCount = current->mFrameCount;
+
+    bool eitherChanged = false;
+
+    // check for change in input HAL configuration
+    NBAIO_Format previousFormat = format;
+    if (current->mInputSourceGen != inputSourceGen) {
+        inputSource = current->mInputSource;
+        inputSourceGen = current->mInputSourceGen;
+        if (inputSource == NULL) {
+            format = Format_Invalid;
+            sampleRate = 0;
+        } else {
+            format = inputSource->format();
+            sampleRate = Format_sampleRate(format);
+            unsigned channelCount = Format_channelCount(format);
+            ALOG_ASSERT(channelCount == 1 || channelCount == 2);
+        }
+        dumpState->mSampleRate = sampleRate;
+        eitherChanged = true;
+    }
+
+    // check for change in pipe
+    if (current->mPipeSinkGen != pipeSinkGen) {
+        pipeSink = current->mPipeSink;
+        pipeSinkGen = current->mPipeSinkGen;
+        eitherChanged = true;
+    }
+
+    // input source and pipe sink must be compatible
+    if (eitherChanged && inputSource != NULL && pipeSink != NULL) {
+        ALOG_ASSERT(Format_isEqual(format, pipeSink->format()));
+    }
+
+    if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
+        // FIXME to avoid priority inversion, don't delete here
+        delete[] readBuffer;
+        readBuffer = NULL;
+        if (frameCount > 0 && sampleRate > 0) {
+            // FIXME new may block for unbounded time at internal mutex of the heap
+            //       implementation; it would be better to have normal capture thread allocate for
+            //       us to avoid blocking here and to prevent possible priority inversion
+            unsigned channelCount = Format_channelCount(format);
+            // FIXME frameSize
+            readBuffer = new short[frameCount * channelCount];
+            periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
+            underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
+            overrunNs = (frameCount * 500000000LL) / sampleRate;    // 0.50
+            forceNs = (frameCount * 950000000LL) / sampleRate;      // 0.95
+            warmupNs = (frameCount * 500000000LL) / sampleRate;     // 0.50
+        } else {
+            periodNs = 0;
+            underrunNs = 0;
+            overrunNs = 0;
+            forceNs = 0;
+            warmupNs = 0;
+        }
+        readBufferState = -1;
+        dumpState->mFrameCount = frameCount;
+    }
+
+}
+
+void FastCapture::onWork()
+{
+    const FastCaptureState * const current = (const FastCaptureState *) this->current;
+    FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) this->dumpState;
+    const FastCaptureState::Command command = this->command;
+    const size_t frameCount = current->mFrameCount;
+
+    if ((command & FastCaptureState::READ) /*&& isWarm*/) {
+        ALOG_ASSERT(inputSource != NULL);
+        ALOG_ASSERT(readBuffer != NULL);
+        dumpState->mReadSequence++;
+        ATRACE_BEGIN("read");
+        ssize_t framesRead = inputSource->read(readBuffer, frameCount,
+                AudioBufferProvider::kInvalidPTS);
+        ATRACE_END();
+        dumpState->mReadSequence++;
+        if (framesRead >= 0) {
+            LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount);
+            totalNativeFramesRead += framesRead;
+            dumpState->mFramesRead = totalNativeFramesRead;
+            readBufferState = framesRead;
+        } else {
+            dumpState->mReadErrors++;
+            readBufferState = 0;
+        }
+        // FIXME rename to attemptedIO
+        attemptedWrite = true;
+    }
+
+    if (command & FastCaptureState::WRITE) {
+        ALOG_ASSERT(pipeSink != NULL);
+        ALOG_ASSERT(readBuffer != NULL);
+        if (readBufferState < 0) {
+            unsigned channelCount = Format_channelCount(format);
+            // FIXME frameSize
+            memset(readBuffer, 0, frameCount * channelCount * sizeof(short));
+            readBufferState = frameCount;
+        }
+        if (readBufferState > 0) {
+            ssize_t framesWritten = pipeSink->write(readBuffer, readBufferState);
+            // FIXME This supports at most one fast capture client.
+            //       To handle multiple clients this could be converted to an array,
+            //       or with a lot more work the control block could be shared by all clients.
+            audio_track_cblk_t* cblk = current->mCblk;
+            if (cblk != NULL && framesWritten > 0) {
+                int32_t rear = cblk->u.mStreaming.mRear;
+                android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
+                cblk->mServer += framesWritten;
+                int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
+                if (!(old & CBLK_FUTEX_WAKE)) {
+                    // client is never in server process, so don't use FUTEX_WAKE_PRIVATE
+                    (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1);
+                }
+            }
+        }
+    }
+}
+
+FastCaptureDumpState::FastCaptureDumpState() : FastThreadDumpState(),
+    mReadSequence(0), mFramesRead(0), mReadErrors(0), mSampleRate(0), mFrameCount(0)
+{
+}
+
+FastCaptureDumpState::~FastCaptureDumpState()
+{
+}
+
+}   // namespace android
diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h
new file mode 100644
index 0000000..e535b9d
--- /dev/null
+++ b/services/audioflinger/FastCapture.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_FAST_CAPTURE_H
+#define ANDROID_AUDIO_FAST_CAPTURE_H
+
+#include "FastThread.h"
+#include "StateQueue.h"
+#include "FastCaptureState.h"
+
+namespace android {
+
+typedef StateQueue<FastCaptureState> FastCaptureStateQueue;
+
+struct FastCaptureDumpState : FastThreadDumpState {
+    FastCaptureDumpState();
+    /*virtual*/ ~FastCaptureDumpState();
+
+    // FIXME by renaming, could pull up many of these to FastThreadDumpState
+    uint32_t mReadSequence;     // incremented before and after each read()
+    uint32_t mFramesRead;       // total number of frames read successfully
+    uint32_t mReadErrors;       // total number of read() errors
+    uint32_t mSampleRate;
+    size_t   mFrameCount;
+};
+
+class FastCapture : public FastThread {
+
+public:
+            FastCapture();
+    virtual ~FastCapture();
+
+            FastCaptureStateQueue*  sq();
+
+private:
+            FastCaptureStateQueue   mSQ;
+
+    // callouts
+    virtual const FastThreadState *poll();
+    virtual void setLog(NBLog::Writer *logWriter);
+    virtual void onIdle();
+    virtual void onExit();
+    virtual bool isSubClassCommand(FastThreadState::Command command);
+    virtual void onStateChange();
+    virtual void onWork();
+
+    static const FastCaptureState initial;
+    FastCaptureState preIdle; // copy of state before we went into idle
+    // FIXME by renaming, could pull up many of these to FastThread
+    NBAIO_Source *inputSource;
+    int inputSourceGen;
+    NBAIO_Sink *pipeSink;
+    int pipeSinkGen;
+    short *readBuffer;
+    ssize_t readBufferState;    // number of initialized frames in readBuffer, or -1 to clear
+    NBAIO_Format format;
+    unsigned sampleRate;
+    FastCaptureDumpState dummyDumpState;
+    uint32_t totalNativeFramesRead; // copied to dumpState->mFramesRead
+
+};  // class FastCapture
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_FAST_CAPTURE_H
diff --git a/services/audioflinger/FastCaptureState.cpp b/services/audioflinger/FastCaptureState.cpp
new file mode 100644
index 0000000..1d029b7
--- /dev/null
+++ b/services/audioflinger/FastCaptureState.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FastCaptureState.h"
+
+namespace android {
+
+FastCaptureState::FastCaptureState() : FastThreadState(),
+    mInputSource(NULL), mInputSourceGen(0), mPipeSink(NULL), mPipeSinkGen(0), mFrameCount(0)
+{
+}
+
+FastCaptureState::~FastCaptureState()
+{
+}
+
+}   // android
diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h
new file mode 100644
index 0000000..29c865a
--- /dev/null
+++ b/services/audioflinger/FastCaptureState.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_FAST_CAPTURE_STATE_H
+#define ANDROID_AUDIO_FAST_CAPTURE_STATE_H
+
+#include <media/nbaio/NBAIO.h>
+#include "FastThreadState.h"
+#include <private/media/AudioTrackShared.h>
+
+namespace android {
+
+// Represent a single state of the fast capture
+struct FastCaptureState : FastThreadState {
+                FastCaptureState();
+    /*virtual*/ ~FastCaptureState();
+
+    // all pointer fields use raw pointers; objects are owned and ref-counted by RecordThread
+    NBAIO_Source    *mInputSource;      // HAL input device, must already be negotiated
+    // FIXME by renaming, could pull up these fields to FastThreadState
+    int             mInputSourceGen;    // increment when mInputSource is assigned
+    NBAIO_Sink      *mPipeSink;         // after reading from input source, write to this pipe sink
+    int             mPipeSinkGen;       // increment when mPipeSink is assigned
+    size_t          mFrameCount;        // number of frames per fast capture buffer
+    audio_track_cblk_t  *mCblk;         // control block for the single fast client, or NULL
+
+    // Extends FastThreadState::Command
+    static const Command
+        // The following commands also process configuration changes, and can be "or"ed:
+        READ = 0x8,             // read from input source
+        WRITE = 0x10,           // write to pipe sink
+        READ_WRITE = 0x18;      // read from input source and write to pipe sink
+
+};  // struct FastCaptureState
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_FAST_CAPTURE_STATE_H
diff --git a/services/audioflinger/StateQueueInstantiations.cpp b/services/audioflinger/StateQueueInstantiations.cpp
index 0d5cd0c..6f4505e 100644
--- a/services/audioflinger/StateQueueInstantiations.cpp
+++ b/services/audioflinger/StateQueueInstantiations.cpp
@@ -16,12 +16,14 @@
 
 #include "Configuration.h"
 #include "FastMixerState.h"
+#include "FastCaptureState.h"
 #include "StateQueue.h"
 
 // FIXME hack for gcc
 
 namespace android {
 
-template class StateQueue<FastMixerState>;  // typedef FastMixerStateQueue
+template class StateQueue<FastMixerState>;      // typedef FastMixerStateQueue
+template class StateQueue<FastCaptureState>;    // typedef FastCaptureStateQueue
 
 }