Merge "ToneGenerator requests fast track"
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 07c7be5..a09f971 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -19,7 +19,9 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 #include <utils/Vector.h>
 
 namespace android {
@@ -38,7 +40,11 @@
 
     NuMediaExtractor();
 
-    status_t setDataSource(const char *path);
+    status_t setDataSource(
+            const char *path,
+            const KeyedVector<String8, String8> *headers = NULL);
+
+    status_t setDataSource(int fd, off64_t offset, off64_t size);
 
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format) const;
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index cb5c7f3..58c6d38 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -93,7 +93,10 @@
         } break;
         case START: {
             CHECK_INTERFACE(IAudioRecord, data, reply);
-            reply->writeInt32(start(data.readInt32(), data.readInt32(), data.readInt32()));
+            pid_t tid = (pid_t) data.readInt32();
+            int event = data.readInt32();
+            int triggerSession = data.readInt32();
+            reply->writeInt32(start(tid, event, triggerSession));
             return NO_ERROR;
         } break;
         case STOP: {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index d0a7880..aba95bc 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -142,7 +142,19 @@
         if (httpSource->connect(uri, headers) != OK) {
             return NULL;
         }
-        source = new NuCachedSource2(httpSource);
+
+        String8 cacheConfig;
+        bool disconnectAtHighwatermark;
+        if (headers != NULL) {
+            KeyedVector<String8, String8> copy = *headers;
+            NuCachedSource2::RemoveCacheSpecificHeaders(
+                    &copy, &cacheConfig, &disconnectAtHighwatermark);
+        }
+
+        source = new NuCachedSource2(
+                httpSource,
+                cacheConfig.isEmpty() ? NULL : cacheConfig.string());
+
 # if CHROMIUM_AVAILABLE
     } else if (!strncasecmp("data:", uri, 5)) {
         source = new DataUriSource(uri);
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 224ec33..8758c93 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -26,6 +26,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -51,8 +52,13 @@
     mSelectedTracks.clear();
 }
 
-status_t NuMediaExtractor::setDataSource(const char *path) {
-    sp<DataSource> dataSource = DataSource::CreateFromURI(path);
+status_t NuMediaExtractor::setDataSource(
+        const char *path, const KeyedVector<String8, String8> *headers) {
+    if (mImpl != NULL) {
+        return -EINVAL;
+    }
+
+    sp<DataSource> dataSource = DataSource::CreateFromURI(path, headers);
 
     if (dataSource == NULL) {
         return -ENOENT;
@@ -67,6 +73,27 @@
     return OK;
 }
 
+status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
+    if (mImpl != NULL) {
+        return -EINVAL;
+    }
+
+    sp<FileSource> fileSource = new FileSource(dup(fd), offset, size);
+
+    status_t err = fileSource->initCheck();
+    if (err != OK) {
+        return err;
+    }
+
+    mImpl = MediaExtractor::Create(fileSource);
+
+    if (mImpl == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    return OK;
+}
+
 size_t NuMediaExtractor::countTracks() const {
     return mImpl == NULL ? 0 : mImpl->countTracks();
 }
@@ -91,6 +118,11 @@
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
 
+    int64_t durationUs;
+    if (meta->findInt64(kKeyDuration, &durationUs)) {
+        msg->setInt64("durationUs", durationUs);
+    }
+
     if (!strncasecmp("video/", mime, 6)) {
         int32_t width, height;
         CHECK(meta->findInt32(kKeyWidth, &width));
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9b4fb7a..d0611b0 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -4045,11 +4045,11 @@
     uint32_t bufBytes        = buf.buffer()->size();
     uint32_t consumedAlready = buf.position();
 
-    ALOG_ASSERT(consumedAlready <= bufFrames,
+    ALOG_ASSERT(consumedAlready <= bufBytes,
                 "Bad bookkeeping while updating frames pending.  Timed buffer is"
                 " only %u bytes long, but claims to have consumed %u"
                 " bytes.  (update reason: \"%s\")",
-                bufFrames, consumedAlready, logTag);
+                bufBytes, consumedAlready, logTag);
 
     uint32_t bufFrames = (bufBytes - consumedAlready) / mCblk->frameSize;
     ALOG_ASSERT(mFramesPendingInQueue >= bufFrames,
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 399d987..100f289 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -119,6 +119,7 @@
     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
         // FIXME redundant per track
         t->localTimeFreq = lc.getLocalFreq();
+        t->resampler = NULL;
         t++;
     }
 
@@ -326,15 +327,9 @@
         track.enabled = false;
         invalidateState(1<<name);
     }
-    if (track.resampler != NULL) {
-        // delete the resampler
-        delete track.resampler;
-        track.resampler = NULL;
-        track.sampleRate = mSampleRate;
-        invalidateState(1<<name);
-    }
-    track.volumeInc[0] = 0;
-    track.volumeInc[1] = 0;
+    // delete the resampler
+    delete track.resampler;
+    track.resampler = NULL;
     mTrackNames &= ~(1<<name);
 }
 
@@ -438,6 +433,12 @@
             track.resetResampler();
             invalidateState(1 << name);
             break;
+        case REMOVE:
+            delete track.resampler;
+            track.resampler = NULL;
+            track.sampleRate = mSampleRate;
+            invalidateState(1 << name);
+            break;
         default:
             LOG_FATAL("bad param");
         }
@@ -498,7 +499,7 @@
 
 bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
 {
-    if (value!=devSampleRate || resampler) {
+    if (value != devSampleRate || resampler != NULL) {
         if (sampleRate != value) {
             sampleRate = value;
             if (resampler == NULL) {
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index a04fe95..9698d0c 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -70,8 +70,17 @@
         AUX_BUFFER      = 0x4003,
         DOWNMIX_TYPE    = 0X4004,
         // for target RESAMPLE
-        SAMPLE_RATE     = 0x4100,
-        RESET           = 0x4101,
+        SAMPLE_RATE     = 0x4100, // Configure sample rate conversion on this track name;
+                                  // parameter 'value' is the new sample rate in Hz.
+                                  // Only creates a sample rate converter the first time that
+                                  // the track sample rate is different from the mix sample rate.
+                                  // If the new sample rate is the same as the mix sample rate,
+                                  // and a sample rate converter already exists,
+                                  // then the sample rate converter remains present but is a no-op.
+        RESET           = 0x4101, // Reset sample rate converter without changing sample rate.
+                                  // This clears out the resampler's input buffer.
+        REMOVE          = 0x4102, // Remove the sample rate converter on this track name;
+                                  // the track is restored to the mix sample rate.
         // for target RAMP_VOLUME and VOLUME (8 channels max)
         VOLUME0         = 0x4200,
         VOLUME1         = 0x4201,
@@ -237,7 +246,10 @@
     // indicates whether a downmix effect has been found and is usable by this mixer
     static bool                isMultichannelCapable;
 
+    // Call after changing either the enabled status of a track, or parameters of an enabled track.
+    // OK to call more often than that, but unnecessary.
     void invalidateState(uint32_t mask);
+
     static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
 
     static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);