From f91df1b368a140abd37c80b204bd48d78778cc43 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Thu, 13 Mar 2014 14:59:31 -0700 Subject: [PATCH] Start adding FastCapture based on FastThread WIP This version supports at most one fast capture client. Change-Id: Idf609bfc80ae22433433d66a5232c043c65506df --- services/audioflinger/Android.mk | 1 + services/audioflinger/FastCapture.cpp | 222 +++++++++++++++++++++ services/audioflinger/FastCapture.h | 78 ++++++++ services/audioflinger/FastCaptureState.cpp | 30 +++ services/audioflinger/FastCaptureState.h | 51 +++++ services/audioflinger/StateQueueInstantiations.cpp | 4 +- 6 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 services/audioflinger/FastCapture.cpp create mode 100644 services/audioflinger/FastCapture.h create mode 100644 services/audioflinger/FastCaptureState.cpp create mode 100644 services/audioflinger/FastCaptureState.h diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 8d0a70547b..3b128cf135 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -63,6 +63,7 @@ LOCAL_32_BIT_ONLY := true 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 0000000000..0c9b9767e4 --- /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 +#include +#include +#include +#include +#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 0000000000..e535b9dfcb --- /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 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 0000000000..1d029b7a2a --- /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 0000000000..29c865a09e --- /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 +#include "FastThreadState.h" +#include + +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 0d5cd0c48f..6f4505e3e1 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; // typedef FastMixerStateQueue +template class StateQueue; // typedef FastMixerStateQueue +template class StateQueue; // typedef FastCaptureStateQueue } -- 2.11.0