Merge "- Support comfort noise in AMRExtractor - Support duration and seeking in AMRExtractor for different bit rates"
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 11ac56c..89b3dab 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -378,14 +378,11 @@
 }
 
 void AwesomePlayer::reset() {
-    LOGI("reset");
-
     Mutex::Autolock autoLock(mLock);
     reset_l();
 }
 
 void AwesomePlayer::reset_l() {
-    LOGI("reset_l");
     mDisplayWidth = 0;
     mDisplayHeight = 0;
 
@@ -411,10 +408,6 @@
         }
     }
 
-    if (mFlags & PREPARING) {
-        LOGI("waiting until preparation is completes.");
-    }
-
     while (mFlags & PREPARING) {
         mPreparedCondition.wait(mLock);
     }
@@ -438,8 +431,6 @@
     }
     mAudioSource.clear();
 
-    LOGI("audio source cleared");
-
     mTimeSource = NULL;
 
     delete mAudioPlayer;
@@ -480,8 +471,6 @@
         IPCThreadState::self()->flushCommands();
     }
 
-    LOGI("video source cleared");
-
     mDurationUs = -1;
     mFlags = 0;
     mExtractorFlags = 0;
@@ -498,8 +487,6 @@
     mFileSource.clear();
 
     mBitrate = -1;
-
-    LOGI("reset_l completed");
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index c6c36e3..0bed3ca 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -51,6 +51,7 @@
       mNumRetries(0),
       mDurationUs(-1),
       mSeekDone(false),
+      mDisconnectPending(false),
       mMonitorQueueGeneration(0) {
 }
 
@@ -68,6 +69,11 @@
 }
 
 void LiveSession::disconnect() {
+    Mutex::Autolock autoLock(mLock);
+    mDisconnectPending = true;
+
+    mHTTPDataSource->disconnect();
+
     (new AMessage(kWhatDisconnect, id()))->post();
 }
 
@@ -138,7 +144,13 @@
     mMasterURL = url;
 
     sp<M3UParser> playlist = fetchPlaylist(url.c_str());
-    CHECK(playlist != NULL);
+
+    if (playlist == NULL) {
+        LOGE("unable to fetch master playlist '%s'.", url.c_str());
+
+        mDataSource->queueEOS(ERROR_IO);
+        return;
+    }
 
     if (playlist->isVariantPlaylist()) {
         for (size_t i = 0; i < playlist->size(); ++i) {
@@ -177,6 +189,9 @@
     LOGI("onDisconnect");
 
     mDataSource->queueEOS(ERROR_END_OF_STREAM);
+
+    Mutex::Autolock autoLock(mLock);
+    mDisconnectPending = false;
 }
 
 status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) {
@@ -189,6 +204,14 @@
     } else if (strncasecmp(url, "http://", 7)) {
         return ERROR_UNSUPPORTED;
     } else {
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            if (mDisconnectPending) {
+                return ERROR_IO;
+            }
+        }
+
         status_t err = mHTTPDataSource->connect(url);
 
         if (err != OK) {
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index 41f5ad0..f1188c4 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -87,6 +87,7 @@
     Condition mCondition;
     int64_t mDurationUs;
     bool mSeekDone;
+    bool mDisconnectPending;
 
     int32_t mMonitorQueueGeneration;
 
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 77917b3..3e710dc 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -254,26 +254,12 @@
         return false;
     }
 
-    if (value == "npt=now-" || value == "npt=0-") {
-        return false;
-    }
-
     if (strncmp(value.c_str(), "npt=", 4)) {
         return false;
     }
 
-    const char *s = value.c_str() + 4;
-    char *end;
-    double from = strtod(s, &end);
-
-    if (end == s || *end != '-') {
-        return false;
-    }
-
-    s = end + 1;
-    double to = strtod(s, &end);
-
-    if (end == s || *end != '\0' || to < from) {
+    float from, to;
+    if (!parseNTPRange(value.c_str() + 4, &from, &to)) {
         return false;
     }
 
@@ -307,5 +293,39 @@
     }
 }
 
+// static
+bool ASessionDescription::parseNTPRange(
+        const char *s, float *npt1, float *npt2) {
+    if (s[0] == '-') {
+        return false;  // no start time available.
+    }
+
+    if (!strncmp("now", s, 3)) {
+        return false;  // no absolute start time available
+    }
+
+    char *end;
+    *npt1 = strtof(s, &end);
+
+    if (end == s || *end != '-') {
+        // Failed to parse float or trailing "dash".
+        return false;
+    }
+
+    s = end + 1;  // skip the dash.
+
+    if (!strncmp("now", s, 3)) {
+        return false;  // no absolute end time available
+    }
+
+    *npt2 = strtof(s, &end);
+
+    if (end == s || *end != '\0') {
+        return false;
+    }
+
+    return *npt2 > *npt1;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/rtsp/ASessionDescription.h b/media/libstagefright/rtsp/ASessionDescription.h
index a3fa79e..b462983 100644
--- a/media/libstagefright/rtsp/ASessionDescription.h
+++ b/media/libstagefright/rtsp/ASessionDescription.h
@@ -55,6 +55,14 @@
 
     bool findAttribute(size_t index, const char *key, AString *value) const;
 
+    // parses strings of the form
+    //   npt      := npt-time "-" npt-time? | "-" npt-time
+    //   npt-time := "now" | [0-9]+("." [0-9]*)?
+    //
+    // Returns true iff both "npt1" and "npt2" times were available,
+    // i.e. we have a fixed duration, otherwise this is live streaming.
+    static bool parseNTPRange(const char *s, float *npt1, float *npt2);
+
 protected:
     virtual ~ASessionDescription();
 
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 9bb8c46..306a9c1 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -938,13 +938,11 @@
 
         AString val;
         CHECK(GetAttribute(range.c_str(), "npt", &val));
-        float npt1, npt2;
 
-        if (val == "now-" || val == "0-") {
+        float npt1, npt2;
+        if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
             // This is a live stream and therefore not seekable.
             return;
-        } else {
-            CHECK_EQ(sscanf(val.c_str(), "%f-%f", &npt1, &npt2), 2);
         }
 
         i = response->mHeaders.indexOfKey("rtp-info");
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index be004d2..853a5af 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -343,8 +343,9 @@
     mData.putAUInt16(deviceProperties); // Device Properties Supported
     mData.putAUInt16(captureFormats); // Capture Formats
     mData.putAUInt16(playbackFormats);  // Playback Formats
-    // FIXME
-    string.set("Google, Inc.");
+
+    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
+    string.set(prop_value);
     mData.putString(string);   // Manufacturer
 
     property_get("ro.product.model", prop_value, "MTP Device");
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 18abc0b..e84d136 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -1893,7 +1893,8 @@
         AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
         AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET |
         AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) &&
-        (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) &&
+        ((getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) ||
+         (stream == AudioSystem::SYSTEM)) &&
         streamDesc.mCanBeMuted) {
         volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
         // when the phone is ringing we must consider that music could have been paused just before