Keep a copy of most recent audio played
Change-Id: I6b2f97881c39998a2fae9ab79d669af6c0a37e94
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 @@
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 @@
state->mColdFutexAddr = &mFastMixerFutex;
state->mColdGen++;
state->mDumpState = &mFastMixerDumpState;
+ state->mTeeSink = mTeeSink.get();
sq->end();
sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
@@ -3440,6 +3457,62 @@
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;
}