Keep a copy of most recent audio played

Change-Id: I6b2f97881c39998a2fae9ab79d669af6c0a37e94
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 @@
 # 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 @@
         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;
 }
 
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 @@
         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 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 @@
 
             // 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 @@
                 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 @@
 
 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 @@
     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 @@
     // 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;