summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/FastCapture.cpp
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2014-03-13 14:59:31 -0700
committerGlenn Kasten <gkasten@google.com>2014-05-22 16:19:08 -0700
commitf91df1b368a140abd37c80b204bd48d78778cc43 (patch)
tree238d896ad29af48d8ee069e853ee9fa1035955cc /services/audioflinger/FastCapture.cpp
parent29b703eec27b305e7b5b2343bf257643e38f6b68 (diff)
downloadframeworks_av-f91df1b368a140abd37c80b204bd48d78778cc43.zip
frameworks_av-f91df1b368a140abd37c80b204bd48d78778cc43.tar.gz
frameworks_av-f91df1b368a140abd37c80b204bd48d78778cc43.tar.bz2
Start adding FastCapture based on FastThread WIP
This version supports at most one fast capture client. Change-Id: Idf609bfc80ae22433433d66a5232c043c65506df
Diffstat (limited to 'services/audioflinger/FastCapture.cpp')
-rw-r--r--services/audioflinger/FastCapture.cpp222
1 files changed, 222 insertions, 0 deletions
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