summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-05-21 09:17:20 -0700
committerGlenn Kasten <gkasten@google.com>2012-05-21 12:36:06 -0700
commitfbae5dae5187aca9d974cbe15ec818e9c6f56705 (patch)
tree101ef33da2a18e0cb1c70a0e1ae085450dc60396
parentcd8a36fdc49a823f78d45e8e1a464dc261553b26 (diff)
downloadframeworks_av-fbae5dae5187aca9d974cbe15ec818e9c6f56705.zip
frameworks_av-fbae5dae5187aca9d974cbe15ec818e9c6f56705.tar.gz
frameworks_av-fbae5dae5187aca9d974cbe15ec818e9c6f56705.tar.bz2
Keep a copy of most recent audio played
Change-Id: I6b2f97881c39998a2fae9ab79d669af6c0a37e94
-rw-r--r--services/audioflinger/Android.mk4
-rw-r--r--services/audioflinger/AudioFlinger.cpp73
-rw-r--r--services/audioflinger/AudioFlinger.h3
-rw-r--r--services/audioflinger/FastMixer.cpp5
-rw-r--r--services/audioflinger/FastMixerState.cpp3
-rw-r--r--services/audioflinger/FastMixerState.h1
-rw-r--r--services/audioflinger/PipeReader.cpp4
7 files changed, 90 insertions, 3 deletions
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 0d7f06a..4f59a8a 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -85,4 +85,8 @@ LOCAL_CFLAGS += -DHAVE_REQUEST_PRIORITY -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
# uncomment for systrace
# LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO
+# uncomment for dumpsys to write most recent audio output to .wav file
+# 47.5 seconds at 44.1 kHz, 8 megabytes
+# LOCAL_CFLAGS += -DTEE_SINK_FRAMES=0x200000
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 339f6ea..3c60e5a 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -79,6 +79,8 @@
#include "AudioStreamOutSink.h"
#include "MonoPipe.h"
#include "MonoPipeReader.h"
+#include "Pipe.h"
+#include "PipeReader.h"
#include "SourceAudioBufferProvider.h"
#ifdef HAVE_REQUEST_PRIORITY
@@ -2217,6 +2219,20 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
ALOG_ASSERT(index == 0);
mPipeSink = monoPipe;
+#ifdef TEE_SINK_FRAMES
+ // create a Pipe to archive a copy of FastMixer's output for dumpsys
+ Pipe *teeSink = new Pipe(TEE_SINK_FRAMES, format);
+ numCounterOffers = 0;
+ index = teeSink->negotiate(offers, 1, NULL, numCounterOffers);
+ ALOG_ASSERT(index == 0);
+ mTeeSink = teeSink;
+ PipeReader *teeSource = new PipeReader(*teeSink);
+ numCounterOffers = 0;
+ index = teeSource->negotiate(offers, 1, NULL, numCounterOffers);
+ ALOG_ASSERT(index == 0);
+ mTeeSource = teeSource;
+#endif
+
#ifdef SOAKER
// create a soaker as workaround for governor issues
mSoaker = new Soaker();
@@ -2245,6 +2261,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
state->mColdFutexAddr = &mFastMixerFutex;
state->mColdGen++;
state->mDumpState = &mFastMixerDumpState;
+ state->mTeeSink = mTeeSink.get();
sq->end();
sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
@@ -3440,6 +3457,62 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
FastMixerDumpState copy = mFastMixerDumpState;
copy.dump(fd);
+ // Write the tee output to a .wav file
+ NBAIO_Source *teeSource = mTeeSource.get();
+ if (teeSource != NULL) {
+ char teePath[64];
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ struct tm tm;
+ localtime_r(&tv.tv_sec, &tm);
+ strftime(teePath, sizeof(teePath), "/data/misc/media/%T.wav", &tm);
+ int teeFd = open(teePath, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ if (teeFd >= 0) {
+ char wavHeader[44];
+ memcpy(wavHeader,
+ "RIFF\0\0\0\0WAVEfmt \20\0\0\0\1\0\2\0\104\254\0\0\0\0\0\0\4\0\20\0data\0\0\0\0",
+ sizeof(wavHeader));
+ NBAIO_Format format = teeSource->format();
+ unsigned channelCount = Format_channelCount(format);
+ ALOG_ASSERT(channelCount <= FCC_2);
+ unsigned sampleRate = Format_sampleRate(format);
+ wavHeader[22] = channelCount; // number of channels
+ wavHeader[24] = sampleRate; // sample rate
+ wavHeader[25] = sampleRate >> 8;
+ wavHeader[32] = channelCount * 2; // block alignment
+ write(teeFd, wavHeader, sizeof(wavHeader));
+ size_t total = 0;
+ bool firstRead = true;
+ for (;;) {
+#define TEE_SINK_READ 1024
+ short buffer[TEE_SINK_READ * FCC_2];
+ size_t count = TEE_SINK_READ;
+ ssize_t actual = teeSource->read(buffer, count);
+ bool wasFirstRead = firstRead;
+ firstRead = false;
+ if (actual <= 0) {
+ if (actual == (ssize_t) OVERRUN && wasFirstRead) {
+ continue;
+ }
+ break;
+ }
+ ALOG_ASSERT(actual <= count);
+ write(teeFd, buffer, actual * channelCount * sizeof(short));
+ total += actual;
+ }
+ lseek(teeFd, (off_t) 4, SEEK_SET);
+ uint32_t temp = 44 + total * channelCount * sizeof(short) - 8;
+ write(teeFd, &temp, sizeof(temp));
+ lseek(teeFd, (off_t) 40, SEEK_SET);
+ temp = total * channelCount * sizeof(short);
+ write(teeFd, &temp, sizeof(temp));
+ close(teeFd);
+ fdprintf(fd, "FastMixer tee copied to %s\n", teePath);
+ } else {
+ fdprintf(fd, "FastMixer unable to create tee %s: \n", strerror(errno));
+ }
+ }
+
return NO_ERROR;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index de3561d..1ae5414 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1111,6 +1111,9 @@ public:
sp<NBAIO_Sink> mPipeSink;
// The current sink for the normal mixer to write it's (sub)mix, mOutputSink or mPipeSink
sp<NBAIO_Sink> mNormalSink;
+ // For dumpsys
+ sp<NBAIO_Sink> mTeeSink;
+ sp<NBAIO_Source> mTeeSource;
public:
virtual bool hasFastMixer() const = 0;
virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index df9ec8e..52effb2 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -77,6 +77,7 @@ bool FastMixer::threadLoop()
bool isWarm = false; // true means ready to mix, false means wait for warmup before mixing
struct timespec measuredWarmupTs = {0, 0}; // how long did it take for warmup to complete
uint32_t warmupCycles = 0; // counter of number of loop cycles required to warmup
+ NBAIO_Sink* teeSink = NULL; // if non-NULL, then duplicate write() to this non-blocking sink
for (;;) {
@@ -106,6 +107,7 @@ bool FastMixer::threadLoop()
// As soon as possible of learning of a new dump area, start using it
dumpState = next->mDumpState != NULL ? next->mDumpState : &dummyDumpState;
+ teeSink = next->mTeeSink;
// We want to always have a valid reference to the previous (non-idle) state.
// However, the state queue only guarantees access to current and previous states.
@@ -398,6 +400,9 @@ bool FastMixer::threadLoop()
memset(mixBuffer, 0, frameCount * 2 * sizeof(short));
mixBufferState = ZEROED;
}
+ if (teeSink != NULL) {
+ (void) teeSink->write(mixBuffer, frameCount);
+ }
// FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
// but this code should be modified to handle both non-blocking and blocking sinks
dumpState->mWriteSequence++;
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 139a1c8..6305a83 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -30,7 +30,8 @@ FastTrack::~FastTrack()
FastMixerState::FastMixerState() :
mFastTracksGen(0), mTrackMask(0), mOutputSink(NULL), mOutputSinkGen(0),
- mFrameCount(0), mCommand(INITIAL), mColdFutexAddr(NULL), mColdGen(0), mDumpState(NULL)
+ mFrameCount(0), mCommand(INITIAL), mColdFutexAddr(NULL), mColdGen(0),
+ mDumpState(NULL), mTeeSink(NULL)
{
}
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index ce0cdb5..bc69c9c 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -76,6 +76,7 @@ struct FastMixerState {
unsigned mColdGen; // increment when COLD_IDLE is requested so it's only performed once
// This might be a one-time configuration rather than per-state
FastMixerDumpState* mDumpState; // if non-NULL, then update dump state periodically
+ NBAIO_Sink* mTeeSink; // if non-NULL, then duplicate write()s to this non-blocking sink
}; // struct FastMixerState
} // namespace android
diff --git a/services/audioflinger/PipeReader.cpp b/services/audioflinger/PipeReader.cpp
index 43bcb42..df3ee04 100644
--- a/services/audioflinger/PipeReader.cpp
+++ b/services/audioflinger/PipeReader.cpp
@@ -49,9 +49,9 @@ ssize_t PipeReader::availableToRead()
// read() is not multi-thread safe w.r.t. itself, so no mutex or atomic op needed to read mFront
size_t avail = rear - mFront;
if (CC_UNLIKELY(avail > mPipe.mMaxFrames)) {
- // Discard all but 3/4 of the most recent data in pipe to avoid another overrun immediately
+ // Discard 1/16 of the most recent data in pipe to avoid another overrun immediately
int32_t oldFront = mFront;
- mFront = rear - mPipe.mMaxFrames + (mPipe.mMaxFrames >> 2);
+ mFront = rear - mPipe.mMaxFrames + (mPipe.mMaxFrames >> 4);
mFramesOverrun += (size_t) (mFront - oldFront);
++mOverruns;
return OVERRUN;