summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/libmedia/AudioTrackShared.cpp15
-rw-r--r--services/audioflinger/AudioFlinger.h2
-rw-r--r--services/audioflinger/Threads.cpp277
-rw-r--r--services/audioflinger/Threads.h40
-rw-r--r--services/audioflinger/Tracks.cpp7
5 files changed, 317 insertions, 24 deletions
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 219dbfd..0dbfa62 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -134,10 +134,17 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques
ssize_t filled = rear - front;
// pipe should not be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
- ALOGE("Shared memory control block is corrupt (filled=%d); shutting down", filled);
- mIsShutdown = true;
- status = NO_INIT;
- goto end;
+ if (mIsOut) {
+ ALOGE("Shared memory control block is corrupt (filled=%d, mFrameCount=%u); "
+ "shutting down", filled, mFrameCount);
+ mIsShutdown = true;
+ status = NO_INIT;
+ goto end;
+ }
+ // for input, sync up on overrun
+ filled = 0;
+ cblk->u.mStreaming.mFront = rear;
+ (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
}
// don't allow filling pipe beyond the nominal size
size_t avail = mIsOut ? mFrameCount - filled : filled;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8d11e72..6e73a14 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -50,6 +50,8 @@
#include <media/AudioBufferProvider.h>
#include <media/ExtendedAudioBufferProvider.h>
+
+#include "FastCapture.h"
#include "FastMixer.h"
#include <media/nbaio/NBAIO.h>
#include "AudioWatchdog.h"
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 742163b..c986f9d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -38,6 +38,7 @@
#include <audio_utils/minifloat.h>
// NBAIO implementations
+#include <media/nbaio/AudioStreamInSource.h>
#include <media/nbaio/AudioStreamOutSink.h>
#include <media/nbaio/MonoPipe.h>
#include <media/nbaio/MonoPipeReader.h>
@@ -53,6 +54,7 @@
#include "AudioFlinger.h"
#include "AudioMixer.h"
#include "FastMixer.h"
+#include "FastCapture.h"
#include "ServiceUtilities.h"
#include "SchedulingPolicyService.h"
@@ -131,9 +133,17 @@ static const enum {
// up large writes into smaller ones, and the wrapper would need to deal with scheduler.
} kUseFastMixer = FastMixer_Static;
+// Whether to use fast capture
+static const enum {
+ FastCapture_Never, // never initialize or use: for debugging only
+ FastCapture_Always, // always initialize and use, even if not needed: for debugging only
+ FastCapture_Static, // initialize if needed, then use all the time if initialized
+} kUseFastCapture = FastCapture_Static;
+
// Priorities for requestPriority
static const int kPriorityAudioApp = 2;
static const int kPriorityFastMixer = 3;
+static const int kPriorityFastCapture = 3;
// IAudioFlinger::createTrack() reports back to client the total size of shared memory area
// for the track. The client then sub-divides this into smaller buffers for its use.
@@ -4760,16 +4770,151 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
#endif
, mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
"RecordThreadRO", MemoryHeapBase::READ_ONLY))
+ // mFastCapture below
+ , mFastCaptureFutex(0)
+ // mInputSource
+ // mPipeSink
+ // mPipeSource
+ , mPipeFramesP2(0)
+ // mPipeMemory
+ // mFastCaptureNBLogWriter
+ , mFastTrackAvail(true)
{
snprintf(mName, kNameLength, "AudioIn_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
readInputParameters_l();
+
+ // create an NBAIO source for the HAL input stream, and negotiate
+ mInputSource = new AudioStreamInSource(input->stream);
+ size_t numCounterOffers = 0;
+ const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)};
+ ssize_t index = mInputSource->negotiate(offers, 1, NULL, numCounterOffers);
+ ALOG_ASSERT(index == 0);
+
+ // initialize fast capture depending on configuration
+ bool initFastCapture;
+ switch (kUseFastCapture) {
+ case FastCapture_Never:
+ initFastCapture = false;
+ break;
+ case FastCapture_Always:
+ initFastCapture = true;
+ break;
+ case FastCapture_Static:
+ uint32_t primaryOutputSampleRate;
+ {
+ AutoMutex _l(audioFlinger->mHardwareLock);
+ primaryOutputSampleRate = audioFlinger->mPrimaryOutputSampleRate;
+ }
+ initFastCapture =
+ // either capture sample rate is same as (a reasonable) primary output sample rate
+ (((primaryOutputSampleRate == 44100 || primaryOutputSampleRate == 48000) &&
+ (mSampleRate == primaryOutputSampleRate)) ||
+ // or primary output sample rate is unknown, and capture sample rate is reasonable
+ ((primaryOutputSampleRate == 0) &&
+ ((mSampleRate == 44100 || mSampleRate == 48000)))) &&
+ // and the buffer size is < 10 ms
+ (mFrameCount * 1000) / mSampleRate < 10;
+ break;
+ // case FastCapture_Dynamic:
+ }
+
+ if (initFastCapture) {
+ // create a Pipe for FastMixer to write to, and for us and fast tracks to read from
+ NBAIO_Format format = mInputSource->format();
+ size_t pipeFramesP2 = roundup(mFrameCount * 8);
+ size_t pipeSize = pipeFramesP2 * Format_frameSize(format);
+ void *pipeBuffer;
+ const sp<MemoryDealer> roHeap(readOnlyHeap());
+ sp<IMemory> pipeMemory;
+ if ((roHeap == 0) ||
+ (pipeMemory = roHeap->allocate(pipeSize)) == 0 ||
+ (pipeBuffer = pipeMemory->pointer()) == NULL) {
+ ALOGE("not enough memory for pipe buffer size=%zu", pipeSize);
+ goto failed;
+ }
+ // pipe will be shared directly with fast clients, so clear to avoid leaking old information
+ memset(pipeBuffer, 0, pipeSize);
+ Pipe *pipe = new Pipe(pipeFramesP2, format, pipeBuffer);
+ const NBAIO_Format offers[1] = {format};
+ size_t numCounterOffers = 0;
+ ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
+ ALOG_ASSERT(index == 0);
+ mPipeSink = pipe;
+ PipeReader *pipeReader = new PipeReader(*pipe);
+ numCounterOffers = 0;
+ index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
+ ALOG_ASSERT(index == 0);
+ mPipeSource = pipeReader;
+ mPipeFramesP2 = pipeFramesP2;
+ mPipeMemory = pipeMemory;
+
+ // create fast capture
+ mFastCapture = new FastCapture();
+ FastCaptureStateQueue *sq = mFastCapture->sq();
+#ifdef STATE_QUEUE_DUMP
+ // FIXME
+#endif
+ FastCaptureState *state = sq->begin();
+ state->mCblk = NULL;
+ state->mInputSource = mInputSource.get();
+ state->mInputSourceGen++;
+ state->mPipeSink = pipe;
+ state->mPipeSinkGen++;
+ state->mFrameCount = mFrameCount;
+ state->mCommand = FastCaptureState::COLD_IDLE;
+ // already done in constructor initialization list
+ //mFastCaptureFutex = 0;
+ state->mColdFutexAddr = &mFastCaptureFutex;
+ state->mColdGen++;
+ state->mDumpState = &mFastCaptureDumpState;
+#ifdef TEE_SINK
+ // FIXME
+#endif
+ mFastCaptureNBLogWriter = audioFlinger->newWriter_l(kFastCaptureLogSize, "FastCapture");
+ state->mNBLogWriter = mFastCaptureNBLogWriter.get();
+ sq->end();
+ sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+
+ // start the fast capture
+ mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
+ pid_t tid = mFastCapture->getTid();
+ int err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
+ if (err != 0) {
+ ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
+ kPriorityFastCapture, getpid_cached, tid, err);
+ }
+
+#ifdef AUDIO_WATCHDOG
+ // FIXME
+#endif
+
+ }
+failed: ;
+
+ // FIXME mNormalSource
}
AudioFlinger::RecordThread::~RecordThread()
{
+ if (mFastCapture != 0) {
+ FastCaptureStateQueue *sq = mFastCapture->sq();
+ FastCaptureState *state = sq->begin();
+ if (state->mCommand == FastCaptureState::COLD_IDLE) {
+ int32_t old = android_atomic_inc(&mFastCaptureFutex);
+ if (old == -1) {
+ (void) syscall(__NR_futex, &mFastCaptureFutex, FUTEX_WAKE_PRIVATE, 1);
+ }
+ }
+ state->mCommand = FastCaptureState::EXIT;
+ sq->end();
+ sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+ mFastCapture->join();
+ mFastCapture.clear();
+ }
+ mAudioFlinger->unregisterWriter(mFastCaptureNBLogWriter);
mAudioFlinger->unregisterWriter(mNBLogWriter);
delete[] mRsmpInBuffer;
}
@@ -4824,6 +4969,8 @@ reacquire_wakelock:
// activeTracks accumulates a copy of a subset of mActiveTracks
Vector< sp<RecordTrack> > activeTracks;
+ // reference to the (first and only) fast track
+ sp<RecordTrack> fastTrack;
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -4905,6 +5052,11 @@ reacquire_wakelock:
activeTracks.add(activeTrack);
i++;
+ if (activeTrack->isFastTrack()) {
+ ALOG_ASSERT(!mFastTrackAvail);
+ ALOG_ASSERT(fastTrack == 0);
+ fastTrack = activeTrack;
+ }
}
if (doBroadcast) {
mStartStopCond.broadcast();
@@ -4930,6 +5082,36 @@ reacquire_wakelock:
effectChains[i]->process_l();
}
+ // Start the fast capture if it's not already running
+ if (mFastCapture != 0) {
+ FastCaptureStateQueue *sq = mFastCapture->sq();
+ FastCaptureState *state = sq->begin();
+ if (state->mCommand != FastCaptureState::READ_WRITE /* FIXME &&
+ (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)*/) {
+ if (state->mCommand == FastCaptureState::COLD_IDLE) {
+ int32_t old = android_atomic_inc(&mFastCaptureFutex);
+ if (old == -1) {
+ (void) syscall(__NR_futex, &mFastCaptureFutex, FUTEX_WAKE_PRIVATE, 1);
+ }
+ }
+ state->mCommand = FastCaptureState::READ_WRITE;
+#if 0 // FIXME
+ mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
+ FastCaptureDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
+#endif
+ state->mCblk = fastTrack != 0 ? fastTrack->cblk() : NULL;
+ sq->end();
+ sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+#if 0
+ if (kUseFastCapture == FastCapture_Dynamic) {
+ mNormalSource = mPipeSource;
+ }
+#endif
+ } else {
+ sq->end(false /*didModify*/);
+ }
+ }
+
// Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
// Only the client(s) that are too slow will overrun. But if even the fastest client is too
// slow, then this RecordThread will overrun by not calling HAL read often enough.
@@ -4937,24 +5119,45 @@ reacquire_wakelock:
// copy to the right place. Permitted because mRsmpInBuffer was over-allocated.
int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
- ssize_t bytesRead = mInput->stream->read(mInput->stream,
- &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
- if (bytesRead <= 0) {
- ALOGE("read failed: bytesRead=%d < %u", bytesRead, mBufferSize);
+ ssize_t framesRead;
+
+ // If an NBAIO source is present, use it to read the normal capture's data
+ if (mPipeSource != 0) {
+ size_t framesToRead = mBufferSize / mFrameSize;
+ framesRead = mPipeSource->read(&mRsmpInBuffer[rear * mChannelCount],
+ framesToRead, AudioBufferProvider::kInvalidPTS);
+ if (framesRead == 0) {
+ // since pipe is non-blocking, simulate blocking input
+ sleepUs = (framesToRead * 1000000LL) / mSampleRate;
+ }
+ // otherwise use the HAL / AudioStreamIn directly
+ } else {
+ ssize_t bytesRead = mInput->stream->read(mInput->stream,
+ &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
+ if (bytesRead < 0) {
+ framesRead = bytesRead;
+ } else {
+ framesRead = bytesRead / mFrameSize;
+ }
+ }
+
+ if (framesRead < 0 || (framesRead == 0 && mPipeSource == 0)) {
+ ALOGE("read failed: framesRead=%d", framesRead);
// Force input into standby so that it tries to recover at next read attempt
inputStandBy();
sleepUs = kRecordThreadSleepUs;
+ }
+ if (framesRead <= 0) {
continue;
}
- ALOG_ASSERT((size_t) bytesRead <= mBufferSize);
- size_t framesRead = bytesRead / mFrameSize;
ALOG_ASSERT(framesRead > 0);
+
if (mTeeSink != 0) {
(void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead);
}
// If destination is non-contiguous, we now correct for reading past end of buffer.
size_t part1 = mRsmpInFramesP2 - rear;
- if (framesRead > part1) {
+ if ((size_t) framesRead > part1) {
memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
(framesRead - part1) * mFrameSize);
}
@@ -4965,6 +5168,11 @@ reacquire_wakelock:
for (size_t i = 0; i < size; i++) {
activeTrack = activeTracks[i];
+ // skip fast tracks, as those are handled directly by FastCapture
+ if (activeTrack->isFastTrack()) {
+ continue;
+ }
+
enum {
OVERRUN_UNKNOWN,
OVERRUN_TRUE,
@@ -5193,6 +5401,30 @@ void AudioFlinger::RecordThread::standbyIfNotAlreadyInStandby()
void AudioFlinger::RecordThread::inputStandBy()
{
+ // Idle the fast capture if it's currently running
+ if (mFastCapture != 0) {
+ FastCaptureStateQueue *sq = mFastCapture->sq();
+ FastCaptureState *state = sq->begin();
+ if (!(state->mCommand & FastCaptureState::IDLE)) {
+ state->mCommand = FastCaptureState::COLD_IDLE;
+ state->mColdFutexAddr = &mFastCaptureFutex;
+ state->mColdGen++;
+ mFastCaptureFutex = 0;
+ sq->end();
+ // BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now
+ sq->push(FastCaptureStateQueue::BLOCK_UNTIL_ACKED);
+#if 0
+ if (kUseFastCapture == FastCapture_Dynamic) {
+ // FIXME
+ }
+#endif
+#ifdef AUDIO_WATCHDOG
+ // FIXME
+#endif
+ } else {
+ sq->end(false /*didModify*/);
+ }
+ }
mInput->stream->common.standby(&mInput->stream->common);
}
@@ -5219,36 +5451,40 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
// use case: callback handler and frame count is default or at least as large as HAL
(
(tid != -1) &&
- ((frameCount == 0) ||
+ ((frameCount == 0) /*||
+ // FIXME must be equal to pipe depth, so don't allow it to be specified by client
// FIXME not necessarily true, should be native frame count for native SR!
- (frameCount >= mFrameCount))
+ (frameCount >= mFrameCount)*/)
) &&
// PCM data
audio_is_linear_pcm(format) &&
+ // native format
+ (format == mFormat) &&
// mono or stereo
( (channelMask == AUDIO_CHANNEL_IN_MONO) ||
(channelMask == AUDIO_CHANNEL_IN_STEREO) ) &&
- // hardware sample rate
- // FIXME actually the native hardware sample rate
+ // native channel mask
+ (channelMask == mChannelMask) &&
+ // native hardware sample rate
(sampleRate == mSampleRate) &&
// record thread has an associated fast capture
- hasFastCapture()
- // fast capture does not require slots
+ hasFastCapture() &&
+ // there are sufficient fast track slots available
+ mFastTrackAvail
) {
- // if frameCount not specified, then it defaults to fast capture (HAL) frame count
+ // if frameCount not specified, then it defaults to pipe frame count
if (frameCount == 0) {
- // FIXME wrong mFrameCount
- frameCount = mFrameCount * kFastTrackMultiplier;
+ frameCount = mPipeFramesP2;
}
ALOGV("AUDIO_INPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
frameCount, mFrameCount);
} else {
ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%d "
"mFrameCount=%d format=%d isLinear=%d channelMask=%#x sampleRate=%u mSampleRate=%u "
- "hasFastCapture=%d tid=%d",
+ "hasFastCapture=%d tid=%d mFastTrackAvail=%d",
frameCount, mFrameCount, format,
audio_is_linear_pcm(format),
- channelMask, sampleRate, mSampleRate, hasFastCapture(), tid);
+ channelMask, sampleRate, mSampleRate, hasFastCapture(), tid, mFastTrackAvail);
*flags &= ~IAudioFlinger::TRACK_FAST;
// FIXME It's not clear that we need to enforce this any more, since we have a pipe.
// For compatibility with AudioRecord calculation, buffer depth is forced
@@ -5477,6 +5713,10 @@ void AudioFlinger::RecordThread::removeTrack_l(const sp<RecordTrack>& track)
{
mTracks.remove(track);
// need anything related to effects here?
+ if (track->isFastTrack()) {
+ ALOG_ASSERT(!mFastTrackAvail);
+ mFastTrackAvail = true;
+ }
}
void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
@@ -5495,6 +5735,7 @@ void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& a
} else {
dprintf(fd, " No active record clients\n");
}
+ dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
dumpBase(fd, args);
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8c9943c..07887fb 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1064,6 +1064,8 @@ public:
virtual sp<MemoryDealer> readOnlyHeap() const { return mReadOnlyHeap; }
+ virtual sp<IMemory> pipeMemory() const { return mPipeMemory; }
+
sp<AudioFlinger::RecordThread::RecordTrack> createRecordTrack_l(
const sp<AudioFlinger::Client>& client,
uint32_t sampleRate,
@@ -1115,7 +1117,7 @@ public:
static void syncStartEventCallback(const wp<SyncEvent>& event);
virtual size_t frameCount() const { return mFrameCount; }
- bool hasFastCapture() const { return false; }
+ bool hasFastCapture() const { return mFastCapture != 0; }
private:
// Enter standby if not already in standby, and set mStandby flag
@@ -1145,4 +1147,40 @@ private:
const sp<NBAIO_Sink> mTeeSink;
const sp<MemoryDealer> mReadOnlyHeap;
+
+ // one-time initialization, no locks required
+ sp<FastCapture> mFastCapture; // non-0 if there is also a fast capture
+ // FIXME audio watchdog thread
+
+ // contents are not guaranteed to be consistent, no locks required
+ FastCaptureDumpState mFastCaptureDumpState;
+#ifdef STATE_QUEUE_DUMP
+ // FIXME StateQueue observer and mutator dump fields
+#endif
+ // FIXME audio watchdog dump
+
+ // accessible only within the threadLoop(), no locks required
+ // mFastCapture->sq() // for mutating and pushing state
+ int32_t mFastCaptureFutex; // for cold idle
+
+ // The HAL input source is treated as non-blocking,
+ // but current implementation is blocking
+ sp<NBAIO_Source> mInputSource;
+ // The source for the normal capture thread to read from: mInputSource or mPipeSource
+ sp<NBAIO_Source> mNormalSource;
+ // If a fast capture is present, the non-blocking pipe sink written to by fast capture,
+ // otherwise clear
+ sp<NBAIO_Sink> mPipeSink;
+ // If a fast capture is present, the non-blocking pipe source read by normal thread,
+ // otherwise clear
+ sp<NBAIO_Source> mPipeSource;
+ // Depth of pipe from fast capture to normal thread and fast clients, always power of 2
+ size_t mPipeFramesP2;
+ // If a fast capture is present, the Pipe as IMemory, otherwise clear
+ sp<IMemory> mPipeMemory;
+
+ static const size_t kFastCaptureLogSize = 4 * 1024;
+ sp<NBLog::Writer> mFastCaptureNBLogWriter;
+
+ bool mFastTrackAvail; // true if fast track available
};
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 7ddc71c..8a51213 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1854,7 +1854,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
: TrackBase(thread, client, sampleRate, format,
channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid,
flags, false /*isOut*/,
- (flags & IAudioFlinger::TRACK_FAST) != 0 ? ALLOC_READONLY : ALLOC_CBLK),
+ flags & IAudioFlinger::TRACK_FAST ? ALLOC_PIPE : ALLOC_CBLK),
mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0),
// See real initialization of mRsmpInFront at RecordThread::start()
mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
@@ -1876,6 +1876,11 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
mResamplerBufferProvider = new ResamplerBufferProvider(this);
}
+
+ if (flags & IAudioFlinger::TRACK_FAST) {
+ ALOG_ASSERT(thread->mFastTrackAvail);
+ thread->mFastTrackAvail = false;
+ }
}
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()