merge in jb-mr2-release history after reset to jb-mr2-dev
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index 61059bd..9dcb8d9 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -31,7 +31,7 @@
 
     virtual status_t initCheck() const = 0;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
 
     virtual status_t createPlugin(
             const uint8_t uuid[16], const void *data, size_t size) = 0;
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 2defc2d..98b183a 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -48,7 +48,7 @@
         return reply.readInt32();
     }
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const {
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
         data.write(uuid, 16);
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 42584fe..1c0268f 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -885,6 +885,11 @@
     if ((toneType < 0) || (toneType >= NUM_TONES))
         return lResult;
 
+    toneType = getToneForRegion(toneType);
+    if (toneType == TONE_CDMA_SIGNAL_OFF) {
+        return true;
+    }
+
     if (mState == TONE_IDLE) {
         ALOGV("startTone: try to re-init AudioTrack");
         if (!initAudioTrack()) {
@@ -897,7 +902,6 @@
     mLock.lock();
 
     // Get descriptor for requested tone
-    toneType = getToneForRegion(toneType);
     mpNewToneDesc = &sToneDescriptors[toneType];
 
     mDurationMs = durationMs;
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 0e8f913..ae4d845 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -17,6 +17,8 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Crypto"
 #include <utils/Log.h>
+#include <dirent.h>
+#include <dlfcn.h>
 
 #include "Crypto.h"
 
@@ -26,87 +28,176 @@
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 
-#include <dlfcn.h>
-
 namespace android {
 
+KeyedVector<Vector<uint8_t>, String8> Crypto::mUUIDToLibraryPathMap;
+KeyedVector<String8, wp<SharedLibrary> > Crypto::mLibraryPathToOpenLibraryMap;
+Mutex Crypto::mMapLock;
+
+static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
+    if (lhs.size() < rhs.size()) {
+        return true;
+    } else if (lhs.size() > rhs.size()) {
+        return false;
+    }
+
+    return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
+}
+
 Crypto::Crypto()
     : mInitCheck(NO_INIT),
-      mLibHandle(NULL),
       mFactory(NULL),
       mPlugin(NULL) {
-    mInitCheck = init();
 }
 
 Crypto::~Crypto() {
     delete mPlugin;
     mPlugin = NULL;
+    closeFactory();
+}
 
+void Crypto::closeFactory() {
     delete mFactory;
     mFactory = NULL;
-
-    if (mLibHandle != NULL) {
-        dlclose(mLibHandle);
-        mLibHandle = NULL;
-    }
+    mLibrary.clear();
 }
 
 status_t Crypto::initCheck() const {
     return mInitCheck;
 }
 
-status_t Crypto::init() {
-    mLibHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
+/*
+ * Search the plugins directory for a plugin that supports the scheme
+ * specified by uuid
+ *
+ * If found:
+ *    mLibrary holds a strong pointer to the dlopen'd library
+ *    mFactory is set to the library's factory method
+ *    mInitCheck is set to OK
+ *
+ * If not found:
+ *    mLibrary is cleared and mFactory are set to NULL
+ *    mInitCheck is set to an error (!OK)
+ */
+void Crypto::findFactoryForScheme(const uint8_t uuid[16]) {
 
-    if (mLibHandle == NULL) {
-        ALOGE("Unable to locate libdrmdecrypt.so");
+    closeFactory();
 
-        return ERROR_UNSUPPORTED;
+    // lock static maps
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    Vector<uint8_t> uuidVector;
+    uuidVector.appendArray(uuid, sizeof(uuid));
+    ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
+    if (index >= 0) {
+        if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
+            mInitCheck = OK;
+            return;
+        } else {
+            ALOGE("Failed to load from cached library path!");
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediadrm");
+    String8 pluginPath;
+
+    DIR* pDir = opendir(dirPath.string());
+    if (pDir) {
+        struct dirent* pEntry;
+        while ((pEntry = readdir(pDir))) {
+
+            pluginPath = dirPath + "/" + pEntry->d_name;
+
+            if (pluginPath.getPathExtension() == ".so") {
+
+                if (loadLibraryForScheme(pluginPath, uuid)) {
+                    mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
+                    mInitCheck = OK;
+                    closedir(pDir);
+                    return;
+                }
+            }
+        }
+
+        closedir(pDir);
+    }
+
+    // try the legacy libdrmdecrypt.so
+    pluginPath = "libdrmdecrypt.so";
+    if (loadLibraryForScheme(pluginPath, uuid)) {
+        mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
+        mInitCheck = OK;
+        return;
+    }
+
+    ALOGE("Failed to find crypto plugin");
+    mInitCheck = ERROR_UNSUPPORTED;
+}
+
+bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
+
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
     }
 
     typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
+
     CreateCryptoFactoryFunc createCryptoFactory =
-        (CreateCryptoFactoryFunc)dlsym(mLibHandle, "createCryptoFactory");
+        (CreateCryptoFactoryFunc)mLibrary->lookup("createCryptoFactory");
 
-    if (createCryptoFactory == NULL
-            || ((mFactory = createCryptoFactory()) == NULL)) {
-        if (createCryptoFactory == NULL) {
-            ALOGE("Unable to find symbol 'createCryptoFactory'.");
-        } else {
-            ALOGE("createCryptoFactory() failed.");
-        }
-
-        dlclose(mLibHandle);
-        mLibHandle = NULL;
-
-        return ERROR_UNSUPPORTED;
-    }
-
-    return OK;
-}
-
-bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) const {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
+    if (createCryptoFactory == NULL ||
+        (mFactory = createCryptoFactory()) == NULL ||
+        !mFactory->isCryptoSchemeSupported(uuid)) {
+        closeFactory();
         return false;
     }
+    return true;
+}
 
-    return mFactory->isCryptoSchemeSupported(uuid);
+bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
+        return true;
+    }
+
+    findFactoryForScheme(uuid);
+    return (mInitCheck == OK);
 }
 
 status_t Crypto::createPlugin(
         const uint8_t uuid[16], const void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
     if (mPlugin != NULL) {
         return -EINVAL;
     }
 
+    if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
+        findFactoryForScheme(uuid);
+    }
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
     return mFactory->createPlugin(uuid, data, size, &mPlugin);
 }
 
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index d066774..c44ae34 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -20,6 +20,9 @@
 
 #include <media/ICrypto.h>
 #include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include "SharedLibrary.h"
 
 namespace android {
 
@@ -32,7 +35,7 @@
 
     virtual status_t initCheck() const;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
 
     virtual status_t createPlugin(
             const uint8_t uuid[16], const void *data, size_t size);
@@ -56,11 +59,17 @@
     mutable Mutex mLock;
 
     status_t mInitCheck;
-    void *mLibHandle;
+    sp<SharedLibrary> mLibrary;
     CryptoFactory *mFactory;
     CryptoPlugin *mPlugin;
 
-    status_t init();
+    static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
+    static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+    static Mutex mMapLock;
+
+    void findFactoryForScheme(const uint8_t uuid[16]);
+    bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
+    void closeFactory();
 
     DISALLOW_EVIL_CONSTRUCTORS(Crypto);
 };
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index f81929c..f1f9f45 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -12,7 +12,6 @@
         rtp/RTPReceiver.cpp             \
         rtp/RTPSender.cpp               \
         sink/DirectRenderer.cpp         \
-        sink/TunnelRenderer.cpp         \
         sink/WifiDisplaySink.cpp        \
         SNTPClient.cpp                  \
         TimeSyncer.cpp                  \
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index d13a92e..123bc1c 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -124,10 +124,14 @@
             looper()->registerHandler(mTSSender);
 
             err = mTSSender->initAsync(
-                    transportMode,
                     remoteHost,
                     remoteRTPPort,
+                    transportMode,  // rtpMode
                     remoteRTCPPort,
+                    (transportMode == RTPSender::TRANSPORT_UDP
+                        && remoteRTCPPort >= 0)
+                        ? transportMode
+                        : RTPSender::TRANSPORT_NONE,  // rtcpMode
                     localRTPPort);
 
             if (err != OK) {
@@ -174,10 +178,13 @@
     looper()->registerHandler(info->mSender);
 
     status_t err = info->mSender->initAsync(
-            transportMode,
             remoteHost,
             remoteRTPPort,
+            transportMode,  // rtpMode
             remoteRTCPPort,
+            (transportMode == RTPSender::TRANSPORT_UDP && remoteRTCPPort >= 0)
+                ? transportMode
+                : RTPSender::TRANSPORT_NONE,  // rtcpMode
             localRTPPort);
 
     if (err != OK) {
@@ -260,37 +267,6 @@
                         tsPackets,
                         33 /* packetType */,
                         RTPSender::PACKETIZATION_TRANSPORT_STREAM);
-
-#if 0
-                {
-                    int64_t nowUs = ALooper::GetNowUs();
-
-                    int64_t timeUs;
-                    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
-                    int64_t delayMs = (nowUs - timeUs) / 1000ll;
-
-                    static const int64_t kMinDelayMs = 0;
-                    static const int64_t kMaxDelayMs = 300;
-
-                    const char *kPattern = "########################################";
-                    size_t kPatternSize = strlen(kPattern);
-
-                    int n = (kPatternSize * (delayMs - kMinDelayMs))
-                                / (kMaxDelayMs - kMinDelayMs);
-
-                    if (n < 0) {
-                        n = 0;
-                    } else if ((size_t)n > kPatternSize) {
-                        n = kPatternSize;
-                    }
-
-                    ALOGI("[%lld]: (%4lld ms) %s\n",
-                          timeUs / 1000,
-                          delayMs,
-                          kPattern + kPatternSize - n);
-                }
-#endif
             }
 
             if (err != OK) {
diff --git a/media/libstagefright/wifi-display/rtp/RTPBase.h b/media/libstagefright/wifi-display/rtp/RTPBase.h
index 6507a6f..e3fa845 100644
--- a/media/libstagefright/wifi-display/rtp/RTPBase.h
+++ b/media/libstagefright/wifi-display/rtp/RTPBase.h
@@ -29,6 +29,7 @@
 
     enum TransportMode {
         TRANSPORT_UNDEFINED,
+        TRANSPORT_NONE,
         TRANSPORT_UDP,
         TRANSPORT_TCP,
         TRANSPORT_TCP_INTERLEAVED,
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index c8e265c..c686e01 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -38,7 +38,8 @@
         const sp<AMessage> &notify)
     : mNetSession(netSession),
       mNotify(notify),
-      mMode(TRANSPORT_UNDEFINED),
+      mRTPMode(TRANSPORT_UNDEFINED),
+      mRTCPMode(TRANSPORT_UNDEFINED),
       mRTPSessionID(0),
       mRTCPSessionID(0),
       mRTPConnected(false),
@@ -74,18 +75,24 @@
 }
 
 status_t RTPSender::initAsync(
-        TransportMode mode,
         const char *remoteHost,
         int32_t remoteRTPPort,
+        TransportMode rtpMode,
         int32_t remoteRTCPPort,
+        TransportMode rtcpMode,
         int32_t *outLocalRTPPort) {
-    if (mMode != TRANSPORT_UNDEFINED || mode == TRANSPORT_UNDEFINED) {
+    if (mRTPMode != TRANSPORT_UNDEFINED
+            || rtpMode == TRANSPORT_UNDEFINED
+            || rtpMode == TRANSPORT_NONE
+            || rtcpMode == TRANSPORT_UNDEFINED) {
         return INVALID_OPERATION;
     }
 
-    CHECK_NE(mMode, TRANSPORT_TCP_INTERLEAVED);
+    CHECK_NE(rtpMode, TRANSPORT_TCP_INTERLEAVED);
+    CHECK_NE(rtcpMode, TRANSPORT_TCP_INTERLEAVED);
 
-    if (mode == TRANSPORT_TCP && remoteRTCPPort >= 0) {
+    if (rtcpMode == TRANSPORT_NONE && remoteRTCPPort >= 0
+            || rtcpMode != TRANSPORT_NONE && remoteRTCPPort < 0) {
         return INVALID_OPERATION;
     }
 
@@ -105,7 +112,7 @@
         localRTPPort = PickRandomRTPPort();
 
         status_t err;
-        if (mode == TRANSPORT_UDP) {
+        if (rtpMode == TRANSPORT_UDP) {
             err = mNetSession->createUDPSession(
                     localRTPPort,
                     remoteHost,
@@ -113,7 +120,7 @@
                     rtpNotify,
                     &mRTPSessionID);
         } else {
-            CHECK_EQ(mode, TRANSPORT_TCP);
+            CHECK_EQ(rtpMode, TRANSPORT_TCP);
             err = mNetSession->createTCPDatagramSession(
                     localRTPPort,
                     remoteHost,
@@ -130,7 +137,7 @@
             break;
         }
 
-        if (mode == TRANSPORT_UDP) {
+        if (rtcpMode == TRANSPORT_UDP) {
             err = mNetSession->createUDPSession(
                     localRTPPort + 1,
                     remoteHost,
@@ -138,7 +145,7 @@
                     rtcpNotify,
                     &mRTCPSessionID);
         } else {
-            CHECK_EQ(mode, TRANSPORT_TCP);
+            CHECK_EQ(rtcpMode, TRANSPORT_TCP);
             err = mNetSession->createTCPDatagramSession(
                     localRTPPort + 1,
                     remoteHost,
@@ -155,15 +162,20 @@
         mRTPSessionID = 0;
     }
 
-    if (mode == TRANSPORT_UDP) {
+    if (rtpMode == TRANSPORT_UDP) {
         mRTPConnected = true;
+    }
+
+    if (rtcpMode == TRANSPORT_UDP) {
         mRTCPConnected = true;
     }
 
-    mMode = mode;
+    mRTPMode = rtpMode;
+    mRTCPMode = rtcpMode;
     *outLocalRTPPort = localRTPPort;
 
-    if (mMode == TRANSPORT_UDP) {
+    if (mRTPMode == TRANSPORT_UDP
+            && (mRTCPMode == TRANSPORT_UDP || mRTCPMode == TRANSPORT_NONE)) {
         notifyInitDone(OK);
     }
 
@@ -496,12 +508,12 @@
                 mRTCPSessionID = 0;
             }
 
-            if (mMode == TRANSPORT_TCP) {
-                if (!mRTPConnected
-                        || (mRTCPSessionID > 0 && !mRTCPConnected)) {
-                    notifyInitDone(err);
-                    break;
-                }
+            if (!mRTPConnected
+                    || (mRTPMode != TRANSPORT_NONE && !mRTCPConnected)) {
+                // We haven't completed initialization, attach the error
+                // to the notification instead.
+                notifyInitDone(err);
+                break;
             }
 
             notifyError(err);
@@ -523,20 +535,21 @@
 
         case ANetworkSession::kWhatConnected:
         {
-            CHECK_EQ(mMode, TRANSPORT_TCP);
-
             int32_t sessionID;
             CHECK(msg->findInt32("sessionID", &sessionID));
 
             if  (isRTP) {
+                CHECK_EQ(mRTPMode, TRANSPORT_TCP);
                 CHECK_EQ(sessionID, mRTPSessionID);
                 mRTPConnected = true;
             } else {
+                CHECK_EQ(mRTCPMode, TRANSPORT_TCP);
                 CHECK_EQ(sessionID, mRTCPSessionID);
                 mRTCPConnected = true;
             }
 
-            if (mRTPConnected && (mRTCPSessionID == 0 || mRTCPConnected)) {
+            if (mRTPConnected
+                    && (mRTCPMode == TRANSPORT_NONE || mRTCPConnected)) {
                 notifyInitDone(OK);
             }
             break;
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index 90b1796..8409b8d 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -43,10 +43,11 @@
             const sp<AMessage> &notify);
 
     status_t initAsync(
-              TransportMode mode,
               const char *remoteHost,
               int32_t remoteRTPPort,
+              TransportMode rtpMode,
               int32_t remoteRTCPPort,
+              TransportMode rtcpMode,
               int32_t *outLocalRTPPort);
 
     status_t queueBuffer(
@@ -72,7 +73,8 @@
 
     sp<ANetworkSession> mNetSession;
     sp<AMessage> mNotify;
-    TransportMode mMode;
+    TransportMode mRTPMode;
+    TransportMode mRTCPMode;
     int32_t mRTPSessionID;
     int32_t mRTCPSessionID;
     bool mRTPConnected;
diff --git a/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp b/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
deleted file mode 100644
index 6b185db..0000000
--- a/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright 2012, 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 "TunnelRenderer"
-#include <utils/Log.h>
-
-#include "TunnelRenderer.h"
-
-#include "ATSParser.h"
-
-#include <binder/IMemory.h>
-#include <binder/IServiceManager.h>
-#include <gui/SurfaceComposerClient.h>
-#include <media/IMediaPlayerService.h>
-#include <media/IStreamSource.h>
-#include <media/mediaplayer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <ui/DisplayInfo.h>
-
-namespace android {
-
-struct TunnelRenderer::PlayerClient : public BnMediaPlayerClient {
-    PlayerClient() {}
-
-    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
-        ALOGI("notify %d, %d, %d", msg, ext1, ext2);
-    }
-
-protected:
-    virtual ~PlayerClient() {}
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(PlayerClient);
-};
-
-struct TunnelRenderer::StreamSource : public BnStreamSource {
-    StreamSource(TunnelRenderer *owner);
-
-    virtual void setListener(const sp<IStreamListener> &listener);
-    virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
-
-    virtual void onBufferAvailable(size_t index);
-
-    virtual uint32_t flags() const;
-
-    void doSomeWork();
-
-    void setTimeOffset(int64_t offset);
-
-protected:
-    virtual ~StreamSource();
-
-private:
-    mutable Mutex mLock;
-
-    TunnelRenderer *mOwner;
-
-    sp<IStreamListener> mListener;
-
-    Vector<sp<IMemory> > mBuffers;
-    List<size_t> mIndicesAvailable;
-
-    size_t mNumDeqeued;
-
-    int64_t mTimeOffsetUs;
-    bool mTimeOffsetChanged;
-
-    DISALLOW_EVIL_CONSTRUCTORS(StreamSource);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-TunnelRenderer::StreamSource::StreamSource(TunnelRenderer *owner)
-    : mOwner(owner),
-      mNumDeqeued(0),
-      mTimeOffsetUs(0ll),
-      mTimeOffsetChanged(false) {
-}
-
-TunnelRenderer::StreamSource::~StreamSource() {
-}
-
-void TunnelRenderer::StreamSource::setListener(
-        const sp<IStreamListener> &listener) {
-    mListener = listener;
-}
-
-void TunnelRenderer::StreamSource::setBuffers(
-        const Vector<sp<IMemory> > &buffers) {
-    mBuffers = buffers;
-}
-
-void TunnelRenderer::StreamSource::onBufferAvailable(size_t index) {
-    CHECK_LT(index, mBuffers.size());
-
-    {
-        Mutex::Autolock autoLock(mLock);
-        mIndicesAvailable.push_back(index);
-    }
-
-    doSomeWork();
-}
-
-uint32_t TunnelRenderer::StreamSource::flags() const {
-    return kFlagAlignedVideoData | kFlagIsRealTimeData;
-}
-
-void TunnelRenderer::StreamSource::doSomeWork() {
-    Mutex::Autolock autoLock(mLock);
-
-    while (!mIndicesAvailable.empty()) {
-        sp<ABuffer> srcBuffer = mOwner->dequeueBuffer();
-        if (srcBuffer == NULL) {
-            break;
-        }
-
-        ++mNumDeqeued;
-
-        if (mTimeOffsetChanged) {
-            sp<AMessage> extra = new AMessage;
-
-            extra->setInt32(
-                    IStreamListener::kKeyDiscontinuityMask,
-                    ATSParser::DISCONTINUITY_TIME_OFFSET);
-
-            extra->setInt64("offset", mTimeOffsetUs);
-
-            mListener->issueCommand(
-                    IStreamListener::DISCONTINUITY,
-                    false /* synchronous */,
-                    extra);
-
-            mTimeOffsetChanged = false;
-        }
-
-        ALOGV("dequeue TS packet of size %d", srcBuffer->size());
-
-        size_t index = *mIndicesAvailable.begin();
-        mIndicesAvailable.erase(mIndicesAvailable.begin());
-
-        sp<IMemory> mem = mBuffers.itemAt(index);
-        CHECK_LE(srcBuffer->size(), mem->size());
-        CHECK_EQ((srcBuffer->size() % 188), 0u);
-
-        memcpy(mem->pointer(), srcBuffer->data(), srcBuffer->size());
-        mListener->queueBuffer(index, srcBuffer->size());
-    }
-}
-
-void TunnelRenderer::StreamSource::setTimeOffset(int64_t offset) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (offset != mTimeOffsetUs) {
-        mTimeOffsetUs = offset;
-        mTimeOffsetChanged = true;
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-TunnelRenderer::TunnelRenderer(
-        const sp<IGraphicBufferProducer> &bufferProducer)
-    : mSurfaceTex(bufferProducer),
-      mStartup(true) {
-    mStreamSource = new StreamSource(this);
-}
-
-TunnelRenderer::~TunnelRenderer() {
-    destroyPlayer();
-}
-
-void TunnelRenderer::setTimeOffset(int64_t offset) {
-    mStreamSource->setTimeOffset(offset);
-}
-
-void TunnelRenderer::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        default:
-            TRESPASS();
-    }
-}
-
-void TunnelRenderer::initPlayer() {
-    if (mSurfaceTex == NULL) {
-        mComposerClient = new SurfaceComposerClient;
-        CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
-
-        DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(0, &info);
-        ssize_t displayWidth = info.w;
-        ssize_t displayHeight = info.h;
-
-        mSurfaceControl =
-            mComposerClient->createSurface(
-                    String8("A Surface"),
-                    displayWidth,
-                    displayHeight,
-                    PIXEL_FORMAT_RGB_565,
-                    0);
-
-        CHECK(mSurfaceControl != NULL);
-        CHECK(mSurfaceControl->isValid());
-
-        SurfaceComposerClient::openGlobalTransaction();
-        CHECK_EQ(mSurfaceControl->setLayer(INT_MAX), (status_t)OK);
-        CHECK_EQ(mSurfaceControl->show(), (status_t)OK);
-        SurfaceComposerClient::closeGlobalTransaction();
-
-        mSurface = mSurfaceControl->getSurface();
-        CHECK(mSurface != NULL);
-    }
-
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.player"));
-    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
-    CHECK(service.get() != NULL);
-
-    mPlayerClient = new PlayerClient;
-
-    mPlayer = service->create(mPlayerClient, 0);
-    CHECK(mPlayer != NULL);
-    CHECK_EQ(mPlayer->setDataSource(mStreamSource), (status_t)OK);
-
-    mPlayer->setVideoSurfaceTexture(
-            mSurfaceTex != NULL ? mSurfaceTex : mSurface->getIGraphicBufferProducer());
-
-    mPlayer->start();
-}
-
-void TunnelRenderer::destroyPlayer() {
-    mStreamSource.clear();
-
-    mPlayer->setVideoSurfaceTexture(NULL);
-
-    mPlayer->stop();
-    mPlayer.clear();
-
-    if (mSurfaceTex == NULL) {
-        mSurface.clear();
-        mSurfaceControl.clear();
-
-        mComposerClient->dispose();
-        mComposerClient.clear();
-    }
-}
-
-void TunnelRenderer::queueBuffer(const sp<ABuffer> &buffer) {
-    {
-        Mutex::Autolock autoLock(mLock);
-        mBuffers.push_back(buffer);
-    }
-
-    if (mStartup) {
-        initPlayer();
-        mStartup = false;
-    }
-
-    mStreamSource->doSomeWork();
-}
-
-sp<ABuffer> TunnelRenderer::dequeueBuffer() {
-    Mutex::Autolock autoLock(mLock);
-    if (mBuffers.empty()) {
-        return NULL;
-    }
-
-    sp<ABuffer> buf = *mBuffers.begin();
-    mBuffers.erase(mBuffers.begin());
-
-    return buf;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/wifi-display/sink/TunnelRenderer.h b/media/libstagefright/wifi-display/sink/TunnelRenderer.h
deleted file mode 100644
index 479e73c..0000000
--- a/media/libstagefright/wifi-display/sink/TunnelRenderer.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012, 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 TUNNEL_RENDERER_H_
-
-#define TUNNEL_RENDERER_H_
-
-#include <gui/Surface.h>
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct ABuffer;
-struct SurfaceComposerClient;
-struct SurfaceControl;
-struct Surface;
-struct IMediaPlayer;
-struct IStreamListener;
-
-// This class reassembles incoming RTP packets into the correct order
-// and sends the resulting transport stream to a mediaplayer instance
-// for playback.
-struct TunnelRenderer : public AHandler {
-    TunnelRenderer(const sp<IGraphicBufferProducer> &bufferProducer);
-
-    void queueBuffer(const sp<ABuffer> &buffer);
-    sp<ABuffer> dequeueBuffer();
-
-    void setTimeOffset(int64_t offset);
-
-    int64_t getAvgLatenessUs() {
-        return 0ll;
-    }
-
-protected:
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-    virtual ~TunnelRenderer();
-
-private:
-    struct PlayerClient;
-    struct StreamSource;
-
-    mutable Mutex mLock;
-
-    sp<IGraphicBufferProducer> mSurfaceTex;
-
-    bool mStartup;
-    List<sp<ABuffer> > mBuffers;
-
-    sp<SurfaceComposerClient> mComposerClient;
-    sp<SurfaceControl> mSurfaceControl;
-    sp<Surface> mSurface;
-    sp<PlayerClient> mPlayerClient;
-    sp<IMediaPlayer> mPlayer;
-    sp<StreamSource> mStreamSource;
-
-    void initPlayer();
-    void destroyPlayer();
-
-    DISALLOW_EVIL_CONSTRUCTORS(TunnelRenderer);
-};
-
-}  // namespace android
-
-#endif  // TUNNEL_RENDERER_H_
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index d993764..2c4a373 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -502,16 +502,121 @@
     // reserved = b1
     // the first fragment of "buffer" follows
 
+    // Each transport packet (except for the last one contributing to the PES
+    // payload) must contain a multiple of 16 bytes of payload per HDCP spec.
+    bool alignPayload =
+        (mFlags & (EMIT_HDCP20_DESCRIPTOR | EMIT_HDCP21_DESCRIPTOR));
+
+    /*
+       a) The very first PES transport stream packet contains
+
+       4 bytes of TS header
+       ... padding
+       14 bytes of static PES header
+       PES_private_data_len + 1 bytes (only if PES_private_data_len > 0)
+       numStuffingBytes bytes
+
+       followed by the payload
+
+       b) Subsequent PES transport stream packets contain
+
+       4 bytes of TS header
+       ... padding
+
+       followed by the payload
+    */
+
     size_t PES_packet_length = accessUnit->size() + 8 + numStuffingBytes;
     if (PES_private_data_len > 0) {
         PES_packet_length += PES_private_data_len + 1;
     }
 
-    size_t numTSPackets;
-    if (PES_packet_length <= 178) {
-        numTSPackets = 1;
-    } else {
-        numTSPackets = 1 + ((PES_packet_length - 178) + 183) / 184;
+    size_t numTSPackets = 1;
+
+    {
+        // Make sure the PES header fits into a single TS packet:
+        size_t PES_header_size = 14 + numStuffingBytes;
+        if (PES_private_data_len > 0) {
+            PES_header_size += PES_private_data_len + 1;
+        }
+
+        CHECK_LE(PES_header_size, 188u - 4u);
+
+        size_t sizeAvailableForPayload = 188 - 4 - PES_header_size;
+        size_t numBytesOfPayload = accessUnit->size();
+
+        if (numBytesOfPayload > sizeAvailableForPayload) {
+            numBytesOfPayload = sizeAvailableForPayload;
+
+            if (alignPayload && numBytesOfPayload > 16) {
+                numBytesOfPayload -= (numBytesOfPayload % 16);
+            }
+        }
+
+        // size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload;
+        ALOGV("packet 1 contains %zd padding bytes and %zd bytes of payload",
+              numPaddingBytes, numBytesOfPayload);
+
+        size_t numBytesOfPayloadRemaining = accessUnit->size() - numBytesOfPayload;
+
+#if 0
+        // The following hopefully illustrates the logic that led to the
+        // more efficient computation in the #else block...
+
+        while (numBytesOfPayloadRemaining > 0) {
+            size_t sizeAvailableForPayload = 188 - 4;
+
+            size_t numBytesOfPayload = numBytesOfPayloadRemaining;
+
+            if (numBytesOfPayload > sizeAvailableForPayload) {
+                numBytesOfPayload = sizeAvailableForPayload;
+
+                if (alignPayload && numBytesOfPayload > 16) {
+                    numBytesOfPayload -= (numBytesOfPayload % 16);
+                }
+            }
+
+            size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload;
+            ALOGI("packet %zd contains %zd padding bytes and %zd bytes of payload",
+                    numTSPackets + 1, numPaddingBytes, numBytesOfPayload);
+
+            numBytesOfPayloadRemaining -= numBytesOfPayload;
+            ++numTSPackets;
+        }
+#else
+        // This is how many bytes of payload each subsequent TS packet
+        // can contain at most.
+        sizeAvailableForPayload = 188 - 4;
+        size_t sizeAvailableForAlignedPayload = sizeAvailableForPayload;
+        if (alignPayload) {
+            // We're only going to use a subset of the available space
+            // since we need to make each fragment a multiple of 16 in size.
+            sizeAvailableForAlignedPayload -=
+                (sizeAvailableForAlignedPayload % 16);
+        }
+
+        size_t numFullTSPackets =
+            numBytesOfPayloadRemaining / sizeAvailableForAlignedPayload;
+
+        numTSPackets += numFullTSPackets;
+
+        numBytesOfPayloadRemaining -=
+            numFullTSPackets * sizeAvailableForAlignedPayload;
+
+        // numBytesOfPayloadRemaining < sizeAvailableForAlignedPayload
+        if (numFullTSPackets == 0 && numBytesOfPayloadRemaining > 0) {
+            // There wasn't enough payload left to form a full aligned payload,
+            // the last packet doesn't have to be aligned.
+            ++numTSPackets;
+        } else if (numFullTSPackets > 0
+                && numBytesOfPayloadRemaining
+                    + sizeAvailableForAlignedPayload > sizeAvailableForPayload) {
+            // The last packet emitted had a full aligned payload and together
+            // with the bytes remaining does exceed the unaligned payload
+            // size, so we need another packet.
+            ++numTSPackets;
+        }
+#endif
     }
 
     if (flags & EMIT_PAT_AND_PMT) {
@@ -755,8 +860,6 @@
 
     uint64_t PTS = (timeUs * 9ll) / 100ll;
 
-    bool padding = (PES_packet_length < (188 - 10));
-
     if (PES_packet_length >= 65536) {
         // This really should only happen for video.
         CHECK(track->isVideo());
@@ -765,19 +868,37 @@
         PES_packet_length = 0;
     }
 
+    size_t sizeAvailableForPayload = 188 - 4 - 14 - numStuffingBytes;
+    if (PES_private_data_len > 0) {
+        sizeAvailableForPayload -= PES_private_data_len + 1;
+    }
+
+    size_t copy = accessUnit->size();
+
+    if (copy > sizeAvailableForPayload) {
+        copy = sizeAvailableForPayload;
+
+        if (alignPayload && copy > 16) {
+            copy -= (copy % 16);
+        }
+    }
+
+    size_t numPaddingBytes = sizeAvailableForPayload - copy;
+
     uint8_t *ptr = packetDataStart;
     *ptr++ = 0x47;
     *ptr++ = 0x40 | (track->PID() >> 8);
     *ptr++ = track->PID() & 0xff;
-    *ptr++ = (padding ? 0x30 : 0x10) | track->incrementContinuityCounter();
 
-    if (padding) {
-        size_t paddingSize = 188 - 10 - PES_packet_length;
-        *ptr++ = paddingSize - 1;
-        if (paddingSize >= 2) {
+    *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
+                | track->incrementContinuityCounter();
+
+    if (numPaddingBytes > 0) {
+        *ptr++ = numPaddingBytes - 1;
+        if (numPaddingBytes >= 2) {
             *ptr++ = 0x00;
-            memset(ptr, 0xff, paddingSize - 2);
-            ptr += paddingSize - 2;
+            memset(ptr, 0xff, numPaddingBytes - 2);
+            ptr += numPaddingBytes - 2;
         }
     }
 
@@ -813,25 +934,14 @@
         *ptr++ = 0xff;
     }
 
-    // 18 bytes of TS/PES header leave 188 - 18 = 170 bytes for the payload
-
-    size_t sizeLeft = packetDataStart + 188 - ptr;
-    size_t copy = accessUnit->size();
-    if (copy > sizeLeft) {
-        copy = sizeLeft;
-    }
-
     memcpy(ptr, accessUnit->data(), copy);
     ptr += copy;
-    CHECK_EQ(sizeLeft, copy);
-    memset(ptr, 0xff, sizeLeft - copy);
 
+    CHECK_EQ(ptr, packetDataStart + 188);
     packetDataStart += 188;
 
     size_t offset = copy;
     while (offset < accessUnit->size()) {
-        bool padding = (accessUnit->size() - offset) < (188 - 4);
-
         // for subsequent fragments of "buffer":
         // 0x47
         // transport_error_indicator = b0
@@ -843,35 +953,40 @@
         // continuity_counter = b????
         // the fragment of "buffer" follows.
 
+        size_t sizeAvailableForPayload = 188 - 4;
+
+        size_t copy = accessUnit->size() - offset;
+
+        if (copy > sizeAvailableForPayload) {
+            copy = sizeAvailableForPayload;
+
+            if (alignPayload && copy > 16) {
+                copy -= (copy % 16);
+            }
+        }
+
+        size_t numPaddingBytes = sizeAvailableForPayload - copy;
+
         uint8_t *ptr = packetDataStart;
         *ptr++ = 0x47;
         *ptr++ = 0x00 | (track->PID() >> 8);
         *ptr++ = track->PID() & 0xff;
 
-        *ptr++ = (padding ? 0x30 : 0x10) | track->incrementContinuityCounter();
+        *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
+                    | track->incrementContinuityCounter();
 
-        if (padding) {
-            size_t paddingSize = 188 - 4 - (accessUnit->size() - offset);
-            *ptr++ = paddingSize - 1;
-            if (paddingSize >= 2) {
+        if (numPaddingBytes > 0) {
+            *ptr++ = numPaddingBytes - 1;
+            if (numPaddingBytes >= 2) {
                 *ptr++ = 0x00;
-                memset(ptr, 0xff, paddingSize - 2);
-                ptr += paddingSize - 2;
+                memset(ptr, 0xff, numPaddingBytes - 2);
+                ptr += numPaddingBytes - 2;
             }
         }
 
-        // 4 bytes of TS header leave 188 - 4 = 184 bytes for the payload
-
-        size_t sizeLeft = packetDataStart + 188 - ptr;
-        size_t copy = accessUnit->size() - offset;
-        if (copy > sizeLeft) {
-            copy = sizeLeft;
-        }
-
         memcpy(ptr, accessUnit->data() + offset, copy);
         ptr += copy;
-        CHECK_EQ(sizeLeft, copy);
-        memset(ptr, 0xff, sizeLeft - copy);
+        CHECK_EQ(ptr, packetDataStart + 188);
 
         offset += copy;
         packetDataStart += 188;
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 4f7dcc8..9fee4d0 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -43,7 +43,8 @@
             "               -u uri        \tconnect to an rtsp uri\n"
             "               -l ip[:port] \tlisten on the specified port "
             "               -f(ilename)  \tstream media "
-            "(create a sink)\n",
+            "(create a sink)\n"
+            "               -s(pecial)   \trun in 'special' mode\n",
             me);
 }
 
@@ -222,8 +223,10 @@
 
     AString path;
 
+    bool specialMode = false;
+
     int res;
-    while ((res = getopt(argc, argv, "hc:l:u:f:")) >= 0) {
+    while ((res = getopt(argc, argv, "hc:l:u:f:s")) >= 0) {
         switch (res) {
             case 'c':
             {
@@ -281,6 +284,12 @@
                 break;
             }
 
+            case 's':
+            {
+                specialMode = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
@@ -357,7 +366,7 @@
     sp<ALooper> looper = new ALooper;
 
     sp<WifiDisplaySink> sink = new WifiDisplaySink(
-            0 /* flags */,
+            specialMode ? WifiDisplaySink::FLAG_SPECIAL_MODE : 0 /* flags */,
             session,
             surface->getIGraphicBufferProducer());