Merge "Import revised translations."
diff --git a/api/current.xml b/api/current.xml
index 35daa43c..d7e626d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -39256,6 +39256,23 @@
  visibility="public"
 >
 </method>
+<method name="listenUsingInsecureRfcommWithServiceRecord"
+ return="android.bluetooth.BluetoothServerSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="uuid" type="java.util.UUID">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
 <method name="listenUsingRfcommWithServiceRecord"
  return="android.bluetooth.BluetoothServerSocket"
  abstract="false"
@@ -41595,6 +41612,21 @@
 >
 <implements name="android.os.Parcelable">
 </implements>
+<method name="createInsecureRfcommSocketToServiceRecord"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.util.UUID">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
 <method name="createRfcommSocketToServiceRecord"
  return="android.bluetooth.BluetoothSocket"
  abstract="false"
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index ccae92eb..9246a00 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -40,7 +40,7 @@
 MyStreamSource::MyStreamSource(int fd)
     : mFd(fd),
       mFileSize(0),
-      mNextSeekTimeUs(ALooper::GetNowUs() + 5000000ll) {
+      mNextSeekTimeUs(-1) {  // ALooper::GetNowUs() + 5000000ll) {
     CHECK_GE(fd, 0);
 
     mFileSize = lseek64(fd, 0, SEEK_END);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 32df4e8..b2185ad 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -868,6 +868,42 @@
      */
     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
             throws IOException {
+        return createNewRfcommSocketAndRecord(name, uuid, true, true);
+    }
+
+    /**
+     * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
+     * <p>The link key will be unauthenticated i.e the communication is
+     * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
+     * the link key will be encrypted, as encryption is mandartory.
+     * For legacy devices (pre Bluetooth 2.1 devices) the link key will not
+     * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
+     * encrypted and authenticated communication channel is desired.
+     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
+     * connections from a listening {@link BluetoothServerSocket}.
+     * <p>The system will assign an unused RFCOMM channel to listen on.
+     * <p>The system will also register a Service Discovery
+     * Protocol (SDP) record with the local SDP server containing the specified
+     * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
+     * can use the same UUID to query our SDP server and discover which channel
+     * to connect to. This SDP record will be removed when this socket is
+     * closed, or if this application closes unexpectedly.
+     * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
+     * connect to this socket from another device using the same {@link UUID}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     * @param name service name for SDP record
+     * @param uuid uuid for SDP record
+     * @return a listening RFCOMM BluetoothServerSocket
+     * @throws IOException on error, for example Bluetooth not available, or
+     *                     insufficient permissions, or channel in use.
+     */
+    public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
+            throws IOException {
+        return createNewRfcommSocketAndRecord(name, uuid, false, false);
+    }
+
+    private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
+            boolean auth, boolean encrypt) throws IOException {
         RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
 
         BluetoothServerSocket socket;
@@ -881,7 +917,7 @@
             }
 
             socket = new BluetoothServerSocket(
-                    BluetoothSocket.TYPE_RFCOMM, true, true, channel);
+                    BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel);
             errno = socket.mSocket.bindListen();
             if (errno == 0) {
                 if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index ada3c24..e15d003 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -737,6 +737,39 @@
     }
 
     /**
+     * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
+     * outgoing connection to this remote device using SDP lookup of uuid.
+     * <p> The communication channel will not have an authenticated link key
+     * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
+     * devices, the link key will be encrypted, as encryption is mandatory.
+     * For legacy devices (pre Bluetooth 2.1 devices) the link key will
+     * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
+     * encrypted and authenticated communication channel is desired.
+     * <p>This is designed to be used with {@link
+     * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
+     * Bluetooth applications.
+     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
+     * connection. This will also perform an SDP lookup of the given uuid to
+     * determine which channel to connect to.
+     * <p>The remote device will be authenticated and communication on this
+     * socket will be encrypted.
+     * <p>Hint: If you are connecting to a Bluetooth serial board then try
+     * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
+     * However if you are connecting to an Android peer then please generate
+     * your own unique UUID.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     *
+     * @param uuid service record uuid to lookup RFCOMM channel
+     * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+     * @throws IOException on error, for example Bluetooth not available, or
+     *                     insufficient permissions
+     */
+    public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
+        return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
+                new ParcelUuid(uuid));
+    }
+
+    /**
      * Construct an insecure RFCOMM socket ready to start an outgoing
      * connection.
      * Call #connect on the returned #BluetoothSocket to begin the connection.
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 3dd1ecd..d8d63206 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -361,101 +361,103 @@
                             if (fitbottom > okbottom)
                                 okbottom = fitbottom;
                         }
-                    } else if (breakOnlyAtSpaces) {
-                        if (ok != here) {
-                            // Log.e("text", "output ok " + here + " to " +ok);
-
-                            while (ok < spanEnd && chs[ok - paraStart] == ' ') {
-                                ok++;
-                            }
-
-                            v = out(source,
-                                    here, ok,
-                                    okascent, okdescent, oktop, okbottom,
-                                    v,
-                                    spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, hasTabOrEmoji,
-                                    needMultiply, paraStart, chdirs, dir, easy,
-                                    ok == bufend, includepad, trackpad,
-                                    chs, widths, here - paraStart,
-                                    where, ellipsizedWidth, okwidth,
-                                    paint);
-
-                            here = ok;
-                        } else {
-                            // Act like it fit even though it didn't.
-
-                            fitwidth = w;
-                            fit = j + 1;
-
-                            if (fmtop < fittop)
-                                fittop = fmtop;
-                            if (fmascent < fitascent)
-                                fitascent = fmascent;
-                            if (fmdescent > fitdescent)
-                                fitdescent = fmdescent;
-                            if (fmbottom > fitbottom)
-                                fitbottom = fmbottom;
-                        }
                     } else {
-                        if (ok != here) {
-                            // Log.e("text", "output ok " + here + " to " +ok);
+                        if (breakOnlyAtSpaces) {
+                            if (ok != here) {
+                                // Log.e("text", "output ok " + here + " to " +ok);
 
-                            while (ok < spanEnd && chs[ok - paraStart] == ' ') {
-                                ok++;
+                                while (ok < spanEnd && chs[ok - paraStart] == ' ') {
+                                    ok++;
+                                }
+
+                                v = out(source,
+                                        here, ok,
+                                        okascent, okdescent, oktop, okbottom,
+                                        v,
+                                        spacingmult, spacingadd, chooseht,
+                                        choosehtv, fm, hasTabOrEmoji,
+                                        needMultiply, paraStart, chdirs, dir, easy,
+                                        ok == bufend, includepad, trackpad,
+                                        chs, widths, here - paraStart,
+                                        where, ellipsizedWidth, okwidth,
+                                        paint);
+
+                                here = ok;
+                            } else {
+                                // Act like it fit even though it didn't.
+
+                                fitwidth = w;
+                                fit = j + 1;
+
+                                if (fmtop < fittop)
+                                    fittop = fmtop;
+                                if (fmascent < fitascent)
+                                    fitascent = fmascent;
+                                if (fmdescent > fitdescent)
+                                    fitdescent = fmdescent;
+                                if (fmbottom > fitbottom)
+                                    fitbottom = fmbottom;
                             }
-
-                            v = out(source,
-                                    here, ok,
-                                    okascent, okdescent, oktop, okbottom,
-                                    v,
-                                    spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, hasTabOrEmoji,
-                                    needMultiply, paraStart, chdirs, dir, easy,
-                                    ok == bufend, includepad, trackpad,
-                                    chs, widths, here - paraStart,
-                                    where, ellipsizedWidth, okwidth,
-                                    paint);
-
-                            here = ok;
-                        } else if (fit != here) {
-                            // Log.e("text", "output fit " + here + " to " +fit);
-                            v = out(source,
-                                    here, fit,
-                                    fitascent, fitdescent,
-                                    fittop, fitbottom,
-                                    v,
-                                    spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, hasTabOrEmoji,
-                                    needMultiply, paraStart, chdirs, dir, easy,
-                                    fit == bufend, includepad, trackpad,
-                                    chs, widths, here - paraStart,
-                                    where, ellipsizedWidth, fitwidth,
-                                    paint);
-
-                            here = fit;
                         } else {
-                            // Log.e("text", "output one " + here + " to " +(here + 1));
-                            // XXX not sure why the existing fm wasn't ok.
-                            // measureText(paint, mWorkPaint,
-                            //             source, here, here + 1, fm, tab,
-                            //             null);
+                            if (ok != here) {
+                                // Log.e("text", "output ok " + here + " to " +ok);
 
-                            v = out(source,
-                                    here, here+1,
-                                    fm.ascent, fm.descent,
-                                    fm.top, fm.bottom,
-                                    v,
-                                    spacingmult, spacingadd, chooseht,
-                                    choosehtv, fm, hasTabOrEmoji,
-                                    needMultiply, paraStart, chdirs, dir, easy,
-                                    here + 1 == bufend, includepad,
-                                    trackpad,
-                                    chs, widths, here - paraStart,
-                                    where, ellipsizedWidth,
-                                    widths[here - paraStart], paint);
+                                while (ok < spanEnd && chs[ok - paraStart] == ' ') {
+                                    ok++;
+                                }
 
-                            here = here + 1;
+                                v = out(source,
+                                        here, ok,
+                                        okascent, okdescent, oktop, okbottom,
+                                        v,
+                                        spacingmult, spacingadd, chooseht,
+                                        choosehtv, fm, hasTabOrEmoji,
+                                        needMultiply, paraStart, chdirs, dir, easy,
+                                        ok == bufend, includepad, trackpad,
+                                        chs, widths, here - paraStart,
+                                        where, ellipsizedWidth, okwidth,
+                                        paint);
+
+                                here = ok;
+                            } else if (fit != here) {
+                                // Log.e("text", "output fit " + here + " to " +fit);
+                                v = out(source,
+                                        here, fit,
+                                        fitascent, fitdescent,
+                                        fittop, fitbottom,
+                                        v,
+                                        spacingmult, spacingadd, chooseht,
+                                        choosehtv, fm, hasTabOrEmoji,
+                                        needMultiply, paraStart, chdirs, dir, easy,
+                                        fit == bufend, includepad, trackpad,
+                                        chs, widths, here - paraStart,
+                                        where, ellipsizedWidth, fitwidth,
+                                        paint);
+
+                                here = fit;
+                            } else {
+                                // Log.e("text", "output one " + here + " to " +(here + 1));
+                                // XXX not sure why the existing fm wasn't ok.
+                                // measureText(paint, mWorkPaint,
+                                //             source, here, here + 1, fm, tab,
+                                //             null);
+
+                                v = out(source,
+                                        here, here+1,
+                                        fm.ascent, fm.descent,
+                                        fm.top, fm.bottom,
+                                        v,
+                                        spacingmult, spacingadd, chooseht,
+                                        choosehtv, fm, hasTabOrEmoji,
+                                        needMultiply, paraStart, chdirs, dir, easy,
+                                        here + 1 == bufend, includepad,
+                                        trackpad,
+                                        chs, widths, here - paraStart,
+                                        where, ellipsizedWidth,
+                                        widths[here - paraStart], paint);
+
+                                here = here + 1;
+                            }
                         }
 
                         if (here < spanStart) {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 92f3593..3902734 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1806,7 +1806,7 @@
 
     <!-- Do not translate.  WebView User Agent string -->
     <string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>)
-        AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.13</string>
+        AppleWebKit/534.14 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.14</string>
     <!-- Do not translate.  WebView User Agent targeted content -->
     <string name="web_user_agent_target_content" translatable="false">"Mobile "</string>
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 6f011ce..97c541a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -732,6 +732,21 @@
         return TEST_PLAYER;
     }
 
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.httplive.enable-nuplayer", value, NULL)
+            && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
+        if (!strncasecmp("http://", url, 7)) {
+            size_t len = strlen(url);
+            if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
+                return NU_PLAYER;
+            }
+
+            if (strstr(url,"m3u8")) {
+                return NU_PLAYER;
+            }
+        }
+    }
+
     // use MidiFile for MIDI extensions
     int lenURL = strlen(url);
     for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index c4f3764..c20e279 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -2,17 +2,20 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                       \
+        HTTPLiveSource.cpp              \
         NuPlayer.cpp                    \
         NuPlayerDecoder.cpp             \
         NuPlayerDriver.cpp              \
         NuPlayerRenderer.cpp            \
         NuPlayerStreamListener.cpp      \
         DecoderWrapper.cpp              \
+        StreamingSource.cpp             \
 
 LOCAL_C_INCLUDES := \
         $(TOP)/frameworks/base/include/media/stagefright/openmax        \
 	$(TOP)/frameworks/base/media/libstagefright/include             \
         $(TOP)/frameworks/base/media/libstagefright/mpeg2ts             \
+        $(TOP)/frameworks/base/media/libstagefright/httplive            \
 
 LOCAL_MODULE:= libstagefright_nuplayer
 
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
new file mode 100644
index 0000000..c656e69
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "HTTPLiveSource"
+#include <utils/Log.h>
+
+#include "HTTPLiveSource.h"
+
+#include "ATSParser.h"
+#include "AnotherPacketSource.h"
+#include "LiveDataSource.h"
+#include "LiveSession.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+NuPlayer::HTTPLiveSource::HTTPLiveSource(const char *url)
+    : mURL(url),
+      mEOS(false),
+      mOffset(0) {
+}
+
+NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
+    mLiveSession->disconnect();
+    mLiveLooper->stop();
+}
+
+void NuPlayer::HTTPLiveSource::start() {
+    mLiveLooper = new ALooper;
+    mLiveLooper->setName("http live");
+    mLiveLooper->start();
+
+    mLiveSession = new LiveSession;
+    mLiveLooper->registerHandler(mLiveSession);
+
+    mLiveSession->connect(mURL.c_str());
+
+    mTSParser = new ATSParser;
+}
+
+sp<MetaData> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
+    ATSParser::SourceType type =
+        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+
+    sp<AnotherPacketSource> source =
+        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
+
+    if (source == NULL) {
+        return NULL;
+    }
+
+    return source->getFormat();
+}
+
+bool NuPlayer::HTTPLiveSource::feedMoreTSData() {
+    if (mEOS) {
+        return false;
+    }
+
+    sp<LiveDataSource> source =
+        static_cast<LiveDataSource *>(mLiveSession->getDataSource().get());
+
+    for (int32_t i = 0; i < 10; ++i) {
+        char buffer[188];
+        ssize_t n = source->readAtNonBlocking(mOffset, buffer, sizeof(buffer));
+
+        if (n == -EWOULDBLOCK) {
+            break;
+        } else if (n < 0) {
+            LOGI("input data EOS reached.");
+            mTSParser->signalEOS(ERROR_END_OF_STREAM);
+            mEOS = true;
+            break;
+        } else {
+            if (buffer[0] == 0x00) {
+                // XXX legacy
+                mTSParser->signalDiscontinuity(
+                        buffer[1] == 0x00
+                            ? ATSParser::DISCONTINUITY_SEEK
+                            : ATSParser::DISCONTINUITY_FORMATCHANGE);
+            } else {
+                mTSParser->feedTSPacket(buffer, sizeof(buffer));
+            }
+
+            mOffset += n;
+        }
+    }
+
+    return true;
+}
+
+status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit(
+        bool audio, sp<ABuffer> *accessUnit) {
+    ATSParser::SourceType type =
+        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+
+    sp<AnotherPacketSource> source =
+        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
+
+    if (source == NULL) {
+        return -EWOULDBLOCK;
+    }
+
+    status_t finalResult;
+    if (!source->hasBufferAvailable(&finalResult)) {
+        return finalResult == OK ? -EWOULDBLOCK : finalResult;
+    }
+
+    return source->dequeueAccessUnit(accessUnit);
+}
+
+}  // namespace android
+
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
new file mode 100644
index 0000000..1b97699
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HTTP_LIVE_SOURCE_H_
+
+#define HTTP_LIVE_SOURCE_H_
+
+#include "NuPlayer.h"
+#include "NuPlayerSource.h"
+
+namespace android {
+
+struct ATSParser;
+struct LiveSession;
+
+struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
+    HTTPLiveSource(const char *url);
+
+    void start();
+
+    // Returns true iff more data was available, false on EOS.
+    bool feedMoreTSData();
+
+    sp<MetaData> getFormat(bool audio);
+    status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+
+protected:
+    virtual ~HTTPLiveSource();
+
+private:
+    AString mURL;
+    bool mEOS;
+    off64_t mOffset;
+    sp<ALooper> mLiveLooper;
+    sp<LiveSession> mLiveSession;
+    sp<ATSParser> mTSParser;
+
+    DISALLOW_EVIL_CONSTRUCTORS(HTTPLiveSource);
+};
+
+}  // namespace android
+
+#endif  // HTTP_LIVE_SOURCE_H_
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 967fa49..24efa35 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -19,9 +19,14 @@
 #include <utils/Log.h>
 
 #include "NuPlayer.h"
+
+#include "HTTPLiveSource.h"
 #include "NuPlayerDecoder.h"
 #include "NuPlayerRenderer.h"
-#include "NuPlayerStreamListener.h"
+#include "NuPlayerSource.h"
+#include "StreamingSource.h"
+
+#include "ATSParser.h"
 
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -37,9 +42,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 NuPlayer::NuPlayer()
-    : mEOS(false),
-      mAudioEOS(false),
+    : mAudioEOS(false),
       mVideoEOS(false),
+      mScanSourcesPending(false),
       mFlushingAudio(NONE),
       mFlushingVideo(NONE) {
 }
@@ -54,9 +59,15 @@
 void NuPlayer::setDataSource(const sp<IStreamSource> &source) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
 
-    source->incStrong(this);
-    msg->setPointer("source", source.get());  // XXX unsafe.
+    msg->setObject("source", new StreamingSource(source));
+    msg->post();
+}
 
+void NuPlayer::setDataSource(
+        const char *url, const KeyedVector<String8, String8> *headers) {
+    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+
+    msg->setObject("source", new HTTPLiveSource(url));
     msg->post();
 }
 
@@ -104,14 +115,10 @@
 
             CHECK(mSource == NULL);
 
-            void *ptr;
-            CHECK(msg->findPointer("source", &ptr));
+            sp<RefBase> obj;
+            CHECK(msg->findObject("source", &obj));
 
-            mSource = static_cast<IStreamSource *>(ptr);
-            mSource->decStrong(this);
-
-            mStreamListener = new NuPlayerStreamListener(mSource, id());
-            mTSParser = new ATSParser;
+            mSource = static_cast<Source *>(obj.get());
             break;
         }
 
@@ -139,7 +146,7 @@
 
         case kWhatStart:
         {
-            mStreamListener->start();
+            mSource->start();
 
             mRenderer = new Renderer(
                     mAudioSink,
@@ -148,31 +155,27 @@
             looper()->registerHandler(mRenderer);
 
             (new AMessage(kWhatScanSources, id()))->post();
+            mScanSourcesPending = true;
             break;
         }
 
         case kWhatScanSources:
         {
-            instantiateDecoder(
-                    false,
-                    &mVideoDecoder,
-                    false /* ignoreCodecSpecificData */);
+            mScanSourcesPending = false;
+
+            instantiateDecoder(false, &mVideoDecoder);
 
             if (mAudioSink != NULL) {
-                instantiateDecoder(
-                        true,
-                        &mAudioDecoder,
-                        false /* ignoreCodecSpecificData */);
+                instantiateDecoder(true, &mAudioDecoder);
             }
 
-            if (mEOS) {
+            if (!mSource->feedMoreTSData()) {
                 break;
             }
 
-            feedMoreTSData();
-
             if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
                 msg->post(100000ll);
+                mScanSourcesPending = true;
             }
             break;
         }
@@ -192,9 +195,10 @@
                 status_t err = feedDecoderInputData(
                         audio, codecRequest);
 
-                if (err == -EWOULDBLOCK && !mEOS) {
-                    feedMoreTSData();
-                    msg->post();
+                if (err == -EWOULDBLOCK) {
+                    if (mSource->feedMoreTSData()) {
+                        msg->post();
+                    }
                 }
             } else if (what == ACodec::kWhatEOS) {
                 mRenderer->queueEOS(audio, ERROR_END_OF_STREAM);
@@ -322,135 +326,37 @@
 
     mRenderer->signalTimeDiscontinuity();
 
+    bool scanSourcesAgain = false;
+
     if (mFlushingAudio == SHUT_DOWN) {
-        instantiateDecoder(
-                true,
-                &mAudioDecoder,
-                true /* ignoreCodecSpecificData */);
-        CHECK(mAudioDecoder != NULL);
+        scanSourcesAgain = true;
     } else if (mAudioDecoder != NULL) {
         mAudioDecoder->signalResume();
     }
 
     if (mFlushingVideo == SHUT_DOWN) {
-        instantiateDecoder(
-                false,
-                &mVideoDecoder,
-                true /* ignoreCodecSpecificData */);
-        CHECK(mVideoDecoder != NULL);
+        scanSourcesAgain = true;
     } else if (mVideoDecoder != NULL) {
         mVideoDecoder->signalResume();
     }
 
     mFlushingAudio = NONE;
     mFlushingVideo = NONE;
-}
 
-void NuPlayer::feedMoreTSData() {
-    CHECK(!mEOS);
-
-    for (int32_t i = 0; i < 10; ++i) {
-        char buffer[188];
-        ssize_t n = mStreamListener->read(buffer, sizeof(buffer));
-
-        if (n == 0) {
-            LOGI("input data EOS reached.");
-            mTSParser->signalEOS(ERROR_END_OF_STREAM);
-            mEOS = true;
-            break;
-        } else if (n == INFO_DISCONTINUITY) {
-            mTSParser->signalDiscontinuity(ATSParser::DISCONTINUITY_SEEK);
-        } else if (n < 0) {
-            CHECK_EQ(n, -EWOULDBLOCK);
-            break;
-        } else {
-            if (buffer[0] == 0x00) {
-                // XXX legacy
-                mTSParser->signalDiscontinuity(
-                        buffer[1] == 0x00
-                            ? ATSParser::DISCONTINUITY_SEEK
-                            : ATSParser::DISCONTINUITY_FORMATCHANGE);
-            } else {
-                mTSParser->feedTSPacket(buffer, sizeof(buffer));
-            }
-        }
+    if (scanSourcesAgain && !mScanSourcesPending) {
+        mScanSourcesPending = true;
+        (new AMessage(kWhatScanSources, id()))->post();
     }
 }
 
-status_t NuPlayer::dequeueNextAccessUnit(
-        ATSParser::SourceType *type, sp<ABuffer> *accessUnit) {
-    accessUnit->clear();
-
-    status_t audioErr = -EWOULDBLOCK;
-    int64_t audioTimeUs;
-
-    sp<AnotherPacketSource> audioSource =
-        static_cast<AnotherPacketSource *>(
-                mTSParser->getSource(ATSParser::MPEG2ADTS_AUDIO).get());
-
-    if (audioSource != NULL) {
-        audioErr = audioSource->nextBufferTime(&audioTimeUs);
-    }
-
-    status_t videoErr = -EWOULDBLOCK;
-    int64_t videoTimeUs;
-
-    sp<AnotherPacketSource> videoSource =
-        static_cast<AnotherPacketSource *>(
-                mTSParser->getSource(ATSParser::AVC_VIDEO).get());
-
-    if (videoSource != NULL) {
-        videoErr = videoSource->nextBufferTime(&videoTimeUs);
-    }
-
-    if (audioErr == -EWOULDBLOCK || videoErr == -EWOULDBLOCK) {
-        return -EWOULDBLOCK;
-    }
-
-    if (audioErr != OK && videoErr != OK) {
-        return audioErr;
-    }
-
-    if (videoErr != OK || (audioErr == OK && audioTimeUs < videoTimeUs)) {
-        *type = ATSParser::MPEG2ADTS_AUDIO;
-        return audioSource->dequeueAccessUnit(accessUnit);
-    } else {
-        *type = ATSParser::AVC_VIDEO;
-        return videoSource->dequeueAccessUnit(accessUnit);
-    }
-}
-
-status_t NuPlayer::dequeueAccessUnit(
-        ATSParser::SourceType type, sp<ABuffer> *accessUnit) {
-    sp<AnotherPacketSource> source =
-        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
-
-    if (source == NULL) {
-        return -EWOULDBLOCK;
-    }
-
-    status_t finalResult;
-    if (!source->hasBufferAvailable(&finalResult)) {
-        return finalResult == OK ? -EWOULDBLOCK : finalResult;
-    }
-
-    return source->dequeueAccessUnit(accessUnit);
-}
-
-status_t NuPlayer::instantiateDecoder(
-        bool audio, sp<Decoder> *decoder, bool ignoreCodecSpecificData) {
+status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
     if (*decoder != NULL) {
         return OK;
     }
 
-    ATSParser::SourceType type =
-        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+    sp<MetaData> meta = mSource->getFormat(audio);
 
-    sp<AnotherPacketSource> source =
-        static_cast<AnotherPacketSource *>(
-                mTSParser->getSource(type).get());
-
-    if (source == NULL) {
+    if (meta == NULL) {
         return -EWOULDBLOCK;
     }
 
@@ -461,8 +367,7 @@
     *decoder = new Decoder(notify, audio ? NULL : mSurface);
     looper()->registerHandler(*decoder);
 
-    const sp<MetaData> &meta = source->getFormat();
-    (*decoder)->configure(meta, ignoreCodecSpecificData);
+    (*decoder)->configure(meta);
 
     return OK;
 }
@@ -479,19 +384,17 @@
     }
 
     sp<ABuffer> accessUnit;
-    status_t err = dequeueAccessUnit(
-            audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO,
-            &accessUnit);
+    status_t err = mSource->dequeueAccessUnit(audio, &accessUnit);
 
     if (err == -EWOULDBLOCK) {
         return err;
     } else if (err != OK) {
         if (err == INFO_DISCONTINUITY) {
-            int32_t formatChange;
-            if (!accessUnit->meta()->findInt32(
-                        "format-change", &formatChange)) {
-                formatChange = 0;
-            }
+            int32_t type;
+            CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
+
+            bool formatChange =
+                type == ATSParser::DISCONTINUITY_FORMATCHANGE;
 
             LOGI("%s discontinuity (formatChange=%d)",
                  audio ? "audio" : "video", formatChange);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index d4e7428..172a962 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -21,9 +21,6 @@
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/foundation/AHandler.h>
 
-#include "ATSParser.h"
-#include "AnotherPacketSource.h"
-
 namespace android {
 
 struct ACodec;
@@ -35,6 +32,10 @@
     void setListener(const wp<MediaPlayerBase> &listener);
 
     void setDataSource(const sp<IStreamSource> &source);
+
+    void setDataSource(
+            const char *url, const KeyedVector<String8, String8> *headers);
+
     void setVideoSurface(const sp<Surface> &surface);
     void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink);
     void start();
@@ -45,9 +46,12 @@
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
 private:
-    struct Renderer;
     struct Decoder;
+    struct HTTPLiveSource;
     struct NuPlayerStreamListener;
+    struct Renderer;
+    struct Source;
+    struct StreamingSource;
 
     enum {
         kWhatSetDataSource,
@@ -62,11 +66,9 @@
     };
 
     wp<MediaPlayerBase> mListener;
-    sp<IStreamSource> mSource;
+    sp<Source> mSource;
     sp<Surface> mSurface;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
-    sp<NuPlayerStreamListener> mStreamListener;
-    sp<ATSParser> mTSParser;
     sp<Decoder> mVideoDecoder;
     sp<Decoder> mAudioDecoder;
     sp<Renderer> mRenderer;
@@ -75,6 +77,8 @@
     bool mAudioEOS;
     bool mVideoEOS;
 
+    bool mScanSourcesPending;
+
     enum FlushStatus {
         NONE,
         AWAITING_DISCONTINUITY,
@@ -88,19 +92,11 @@
     FlushStatus mFlushingAudio;
     FlushStatus mFlushingVideo;
 
-    status_t instantiateDecoder(
-            bool audio, sp<Decoder> *decoder, bool ignoreCodecSpecificData);
+    status_t instantiateDecoder(bool audio, sp<Decoder> *decoder);
 
     status_t feedDecoderInputData(bool audio, const sp<AMessage> &msg);
     void renderBuffer(bool audio, const sp<AMessage> &msg);
 
-    status_t dequeueNextAccessUnit(
-            ATSParser::SourceType *type, sp<ABuffer> *accessUnit);
-
-    status_t dequeueAccessUnit(
-            ATSParser::SourceType type, sp<ABuffer> *accessUnit);
-
-    void feedMoreTSData();
     void notifyListener(int msg, int ext1, int ext2);
 
     void finishFlushIfPossible();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1d78808..761dfa4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -25,6 +25,7 @@
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/ACodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
@@ -42,8 +43,7 @@
 NuPlayer::Decoder::~Decoder() {
 }
 
-void NuPlayer::Decoder::configure(
-        const sp<MetaData> &meta, bool ignoreCodecSpecificData) {
+void NuPlayer::Decoder::configure(const sp<MetaData> &meta) {
     CHECK(mCodec == NULL);
     CHECK(mWrapper == NULL);
 
@@ -55,10 +55,6 @@
 
     sp<AMessage> format = makeFormat(meta);
 
-    if (ignoreCodecSpecificData) {
-        mCSD.clear();
-    }
-
     if (mSurface != NULL) {
         format->setObject("surface", mSurface);
     }
@@ -128,6 +124,13 @@
         msg->setInt32("sample-rate", sampleRate);
     }
 
+    int32_t maxInputSize;
+    if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
+        msg->setInt32("max-input-size", maxInputSize);
+    }
+
+    mCSDIndex = 0;
+
     uint32_t type;
     const void *data;
     size_t size;
@@ -233,13 +236,6 @@
 #endif
     }
 
-    int32_t maxInputSize;
-    if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
-        msg->setInt32("max-input-size", maxInputSize);
-    }
-
-    mCSDIndex = 0;
-
     return msg;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 07fe47e..3874cfe 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -24,13 +24,13 @@
 
 namespace android {
 
+struct ABuffer;
 struct DecoderWrapper;
 
 struct NuPlayer::Decoder : public AHandler {
     Decoder(const sp<AMessage> &notify, const sp<Surface> &surface = NULL);
 
-    void configure(
-            const sp<MetaData> &meta, bool ignoreCodecSpecificData);
+    void configure(const sp<MetaData> &meta);
 
     void signalFlush();
     void signalResume();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b79251a..d21d4ff 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -27,7 +27,8 @@
 namespace android {
 
 NuPlayerDriver::NuPlayerDriver()
-    : mLooper(new ALooper) {
+    : mLooper(new ALooper),
+      mPlayer(false) {
     mLooper->setName("NuPlayerDriver Looper");
 
     mLooper->start(
@@ -51,7 +52,9 @@
 
 status_t NuPlayerDriver::setDataSource(
         const char *url, const KeyedVector<String8, String8> *headers) {
-    return INVALID_OPERATION;
+    mPlayer->setDataSource(url, headers);
+
+    return OK;
 }
 
 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
@@ -75,25 +78,30 @@
 }
 
 status_t NuPlayerDriver::prepareAsync() {
+    sendEvent(MEDIA_PREPARED);
+
     return OK;
 }
 
 status_t NuPlayerDriver::start() {
     mPlayer->start();
+    mPlaying = true;
 
     return OK;
 }
 
 status_t NuPlayerDriver::stop() {
+    mPlaying = false;
     return OK;
 }
 
 status_t NuPlayerDriver::pause() {
+    mPlaying = false;
     return OK;
 }
 
 bool NuPlayerDriver::isPlaying() {
-    return false;
+    return mPlaying;
 }
 
 status_t NuPlayerDriver::seekTo(int msec) {
@@ -101,11 +109,15 @@
 }
 
 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
-    return INVALID_OPERATION;
+    *msec = 0;
+
+    return OK;
 }
 
 status_t NuPlayerDriver::getDuration(int *msec) {
-    return INVALID_OPERATION;
+    *msec = 0;
+
+    return OK;
 }
 
 status_t NuPlayerDriver::reset() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 245f1dd..44ae3bf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -60,6 +60,7 @@
 private:
     sp<ALooper> mLooper;
     sp<NuPlayer> mPlayer;
+    bool mPlaying;
 
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayerDriver);
 };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 57a652c..00cbec2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -22,6 +22,7 @@
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 
 namespace android {
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index eaa004a..fb3903c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -22,6 +22,8 @@
 
 namespace android {
 
+struct ABuffer;
+
 struct NuPlayer::Renderer : public AHandler {
     Renderer(const sp<MediaPlayerBase::AudioSink> &sink,
              const sp<AMessage> &notify);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
new file mode 100644
index 0000000..044e202
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NUPLAYER_SOURCE_H_
+
+#define NUPLAYER_SOURCE_H_
+
+#include "NuPlayer.h"
+
+namespace android {
+
+struct ABuffer;
+
+struct NuPlayer::Source : public RefBase {
+    Source() {}
+
+    virtual void start() = 0;
+
+    // Returns true iff more data was available, false on EOS.
+    virtual bool feedMoreTSData() = 0;
+
+    virtual sp<MetaData> getFormat(bool audio) = 0;
+
+    virtual status_t dequeueAccessUnit(
+            bool audio, sp<ABuffer> *accessUnit) = 0;
+
+protected:
+    virtual ~Source() {}
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(Source);
+};
+
+}  // namespace android
+
+#endif  // NUPLAYER_SOURCE_H_
+
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
index 92642a8..a23beb7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
@@ -22,6 +22,8 @@
 
 #include <binder/MemoryDealer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -62,7 +64,10 @@
 
     if (mSendDataNotification) {
         mSendDataNotification = false;
-        (new AMessage(kWhatMoreDataQueued, mTargetID))->post();
+
+        if (mTargetID != 0) {
+            (new AMessage(kWhatMoreDataQueued, mTargetID))->post();
+        }
     }
 }
 
@@ -80,7 +85,10 @@
 
     if (mSendDataNotification) {
         mSendDataNotification = false;
-        (new AMessage(kWhatMoreDataQueued, mTargetID))->post();
+
+        if (mTargetID != 0) {
+            (new AMessage(kWhatMoreDataQueued, mTargetID))->post();
+        }
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
new file mode 100644
index 0000000..b85ac9f
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "StreamingSource"
+#include <utils/Log.h>
+
+#include "StreamingSource.h"
+
+#include "ATSParser.h"
+#include "AnotherPacketSource.h"
+#include "NuPlayerStreamListener.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+NuPlayer::StreamingSource::StreamingSource(const sp<IStreamSource> &source)
+    : mSource(source),
+      mEOS(false) {
+}
+
+NuPlayer::StreamingSource::~StreamingSource() {
+}
+
+void NuPlayer::StreamingSource::start() {
+    mStreamListener = new NuPlayerStreamListener(mSource, 0);
+    mTSParser = new ATSParser;
+
+    mStreamListener->start();
+}
+
+bool NuPlayer::StreamingSource::feedMoreTSData() {
+    if (mEOS) {
+        return false;
+    }
+
+    for (int32_t i = 0; i < 10; ++i) {
+        char buffer[188];
+        ssize_t n = mStreamListener->read(buffer, sizeof(buffer));
+
+        if (n == 0) {
+            LOGI("input data EOS reached.");
+            mTSParser->signalEOS(ERROR_END_OF_STREAM);
+            mEOS = true;
+            break;
+        } else if (n == INFO_DISCONTINUITY) {
+            mTSParser->signalDiscontinuity(ATSParser::DISCONTINUITY_SEEK);
+        } else if (n < 0) {
+            CHECK_EQ(n, -EWOULDBLOCK);
+            break;
+        } else {
+            if (buffer[0] == 0x00) {
+                // XXX legacy
+                mTSParser->signalDiscontinuity(
+                        buffer[1] == 0x00
+                            ? ATSParser::DISCONTINUITY_SEEK
+                            : ATSParser::DISCONTINUITY_FORMATCHANGE);
+            } else {
+                mTSParser->feedTSPacket(buffer, sizeof(buffer));
+            }
+        }
+    }
+
+    return true;
+}
+
+sp<MetaData> NuPlayer::StreamingSource::getFormat(bool audio) {
+    ATSParser::SourceType type =
+        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+
+    sp<AnotherPacketSource> source =
+        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
+
+    if (source == NULL) {
+        return NULL;
+    }
+
+    return source->getFormat();
+}
+
+status_t NuPlayer::StreamingSource::dequeueAccessUnit(
+        bool audio, sp<ABuffer> *accessUnit) {
+    ATSParser::SourceType type =
+        audio ? ATSParser::MPEG2ADTS_AUDIO : ATSParser::AVC_VIDEO;
+
+    sp<AnotherPacketSource> source =
+        static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get());
+
+    if (source == NULL) {
+        return -EWOULDBLOCK;
+    }
+
+    status_t finalResult;
+    if (!source->hasBufferAvailable(&finalResult)) {
+        return finalResult == OK ? -EWOULDBLOCK : finalResult;
+    }
+
+    return source->dequeueAccessUnit(accessUnit);
+}
+
+}  // namespace android
+
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h
new file mode 100644
index 0000000..5f0a9dd
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STREAMING_SOURCE_H_
+
+#define STREAMING_SOURCE_H_
+
+#include "NuPlayer.h"
+#include "NuPlayerSource.h"
+
+namespace android {
+
+struct ABuffer;
+struct ATSParser;
+
+struct NuPlayer::StreamingSource : public NuPlayer::Source {
+    StreamingSource(const sp<IStreamSource> &source);
+
+    void start();
+
+    // Returns true iff more data was available, false on EOS.
+    bool feedMoreTSData();
+
+    sp<MetaData> getFormat(bool audio);
+    status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+
+protected:
+    virtual ~StreamingSource();
+
+private:
+    sp<IStreamSource> mSource;
+    bool mEOS;
+    sp<NuPlayerStreamListener> mStreamListener;
+    sp<ATSParser> mTSParser;
+
+    DISALLOW_EVIL_CONSTRUCTORS(StreamingSource);
+};
+
+}  // namespace android
+
+#endif  // STREAMING_SOURCE_H_
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 3bb61f2..39e0c51 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1082,7 +1082,7 @@
 bool ACodec::BaseState::onOMXEvent(
         OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
     if (event != OMX_EventError) {
-        LOGI("[%s] EVENT(%d, 0x%08lx, 0x%08lx)",
+        LOGV("[%s] EVENT(%d, 0x%08lx, 0x%08lx)",
              mCodec->mComponentName.c_str(), event, data1, data2);
 
         return false;
@@ -1520,7 +1520,7 @@
 }
 
 void ACodec::LoadedToIdleState::stateEntered() {
-    LOGI("[%s] Now Loaded->Idle", mCodec->mComponentName.c_str());
+    LOGV("[%s] Now Loaded->Idle", mCodec->mComponentName.c_str());
 
     CHECK_EQ(allocateBuffers(), (status_t)OK);
 }
@@ -1577,7 +1577,7 @@
 }
 
 void ACodec::IdleToExecutingState::stateEntered() {
-    LOGI("[%s] Now Idle->Executing", mCodec->mComponentName.c_str());
+    LOGV("[%s] Now Idle->Executing", mCodec->mComponentName.c_str());
 }
 
 bool ACodec::IdleToExecutingState::onMessageReceived(const sp<AMessage> &msg) {
@@ -1661,7 +1661,7 @@
 }
 
 void ACodec::ExecutingState::stateEntered() {
-    LOGI("[%s] Now Executing", mCodec->mComponentName.c_str());
+    LOGV("[%s] Now Executing", mCodec->mComponentName.c_str());
 
     mCodec->processDeferredMessages();
 }
@@ -1787,7 +1787,7 @@
 }
 
 void ACodec::OutputPortSettingsChangedState::stateEntered() {
-    LOGI("[%s] Now handling output port settings change",
+    LOGV("[%s] Now handling output port settings change",
          mCodec->mComponentName.c_str());
 }
 
@@ -1868,7 +1868,7 @@
 }
 
 void ACodec::ExecutingToIdleState::stateEntered() {
-    LOGI("[%s] Now Executing->Idle", mCodec->mComponentName.c_str());
+    LOGV("[%s] Now Executing->Idle", mCodec->mComponentName.c_str());
 }
 
 bool ACodec::ExecutingToIdleState::onOMXEvent(
@@ -1950,7 +1950,7 @@
 }
 
 void ACodec::IdleToLoadedState::stateEntered() {
-    LOGI("[%s] Now Idle->Loaded", mCodec->mComponentName.c_str());
+    LOGV("[%s] Now Idle->Loaded", mCodec->mComponentName.c_str());
 }
 
 bool ACodec::IdleToLoadedState::onOMXEvent(
@@ -1961,7 +1961,7 @@
             CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet);
             CHECK_EQ(data2, (OMX_U32)OMX_StateLoaded);
 
-            LOGI("[%s] Now Loaded", mCodec->mComponentName.c_str());
+            LOGV("[%s] Now Loaded", mCodec->mComponentName.c_str());
 
             CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
 
@@ -1995,12 +1995,12 @@
 }
 
 void ACodec::ErrorState::stateEntered() {
-    LOGI("[%s] Now in ErrorState", mCodec->mComponentName.c_str());
+    LOGV("[%s] Now in ErrorState", mCodec->mComponentName.c_str());
 }
 
 bool ACodec::ErrorState::onOMXEvent(
         OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
-    LOGI("EVENT(%d, 0x%08lx, 0x%08lx)", event, data1, data2);
+    LOGV("EVENT(%d, 0x%08lx, 0x%08lx)", event, data1, data2);
     return true;
 }
 
@@ -2011,7 +2011,7 @@
 }
 
 void ACodec::FlushingState::stateEntered() {
-    LOGI("[%s] Now Flushing", mCodec->mComponentName.c_str());
+    LOGV("[%s] Now Flushing", mCodec->mComponentName.c_str());
 
     mFlushComplete[kPortIndexInput] = mFlushComplete[kPortIndexOutput] = false;
 }
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 2fe5e18..fa12cf0 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "avc_utils"
+#include <utils/Log.h>
+
 #include "include/avc_utils.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
diff --git a/media/libstagefright/httplive/LiveDataSource.cpp b/media/libstagefright/httplive/LiveDataSource.cpp
index 25e2902..5f5c6d4 100644
--- a/media/libstagefright/httplive/LiveDataSource.cpp
+++ b/media/libstagefright/httplive/LiveDataSource.cpp
@@ -54,7 +54,8 @@
     return mBufferQueue.size();
 }
 
-ssize_t LiveDataSource::readAt(off64_t offset, void *data, size_t size) {
+ssize_t LiveDataSource::readAtNonBlocking(
+        off64_t offset, void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
     if (offset != mOffset) {
@@ -62,6 +63,36 @@
         return -EPIPE;
     }
 
+    size_t totalAvailable = 0;
+    for (List<sp<ABuffer> >::iterator it = mBufferQueue.begin();
+         it != mBufferQueue.end(); ++it) {
+        sp<ABuffer> buffer = *it;
+
+        totalAvailable += buffer->size();
+
+        if (totalAvailable >= size) {
+            break;
+        }
+    }
+
+    if (totalAvailable < size) {
+        return mFinalResult == OK ? -EWOULDBLOCK : mFinalResult;
+    }
+
+    return readAt_l(offset, data, size);
+}
+
+ssize_t LiveDataSource::readAt(off64_t offset, void *data, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+    return readAt_l(offset, data, size);
+}
+
+ssize_t LiveDataSource::readAt_l(off64_t offset, void *data, size_t size) {
+    if (offset != mOffset) {
+        LOGE("Attempt at reading non-sequentially from LiveDataSource.");
+        return -EPIPE;
+    }
+
     size_t sizeDone = 0;
 
     while (sizeDone < size) {
diff --git a/media/libstagefright/httplive/LiveDataSource.h b/media/libstagefright/httplive/LiveDataSource.h
index a489ec6..b7be637 100644
--- a/media/libstagefright/httplive/LiveDataSource.h
+++ b/media/libstagefright/httplive/LiveDataSource.h
@@ -33,6 +33,7 @@
     virtual status_t initCheck() const;
 
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+    ssize_t readAtNonBlocking(off64_t offset, void *data, size_t size);
 
     void queueBuffer(const sp<ABuffer> &buffer);
     void queueEOS(status_t finalResult);
@@ -53,6 +54,8 @@
 
     FILE *mBackupFile;
 
+    ssize_t readAt_l(off64_t offset, void *data, size_t size);
+
     DISALLOW_EVIL_CONSTRUCTORS(LiveDataSource);
 };
 
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 5c4c5df..5b1f14d 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -157,9 +157,16 @@
 
         mBandwidthItems.sort(SortByBandwidth);
 
-        if (mBandwidthItems.size() > 1) {
-            // XXX Remove the lowest bitrate stream for now...
-            mBandwidthItems.removeAt(0);
+        char value[PROPERTY_VALUE_MAX];
+        if (!property_get("media.httplive.enable-nuplayer", value, NULL)
+                || (strcasecmp(value, "true") && strcmp(value, "1"))) {
+            // The "legacy" player cannot deal with audio format changes,
+            // some streams use different audio encoding parameters for
+            // their lowest bandwidth stream.
+            if (mBandwidthItems.size() > 1) {
+                // XXX Remove the lowest bitrate stream for now...
+                mBandwidthItems.removeAt(0);
+            }
         }
     }
 
@@ -421,7 +428,7 @@
             ++mNumRetries;
 
             mLastPlaylistFetchTimeUs = -1;
-            postMonitorQueue(1000000ll);
+            postMonitorQueue(3000000ll);
             return;
         }
 
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index 50c0a99..3873d5d 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -50,7 +50,7 @@
 private:
     enum {
         kMaxNumQueuedFragments = 2,
-        kMaxNumRetries         = 3,
+        kMaxNumRetries         = 5,
     };
 
     static const int64_t kMaxPlaylistAgeUs;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index ee9b5739..7c81ffd 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -334,7 +334,7 @@
 
             if (mStreamType == 0x1b && mSource != NULL) {
                 // Don't signal discontinuities on audio streams.
-                mSource->queueDiscontinuity(true /* formatChange */);
+                mSource->queueDiscontinuity(type);
             }
             break;
         }
@@ -348,7 +348,7 @@
 
             if (mSource != NULL) {
                 mSource->clear();
-                mSource->queueDiscontinuity(!isASeek);
+                mSource->queueDiscontinuity(type);
             }
             break;
         }
@@ -561,6 +561,10 @@
             // After a discontinuity we invalidate the queue's format
             // and won't enqueue any access units to the source until
             // the queue has reestablished the new format.
+
+            if (mSource->getFormat() == NULL) {
+                mSource->setFormat(mQueue.getFormat());
+            }
             mSource->queueAccessUnit(accessUnit);
         }
     }
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index a8fe2c1..c6edf0a 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -33,6 +33,11 @@
       mEOSResult(OK) {
 }
 
+void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
+    CHECK(mFormat == NULL);
+    mFormat = meta;
+}
+
 AnotherPacketSource::~AnotherPacketSource() {
 }
 
@@ -61,8 +66,12 @@
         mBuffers.erase(mBuffers.begin());
 
         int32_t discontinuity;
-        if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)
-                && discontinuity) {
+        if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
+
+            if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) {
+                mFormat.clear();
+            }
+
             return INFO_DISCONTINUITY;
         }
 
@@ -86,8 +95,11 @@
         mBuffers.erase(mBuffers.begin());
 
         int32_t discontinuity;
-        if (buffer->meta()->findInt32("discontinuity", &discontinuity)
-                && discontinuity) {
+        if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
+            if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) {
+                mFormat.clear();
+            }
+
             return INFO_DISCONTINUITY;
         } else {
             int64_t timeUs;
@@ -123,13 +135,10 @@
     mCondition.signal();
 }
 
-void AnotherPacketSource::queueDiscontinuity(bool formatChange) {
+void AnotherPacketSource::queueDiscontinuity(
+        ATSParser::DiscontinuityType type) {
     sp<ABuffer> buffer = new ABuffer(0);
-    buffer->meta()->setInt32("discontinuity", true);
-
-    if (formatChange) {
-        buffer->meta()->setInt32("format-change", true);
-    }
+    buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
 
     Mutex::Autolock autoLock(mLock);
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index f25a067..c20fca3 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -23,6 +23,8 @@
 #include <utils/threads.h>
 #include <utils/List.h>
 
+#include "ATSParser.h"
+
 namespace android {
 
 struct ABuffer;
@@ -30,6 +32,8 @@
 struct AnotherPacketSource : public MediaSource {
     AnotherPacketSource(const sp<MetaData> &meta);
 
+    void setFormat(const sp<MetaData> &meta);
+
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
     virtual sp<MetaData> getFormat();
@@ -42,7 +46,7 @@
     status_t nextBufferTime(int64_t *timeUs);
 
     void queueAccessUnit(const sp<ABuffer> &buffer);
-    void queueDiscontinuity(bool formatChange);
+    void queueDiscontinuity(ATSParser::DiscontinuityType type);
     void signalEOS(status_t result);
 
     void clear();
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 4e7759d..73efdfe 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -225,6 +225,14 @@
 
             mFormat = MakeAACCodecSpecificData(
                     profile, sampling_freq_index, channel_configuration);
+
+            int32_t sampleRate;
+            int32_t numChannels;
+            CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate));
+            CHECK(mFormat->findInt32(kKeyChannelCount, &numChannels));
+
+            LOGI("found AAC codec config (%d Hz, %d channels)",
+                 sampleRate, numChannels);
         } else {
             // profile_ObjectType, sampling_frequency_index, private_bits,
             // channel_configuration, original_copy, home
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4cf01aa..e0397b1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9411,6 +9411,14 @@
             if (DEBUG_SERVICE) Slog.v(
                 TAG, "Removed service that is not running: " + r);
         }
+
+        if (r.bindings.size() > 0) {
+            r.bindings.clear();
+        }
+
+        if (r.restarter instanceof ServiceRestarter) {
+           ((ServiceRestarter)r.restarter).setService(null);
+        }
     }
 
     ComponentName startServiceLocked(IApplicationThread caller,
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 643dbf5..d9b67ea 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -88,8 +88,9 @@
             } else if (msg.what == MSG_WEBKIT_DATA) {
                 TestShellActivity.this.dump(mTimedOut, (String)msg.obj);
                 return;
+            } else if (msg.what == MSG_DUMP_TIMEOUT) {
+                throw new RuntimeException("WebView dump timeout, is it pegged?");
             }
-
             super.handleMessage(msg);
         }
     }
@@ -106,10 +107,12 @@
             case DUMP_AS_TEXT:
                 callback.arg1 = mDumpTopFrameAsText ? 1 : 0;
                 callback.arg2 = mDumpChildFramesAsText ? 1 : 0;
+                setDumpTimeout(DUMP_TIMEOUT_MS);
                 mWebView.documentAsText(callback);
                 break;
             case EXT_REPR:
                 mWebView.externalRepresentation(callback);
+                setDumpTimeout(DUMP_TIMEOUT_MS);
                 break;
             default:
                 finished();
@@ -117,6 +120,11 @@
         }
     }
 
+    private void setDumpTimeout(long timeout) {
+        Message msg = mHandler.obtainMessage(MSG_DUMP_TIMEOUT);
+        mHandler.sendMessageDelayed(msg, timeout);
+    }
+
     public void clearCache() {
       mWebView.freeMemory();
     }
@@ -933,9 +941,11 @@
     private boolean mDumpWebKitData = false;
 
     static final String TIMEOUT_STR = "**Test timeout";
+    static final long DUMP_TIMEOUT_MS = 20000; //20s timeout for dumping webview content
 
     static final int MSG_TIMEOUT = 0;
     static final int MSG_WEBKIT_DATA = 1;
+    static final int MSG_DUMP_TIMEOUT = 2;
 
     static final String LOGTAG="TestShell";