Merge "Add the ability to query the amount of cached data to NuMediaExtractor."
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index d52ed42..4667649 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -64,7 +64,7 @@
 
 LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp
 
-#LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS
+LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS
 
 LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 99dcf45..bce30d7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3994,20 +3994,38 @@
 
     size_t trimEnd;
     for (trimEnd = 0; trimEnd < mTimedBufferQueue.size(); trimEnd++) {
-        int64_t frameCount = mTimedBufferQueue[trimEnd].buffer()->size()
-                           / mCblk->frameSize;
         int64_t bufEnd;
 
-        if (!mMediaTimeToSampleTransform.doReverseTransform(frameCount,
-                                                            &bufEnd)) {
-            ALOGE("Failed to convert frame count of %lld to media time duration"
-                  " (scale factor %d/%u) in %s", frameCount,
-                  mMediaTimeToSampleTransform.a_to_b_numer,
-                  mMediaTimeToSampleTransform.a_to_b_denom,
-                  __PRETTY_FUNCTION__);
-            break;
+        if ((trimEnd + 1) < mTimedBufferQueue.size()) {
+            // We have a next buffer.  Just use its PTS as the PTS of the frame
+            // following the last frame in this buffer.  If the stream is sparse
+            // (ie, there are deliberate gaps left in the stream which should be
+            // filled with silence by the TimedAudioTrack), then this can result
+            // in one extra buffer being left un-trimmed when it could have
+            // been.  In general, this is not typical, and we would rather
+            // optimized away the TS calculation below for the more common case
+            // where PTSes are contiguous.
+            bufEnd = mTimedBufferQueue[trimEnd + 1].pts();
+        } else {
+            // We have no next buffer.  Compute the PTS of the frame following
+            // the last frame in this buffer by computing the duration of of
+            // this frame in media time units and adding it to the PTS of the
+            // buffer.
+            int64_t frameCount = mTimedBufferQueue[trimEnd].buffer()->size()
+                               / mCblk->frameSize;
+
+            if (!mMediaTimeToSampleTransform.doReverseTransform(frameCount,
+                                                                &bufEnd)) {
+                ALOGE("Failed to convert frame count of %lld to media time"
+                      " duration" " (scale factor %d/%u) in %s",
+                      frameCount,
+                      mMediaTimeToSampleTransform.a_to_b_numer,
+                      mMediaTimeToSampleTransform.a_to_b_denom,
+                      __PRETTY_FUNCTION__);
+                break;
+            }
+            bufEnd += mTimedBufferQueue[trimEnd].pts();
         }
-        bufEnd += mTimedBufferQueue[trimEnd].pts();
 
         if (bufEnd > mediaTimeNow)
             break;
@@ -4111,6 +4129,7 @@
     if (pts == AudioBufferProvider::kInvalidPTS) {
         buffer->raw = 0;
         buffer->frameCount = 0;
+        mTimedAudioOutputOnTime = false;
         return INVALID_OPERATION;
     }
 
@@ -4203,14 +4222,14 @@
         // the current output position is within this threshold, then we will
         // concatenate the next input samples to the previous output
         const int64_t kSampleContinuityThreshold =
-                (static_cast<int64_t>(sampleRate()) << 32) / 10;
+                (static_cast<int64_t>(sampleRate()) << 32) / 250;
 
         // if this is the first buffer of audio that we're emitting from this track
         // then it should be almost exactly on time.
         const int64_t kSampleStartupThreshold = 1LL << 32;
 
         if ((mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleContinuityThreshold) ||
-            (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) {
+           (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) {
             // the next input is close enough to being on time, so concatenate it
             // with the last output
             timedYieldSamples_l(buffer);
@@ -4218,7 +4237,13 @@
             ALOGVV("*** on time: head.pos=%d frameCount=%u",
                     head.position(), buffer->frameCount);
             return NO_ERROR;
-        } else if (sampleDelta > 0) {
+        }
+
+        // Looks like our output is not on time.  Reset our on timed status.
+        // Next time we mix samples from our input queue, then should be within
+        // the StartupThreshold.
+        mTimedAudioOutputOnTime = false;
+        if (sampleDelta > 0) {
             // the gap between the current output position and the proper start of
             // the next input sample is too big, so fill it with silence
             uint32_t framesUntilNextInput = (sampleDelta + 0x80000000) >> 32;
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 14954f7..841b06a 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -130,6 +130,7 @@
             continue;
         case FastMixerState::COLD_IDLE:
             // only perform a cold idle command once
+            // FIXME consider checking previous state and only perform if previous != COLD_IDLE
             if (current->mColdGen != coldGen) {
                 int32_t *coldFutexAddr = current->mColdFutexAddr;
                 ALOG_ASSERT(coldFutexAddr != NULL);
@@ -176,6 +177,7 @@
                     sampleRate = Format_sampleRate(format);
                     ALOG_ASSERT(Format_channelCount(format) == 2);
                 }
+                dumpState->mSampleRate = sampleRate;
             }
 
             if ((format != previousFormat) || (frameCount != previous->mFrameCount)) {
@@ -207,6 +209,7 @@
                 // we need to reconfigure all active tracks
                 previousTrackMask = 0;
                 fastTracksGen = current->mFastTracksGen - 1;
+                dumpState->mFrameCount = frameCount;
             } else {
                 previousTrackMask = previous->mTrackMask;
             }
@@ -251,6 +254,12 @@
                         mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
                                 (void *) mixBuffer);
                         // newly allocated track names default to full scale volume
+                        if (fastTrack->mSampleRate != 0 && fastTrack->mSampleRate != sampleRate) {
+                            mixer->setParameter(name, AudioMixer::RESAMPLE,
+                                    AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate);
+                        }
+                        mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
+                                (void *) fastTrack->mChannelMask);
                         mixer->enable(name);
                     }
                     generations[i] = fastTrack->mGeneration;
@@ -276,6 +285,16 @@
                                 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
                                         (void *)0x1000);
                             }
+                            if (fastTrack->mSampleRate != 0 &&
+                                    fastTrack->mSampleRate != sampleRate) {
+                                mixer->setParameter(name, AudioMixer::RESAMPLE,
+                                        AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate);
+                            } else {
+                                mixer->setParameter(name, AudioMixer::RESAMPLE,
+                                        AudioMixer::REMOVE, NULL);
+                            }
+                            mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
+                                    (void *) fastTrack->mChannelMask);
                             // already enabled
                         }
                         generations[i] = fastTrack->mGeneration;
@@ -401,7 +420,8 @@
 
 FastMixerDumpState::FastMixerDumpState() :
     mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
-    mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0)
+    mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0),
+    mSampleRate(0), mFrameCount(0)
 #ifdef FAST_MIXER_STATISTICS
     , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0)
 #endif
@@ -443,9 +463,11 @@
         break;
     }
     fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n"
-                 "          numTracks=%u writeErrors=%u underruns=%u overruns=%u\n",
+                 "          numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
+                 "          sampleRate=%u frameCount=%u\n",
                  string, mWriteSequence, mFramesWritten,
-                 mNumTracks, mWriteErrors, mUnderruns, mOverruns);
+                 mNumTracks, mWriteErrors, mUnderruns, mOverruns,
+                 mSampleRate, mFrameCount);
 #ifdef FAST_MIXER_STATISTICS
     fdprintf(fd, "          cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
                  mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3);
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index b24f2eb..8a8fcb8 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -58,6 +58,8 @@
     uint32_t mWriteErrors;      // total number of write() errors
     uint32_t mUnderruns;        // total number of underruns
     uint32_t mOverruns;         // total number of overruns
+    uint32_t mSampleRate;
+    size_t   mFrameCount;
 #ifdef FAST_MIXER_STATISTICS
     // cycle times in seconds
     float    mMean;
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index 4eacacf..139a1c8 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -19,7 +19,8 @@
 namespace android {
 
 FastTrack::FastTrack() :
-    mBufferProvider(NULL), mVolumeProvider(NULL), mGeneration(0)
+    mBufferProvider(NULL), mVolumeProvider(NULL), mSampleRate(0),
+    mChannelMask(AUDIO_CHANNEL_OUT_STEREO), mGeneration(0)
 {
 }
 
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 64171ac..83094c8 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AUDIO_FAST_MIXER_STATE_H
 #define ANDROID_AUDIO_FAST_MIXER_STATE_H
 
+#include <system/audio.h>
 #include "AudioBufferProvider.h"
 #include "NBAIO.h"
 
@@ -41,6 +42,8 @@
 
     AudioBufferProvider*    mBufferProvider; // must not be NULL
     VolumeProvider*         mVolumeProvider; // optional; if NULL then full-scale
+    unsigned                mSampleRate;     // optional; if zero then use mixer sample rate
+    audio_channel_mask_t    mChannelMask;    // AUDIO_CHANNEL_OUT_MONO or AUDIO_CHANNEL_OUT_STEREO
     int                     mGeneration;     // increment when any field is assigned
 };