Merge "audio flinger: pause direct output when underrunning" into mnc-dev
diff --git a/camera/Android.mk b/camera/Android.mk
index 4c4700b..471cb0d 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -28,6 +28,7 @@
 	ICameraClient.cpp \
 	ICameraService.cpp \
 	ICameraServiceListener.cpp \
+	ICameraServiceProxy.cpp \
 	ICameraRecordingProxy.cpp \
 	ICameraRecordingProxyListener.cpp \
 	camera2/ICameraDeviceUser.cpp \
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index a02dbe2..0071e70 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -494,7 +494,8 @@
                         __FUNCTION__, len);
                 return FAILED_TRANSACTION;
             }
-            int32_t events[len] = {};
+            int32_t events[len];
+            memset(events, 0, sizeof(int32_t) * len);
             status_t status = data.read(events, sizeof(int32_t) * len);
             if (status != NO_ERROR) {
                 ALOGE("%s: Received poorly formatted binder request: notifySystemEvent.",
diff --git a/camera/ICameraServiceProxy.cpp b/camera/ICameraServiceProxy.cpp
new file mode 100644
index 0000000..06a5afb
--- /dev/null
+++ b/camera/ICameraServiceProxy.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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_TAG "BpCameraServiceProxy"
+
+#include <stdint.h>
+
+#include <binder/Parcel.h>
+
+#include <camera/ICameraServiceProxy.h>
+
+namespace android {
+
+class BpCameraServiceProxy: public BpInterface<ICameraServiceProxy> {
+public:
+    BpCameraServiceProxy(const sp<IBinder>& impl) : BpInterface<ICameraServiceProxy>(impl) {}
+
+    virtual void pingForUserUpdate() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor());
+        remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, &reply,
+                IBinder::FLAG_ONEWAY);
+    }
+};
+
+
+IMPLEMENT_META_INTERFACE(CameraServiceProxy, "android.hardware.ICameraServiceProxy");
+
+status_t BnCameraServiceProxy::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags) {
+    switch(code) {
+        case PING_FOR_USER_UPDATE: {
+            CHECK_INTERFACE(ICameraServiceProxy, data, reply);
+            pingForUserUpdate();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+}; // namespace android
+
diff --git a/include/camera/ICameraServiceProxy.h b/include/camera/ICameraServiceProxy.h
new file mode 100644
index 0000000..12a555f
--- /dev/null
+++ b/include/camera/ICameraServiceProxy.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 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 ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
+#define ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class ICameraServiceProxy : public IInterface {
+public:
+    enum {
+        PING_FOR_USER_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
+    };
+
+    DECLARE_META_INTERFACE(CameraServiceProxy);
+
+    virtual void pingForUserUpdate() = 0;
+};
+
+class BnCameraServiceProxy: public BnInterface<ICameraServiceProxy>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+
+
+}; // namespace android
+
+#endif // ANDROID_HARDWARE_ICAMERASERVICEPROXY_H
+
+
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 3241e9c..26cffa6 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -158,6 +158,9 @@
     // or no HW sync source is used.
     static audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId);
 
+    // Indicate JAVA services are ready (scheduling, power management ...)
+    static status_t systemReady();
+
     // Events used to synchronize actions between audio sessions.
     // For instance SYNC_EVENT_PRESENTATION_COMPLETE can be used to delay recording start until
     // playback is complete on another audio session.
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 458f4b4..e9f0131 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -183,6 +183,10 @@
      * pid:                Process ID of the app which initially requested this AudioTrack
      *                     for power management tracking, or -1 for current process ID.
      * pAttributes:        If not NULL, supersedes streamType for use case selection.
+     * doNotReconnect:     If set to true, AudioTrack won't automatically recreate the IAudioTrack
+                           binder to AudioFlinger.
+                           It will return an error instead.  The application will recreate
+                           the track based on offloading or different channel configuration, etc.
      * threadCanCallJava:  Not present in parameter list, and so is fixed at false.
      */
 
@@ -200,7 +204,8 @@
                                     const audio_offload_info_t *offloadInfo = NULL,
                                     int uid = -1,
                                     pid_t pid = -1,
-                                    const audio_attributes_t* pAttributes = NULL);
+                                    const audio_attributes_t* pAttributes = NULL,
+                                    bool doNotReconnect = false);
 
     /* Creates an audio track and registers it with AudioFlinger.
      * With this constructor, the track is configured for static buffer mode.
@@ -228,7 +233,8 @@
                                     const audio_offload_info_t *offloadInfo = NULL,
                                     int uid = -1,
                                     pid_t pid = -1,
-                                    const audio_attributes_t* pAttributes = NULL);
+                                    const audio_attributes_t* pAttributes = NULL,
+                                    bool doNotReconnect = false);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioTrack.
@@ -272,7 +278,8 @@
                             const audio_offload_info_t *offloadInfo = NULL,
                             int uid = -1,
                             pid_t pid = -1,
-                            const audio_attributes_t* pAttributes = NULL);
+                            const audio_attributes_t* pAttributes = NULL,
+                            bool doNotReconnect = false);
 
     /* Result of constructing the AudioTrack. This must be checked for successful initialization
      * before using any AudioTrack API (except for set()), because using
@@ -877,6 +884,8 @@
         // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
         // mLock must be held to read or write those bits reliably.
 
+    bool                    mDoNotReconnect;
+
     int                     mSessionId;
     int                     mAuxEffectId;
 
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 3f7fd09..5051aff 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -243,6 +243,9 @@
 
     /* Get the HW synchronization source used for an audio session */
     virtual audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId) = 0;
+
+    /* Indicate JAVA services are ready (scheduling, power management ...) */
+    virtual status_t systemReady() = 0;
 };
 
 
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index fa917f9..46f900e 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -113,7 +113,8 @@
                 AudioCallback cb = NULL,
                 void *cookie = NULL,
                 audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                const audio_offload_info_t *offloadInfo = NULL) = 0;
+                const audio_offload_info_t *offloadInfo = NULL,
+                bool doNotReconnect = false) = 0;
 
         virtual status_t    start() = 0;
 
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index ce34338..df5e519 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -32,6 +32,8 @@
 
 namespace android {
 
+extern const char *kMaxEncoderInputBuffers;
+
 struct AMessage;
 
 struct MediaCodecList : public BnMediaCodecList {
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 6aeb919..d904ab6 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -27,6 +27,7 @@
 
 #include <cutils/log.h>
 #include "EffectBundle.h"
+#include "math.h"
 
 
 // effect_handle_t interface implementation for bass boost
@@ -830,32 +831,69 @@
     int gainCorrection = 0;
     //Count the energy contribution per band for EQ and BassBoost only if they are active.
     float energyContribution = 0;
+    float energyCross = 0;
+    float energyBassBoost = 0;
+    float crossCorrection = 0;
 
     //EQ contribution
     if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
         for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
-            float bandEnergy = (pContext->pBundledContext->bandGaindB[i] *
-                    LimitLevel_bandEnergyContribution[i])/15.0;
+            float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
+            float bandCoefficient = LimitLevel_bandEnergyCoefficient[i];
+            float bandEnergy = bandFactor * bandCoefficient * bandCoefficient;
             if (bandEnergy > 0)
                 energyContribution += bandEnergy;
         }
+
+        //cross EQ coefficients
+        float bandFactorSum = 0;
+        for (int i = 0; i < FIVEBAND_NUMBANDS-1; i++) {
+            float bandFactor1 = pContext->pBundledContext->bandGaindB[i]/15.0;
+            float bandFactor2 = pContext->pBundledContext->bandGaindB[i+1]/15.0;
+
+            if (bandFactor1 > 0 && bandFactor2 > 0) {
+                float crossEnergy = bandFactor1 * bandFactor2 *
+                        LimitLevel_bandEnergyCrossCoefficient[i];
+                bandFactorSum += bandFactor1 * bandFactor2;
+
+                if (crossEnergy > 0)
+                    energyCross += crossEnergy;
+            }
+        }
+        bandFactorSum -= 1.0;
+        if (bandFactorSum > 0)
+            crossCorrection = bandFactorSum * 0.7;
     }
 
     //BassBoost contribution
     if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
-        float bandEnergy = (pContext->pBundledContext->BassStrengthSaved *
-                LimitLevel_bassBoostEnergyContribution)/1000.0;
-        if (bandEnergy > 0)
-            energyContribution += bandEnergy;
+        float boostFactor = (pContext->pBundledContext->BassStrengthSaved)/1000.0;
+        float boostCoefficient = LimitLevel_bassBoostEnergyCoefficient;
+
+        energyContribution += boostFactor * boostCoefficient * boostCoefficient;
+
+        for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
+            float bandFactor = pContext->pBundledContext->bandGaindB[i]/15.0;
+            float bandCrossCoefficient = LimitLevel_bassBoostEnergyCrossCoefficient[i];
+            float bandEnergy = boostFactor * bandFactor *
+                    bandCrossCoefficient;
+            if (bandEnergy > 0)
+                energyBassBoost += bandEnergy;
+        }
     }
 
     //Virtualizer contribution
     if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
-                   energyContribution += LimitLevel_virtualizerContribution;
-        }
+        energyContribution += LimitLevel_virtualizerContribution *
+                LimitLevel_virtualizerContribution;
+    }
+
+    double totalEnergyEstimation = sqrt(energyContribution + energyCross + energyBassBoost) -
+            crossCorrection;
+    ALOGV(" TOTAL energy estimation: %0.2f", totalEnergyEstimation);
 
     //roundoff
-    int maxLevelRound = (int)(energyContribution + 0.99);
+    int maxLevelRound = (int)(totalEnergyEstimation + 0.99);
     if (maxLevelRound + pContext->pBundledContext->volume > 0) {
         gainCorrection = maxLevelRound + pContext->pBundledContext->volume;
     }
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index b3071f4..9459b87 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -200,10 +200,16 @@
  * updated.
  */
 
-static const float LimitLevel_bandEnergyContribution[FIVEBAND_NUMBANDS] = {
-        5.0, 6.5, 6.45, 4.8, 1.7 };
+static const float LimitLevel_bandEnergyCoefficient[FIVEBAND_NUMBANDS] = {
+        7.56, 9.69, 9.59, 7.37, 2.88};
 
-static const float LimitLevel_bassBoostEnergyContribution = 6.7;
+static const float LimitLevel_bandEnergyCrossCoefficient[FIVEBAND_NUMBANDS-1] = {
+        126.0, 115.0, 125.0, 104.0 };
+
+static const float LimitLevel_bassBoostEnergyCrossCoefficient[FIVEBAND_NUMBANDS] = {
+        221.21, 208.10, 28.16, 0.0, 0.0 };
+
+static const float LimitLevel_bassBoostEnergyCoefficient = 7.12;
 
 static const float LimitLevel_virtualizerContribution = 1.9;
 
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 4c2e77b..6c2c226 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -423,6 +423,13 @@
     return af->getAudioHwSyncForSession(sessionId);
 }
 
+status_t AudioSystem::systemReady()
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return NO_INIT;
+    return af->systemReady();
+}
+
 // ---------------------------------------------------------------------------
 
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index db316b0..faf5935 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -178,7 +178,8 @@
         const audio_offload_info_t *offloadInfo,
         int uid,
         pid_t pid,
-        const audio_attributes_t* pAttributes)
+        const audio_attributes_t* pAttributes,
+        bool doNotReconnect)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -189,7 +190,7 @@
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
-            offloadInfo, uid, pid, pAttributes);
+            offloadInfo, uid, pid, pAttributes, doNotReconnect);
 }
 
 AudioTrack::AudioTrack(
@@ -207,7 +208,8 @@
         const audio_offload_info_t *offloadInfo,
         int uid,
         pid_t pid,
-        const audio_attributes_t* pAttributes)
+        const audio_attributes_t* pAttributes,
+        bool doNotReconnect)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -218,7 +220,7 @@
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
             sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
-            uid, pid, pAttributes);
+            uid, pid, pAttributes, doNotReconnect);
 }
 
 AudioTrack::~AudioTrack()
@@ -266,7 +268,8 @@
         const audio_offload_info_t *offloadInfo,
         int uid,
         pid_t pid,
-        const audio_attributes_t* pAttributes)
+        const audio_attributes_t* pAttributes,
+        bool doNotReconnect)
 {
     ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
           "flags #%x, notificationFrames %u, sessionId %d, transferType %d, uid %d, pid %d",
@@ -308,6 +311,7 @@
     }
     mSharedBuffer = sharedBuffer;
     mTransfer = transferType;
+    mDoNotReconnect = doNotReconnect;
 
     ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(),
             sharedBuffer->size());
@@ -2006,7 +2010,7 @@
     // output parameters and new IAudioFlinger in createTrack_l()
     AudioSystem::clearAudioConfigCache();
 
-    if (isOffloadedOrDirect_l()) {
+    if (isOffloadedOrDirect_l() || mDoNotReconnect) {
         // FIXME re-creation of offloaded tracks is not yet implemented
         return DEAD_OBJECT;
     }
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index d722fe9..a3f014b 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -80,7 +80,8 @@
     RELEASE_AUDIO_PATCH,
     LIST_AUDIO_PATCHES,
     SET_AUDIO_PORT_CONFIG,
-    GET_AUDIO_HW_SYNC
+    GET_AUDIO_HW_SYNC,
+    SYSTEM_READY
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -903,6 +904,12 @@
         }
         return (audio_hw_sync_t)reply.readInt32();
     }
+    virtual status_t systemReady()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        return remote()->transact(SYSTEM_READY, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -1396,6 +1403,11 @@
             reply->writeInt32(getAudioHwSyncForSession((audio_session_t)data.readInt32()));
             return NO_ERROR;
         } break;
+        case SYSTEM_READY: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            systemReady();
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 7ae946d..6902e99 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -48,7 +48,7 @@
 template <typename T>
 static void readFromParcel(const Parcel &data, Vector<T> *items) {
     size_t size = (size_t)data.readUint32();
-    for (size_t i = 0; i < size; i++) {
+    for (size_t i = 0; i < size && data.dataAvail() > 0; i++) {
         T item;
         item.readFromParcel(data);
         items->add(item);
@@ -119,8 +119,6 @@
     switch (code) {
         case CONFIG: {
             CHECK_INTERFACE(IResourceManagerService, data, reply);
-            sp<IResourceManagerClient> client(
-                    interface_cast<IResourceManagerClient>(data.readStrongBinder()));
             Vector<MediaResourcePolicy> policies;
             readFromParcel(data, &policies);
             config(policies);
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 271be0c..34deb59 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -85,12 +85,18 @@
 
     // create the output AudioTrack
     mAudioTrack = new AudioTrack();
-    mAudioTrack->set(AUDIO_STREAM_MUSIC,  //TODO parameterize this
+    status_t status = mAudioTrack->set(AUDIO_STREAM_MUSIC,  //TODO parameterize this
             pLibConfig->sampleRate,
             AUDIO_FORMAT_PCM_16_BIT,
             audio_channel_out_mask_from_count(pLibConfig->numChannels),
             (size_t) mTrackBufferSize,
             AUDIO_OUTPUT_FLAG_NONE);
+    if (status != OK) {
+        ALOGE("JetPlayer::init(): Error initializing JET library; AudioTrack error %d", status);
+        mAudioTrack.clear();
+        mState = EAS_STATE_ERROR;
+        return EAS_FAILURE;
+    }
 
     // create render and playback thread
     {
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 891a9e9..9c0af4a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1489,7 +1489,8 @@
         audio_format_t format, int bufferCount,
         AudioCallback cb, void *cookie,
         audio_output_flags_t flags,
-        const audio_offload_info_t *offloadInfo)
+        const audio_offload_info_t *offloadInfo,
+        bool doNotReconnect)
 {
     mCallback = cb;
     mCallbackCookie = cookie;
@@ -1605,7 +1606,8 @@
                     offloadInfo,
                     mUid,
                     mPid,
-                    mAttributes);
+                    mAttributes,
+                    doNotReconnect);
         } else {
             t = new AudioTrack(
                     mStreamType,
@@ -1622,12 +1624,14 @@
                     NULL, // offload info
                     mUid,
                     mPid,
-                    mAttributes);
+                    mAttributes,
+                    doNotReconnect);
         }
 
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
             ALOGE("Unable to create audio track");
             delete newcbd;
+            // t goes out of scope, so reference count drops to zero
             return NO_INIT;
         } else {
             // successful AudioTrack initialization implies a legacy stream type was generated
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 5103841..e9f72b8 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -97,7 +97,8 @@
                 audio_format_t format, int bufferCount,
                 AudioCallback cb, void *cookie,
                 audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                const audio_offload_info_t *offloadInfo = NULL);
+                const audio_offload_info_t *offloadInfo = NULL,
+                bool doNotReconnect = false);
 
         virtual status_t        start();
         virtual ssize_t         write(const void* buffer, size_t size, bool blocking = true);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 5e7b644..88a7745 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1510,17 +1510,7 @@
                 mVideoTimeUs = timeUs;
             }
 
-            // formatChange && seeking: track whose source is changed during selection
-            // formatChange && !seeking: track whose source is not changed during selection
-            // !formatChange: normal seek
-            if ((seeking || formatChange)
-                    && (trackType == MEDIA_TRACK_TYPE_AUDIO
-                    || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
-                ATSParser::DiscontinuityType type = (formatChange && seeking)
-                        ? ATSParser::DISCONTINUITY_FORMATCHANGE
-                        : ATSParser::DISCONTINUITY_NONE;
-                track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
-            }
+            queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
 
             sp<ABuffer> buffer = mediaBufferToABuffer(
                     mbuf, trackType, seekTimeUs, actualTimeUs);
@@ -1538,10 +1528,26 @@
                     false /* discard */);
 #endif
         } else {
+            queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
             track->mPackets->signalEOS(err);
             break;
         }
     }
 }
 
+void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
+        bool seeking, bool formatChange, media_track_type trackType, Track *track) {
+    // formatChange && seeking: track whose source is changed during selection
+    // formatChange && !seeking: track whose source is not changed during selection
+    // !formatChange: normal seek
+    if ((seeking || formatChange)
+            && (trackType == MEDIA_TRACK_TYPE_AUDIO
+            || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
+        ATSParser::DiscontinuityType type = (formatChange && seeking)
+                ? ATSParser::DISCONTINUITY_FORMATCHANGE
+                : ATSParser::DISCONTINUITY_NONE;
+        track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
+    }
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 7fab051..0a75e4c 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -200,6 +200,9 @@
             media_track_type trackType,
             int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false);
 
+    void queueDiscontinuityIfNeeded(
+            bool seeking, bool formatChange, media_track_type trackType, Track *track);
+
     void schedulePollBuffering();
     void cancelPollBuffering();
     void restartPollBuffering();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 96a7adb..a79858c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1083,12 +1083,12 @@
             } else if (what == Renderer::kWhatMediaRenderingStart) {
                 ALOGV("media rendering started");
                 notifyListener(MEDIA_STARTED, 0, 0);
-            } else if (what == Renderer::kWhatAudioOffloadTearDown) {
-                ALOGV("Tear down audio offload, fall back to s/w path if due to error.");
+            } else if (what == Renderer::kWhatAudioTearDown) {
                 int64_t positionUs;
                 CHECK(msg->findInt64("positionUs", &positionUs));
                 int32_t reason;
                 CHECK(msg->findInt32("reason", &reason));
+                ALOGV("Tear down audio with reason %d.", reason);
                 closeAudioSink();
                 mAudioDecoder.clear();
                 ++mAudioDecoderGeneration;
@@ -1100,9 +1100,22 @@
                 }
 
                 performSeek(positionUs);
+
                 if (reason == Renderer::kDueToError) {
-                    mRenderer->signalDisableOffloadAudio();
-                    mOffloadAudio = false;
+                    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+                    sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
+                    audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
+                    const bool hasVideo = (videoFormat != NULL);
+                    const bool canOffload = canOffloadStream(
+                            audioMeta, hasVideo, true /* is_streaming */, streamType);
+                    if (canOffload) {
+                        mRenderer->signalEnableOffloadAudio();
+                        sp<AMessage> format = mSource->getFormat(true /*audio*/);
+                        tryOpenAudioSinkForOffload(format, hasVideo);
+                    } else {
+                        mRenderer->signalDisableOffloadAudio();
+                        mOffloadAudio = false;
+                    }
                     instantiateDecoder(true /* audio */, &mAudioDecoder);
                 }
             }
@@ -1140,6 +1153,22 @@
             ALOGV("kWhatSeek seekTimeUs=%lld us, needNotify=%d",
                     (long long)seekTimeUs, needNotify);
 
+            if (!mStarted) {
+                // Seek before the player is started. In order to preview video,
+                // need to start the player and pause it. This branch is called
+                // only once if needed. After the player is started, any seek
+                // operation will go through normal path.
+                // All cases, including audio-only, are handled in the same way
+                // for the sake of simplicity.
+                onStart(seekTimeUs);
+                onPause();
+                mPausedByClient = true;
+                if (needNotify) {
+                    notifyDriverSeekComplete();
+                }
+                break;
+            }
+
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
                                            FLUSH_CMD_FLUSH /* video */));
@@ -1233,13 +1262,16 @@
     return OK;
 }
 
-void NuPlayer::onStart() {
+void NuPlayer::onStart(int64_t startPositionUs) {
     mOffloadAudio = false;
     mAudioEOS = false;
     mVideoEOS = false;
     mStarted = true;
 
     mSource->start();
+    if (startPositionUs > 0) {
+        performSeek(startPositionUs);
+    }
 
     uint32_t flags = 0;
 
@@ -1895,11 +1927,15 @@
 void NuPlayer::finishResume() {
     if (mResumePending) {
         mResumePending = false;
-        if (mDriver != NULL) {
-            sp<NuPlayerDriver> driver = mDriver.promote();
-            if (driver != NULL) {
-                driver->notifySeekComplete();
-            }
+        notifyDriverSeekComplete();
+    }
+}
+
+void NuPlayer::notifyDriverSeekComplete() {
+    if (mDriver != NULL) {
+        sp<NuPlayerDriver> driver = mDriver.promote();
+        if (driver != NULL) {
+            driver->notifySeekComplete();
         }
     }
 }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index f417f48..d7aa830 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -233,7 +233,7 @@
     void handleFlushComplete(bool audio, bool isDecoder);
     void finishFlushIfPossible();
 
-    void onStart();
+    void onStart(int64_t startPositionUs = -1);
     void onResume();
     void onPause();
 
@@ -242,6 +242,7 @@
     void flushDecoder(bool audio, bool needShutdown);
 
     void finishResume();
+    void notifyDriverSeekComplete();
 
     void postScanSources();
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 376c93a..6abc81c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -68,6 +68,7 @@
 }
 
 NuPlayer::Decoder::~Decoder() {
+    mCodec->release();
     releaseAndResetMediaBuffers();
 }
 
@@ -414,6 +415,11 @@
     sp<ABuffer> buffer;
     mCodec->getInputBuffer(index, &buffer);
 
+    if (buffer == NULL) {
+        handleError(UNKNOWN_ERROR);
+        return false;
+    }
+
     if (index >= mInputBuffers.size()) {
         for (size_t i = mInputBuffers.size(); i <= index; ++i) {
             mInputBuffers.add();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 231f2e1..84ae25e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -397,23 +397,13 @@
     switch (mState) {
         case STATE_PREPARED:
         case STATE_STOPPED_AND_PREPARED:
-        {
-            mStartupSeekTimeUs = seekTimeUs;
-            // pretend that the seek completed. It will actually happen when starting playback.
-            // TODO: actually perform the seek here, so the player is ready to go at the new
-            // location
-            notifySeekComplete_l();
-            break;
-        }
-
-        case STATE_RUNNING:
         case STATE_PAUSED:
+            mStartupSeekTimeUs = seekTimeUs;
+            // fall through.
+        case STATE_RUNNING:
         {
             mAtEOS = false;
             mSeekInProgress = true;
-            if (mState == STATE_PAUSED) {
-               mStartupSeekTimeUs = seekTimeUs;
-            }
             // seeks can take a while, so we essentially paused
             notifyListener_l(MEDIA_PAUSED);
             mPlayer->seekToAsync(seekTimeUs, true /* needNotify */);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 007a335..409dedf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -82,7 +82,7 @@
       mVideoRenderingStartGeneration(0),
       mAudioRenderingStartGeneration(0),
       mAudioOffloadPauseTimeoutGeneration(0),
-      mAudioOffloadTornDown(false),
+      mAudioTornDown(false),
       mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
       mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER),
       mTotalBuffersQueued(0),
@@ -566,9 +566,9 @@
             break;
         }
 
-        case kWhatAudioOffloadTearDown:
+        case kWhatAudioTearDown:
         {
-            onAudioOffloadTearDown(kDueToError);
+            onAudioTearDown(kDueToError);
             break;
         }
 
@@ -580,7 +580,7 @@
                 break;
             }
             ALOGV("Audio Offload tear down due to pause timeout.");
-            onAudioOffloadTearDown(kDueToTimeout);
+            onAudioTearDown(kDueToTimeout);
             mWakeLock->release();
             break;
         }
@@ -648,7 +648,7 @@
 
         case MediaPlayerBase::AudioSink::CB_EVENT_TEAR_DOWN:
         {
-            me->notifyAudioOffloadTearDown();
+            me->notifyAudioTearDown();
             break;
         }
     }
@@ -792,6 +792,7 @@
                 ALOGW("AudioSink write would block when writing %zu bytes", copy);
             } else {
                 ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy);
+                notifyAudioTearDown();
             }
             break;
         }
@@ -1060,8 +1061,8 @@
     notify->post(delayUs);
 }
 
-void NuPlayer::Renderer::notifyAudioOffloadTearDown() {
-    (new AMessage(kWhatAudioOffloadTearDown, this))->post();
+void NuPlayer::Renderer::notifyAudioTearDown() {
+    (new AMessage(kWhatAudioTearDown, this))->post();
 }
 
 void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
@@ -1480,11 +1481,11 @@
     return durationUs;
 }
 
-void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reason) {
-    if (mAudioOffloadTornDown) {
+void NuPlayer::Renderer::onAudioTearDown(AudioTearDownReason reason) {
+    if (mAudioTornDown) {
         return;
     }
-    mAudioOffloadTornDown = true;
+    mAudioTornDown = true;
 
     int64_t currentPositionUs;
     if (getCurrentPosition(&currentPositionUs) != OK) {
@@ -1495,7 +1496,7 @@
     mAudioSink->flush();
 
     sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatAudioOffloadTearDown);
+    notify->setInt32("what", kWhatAudioTearDown);
     notify->setInt64("positionUs", currentPositionUs);
     notify->setInt32("reason", reason);
     notify->post();
@@ -1653,7 +1654,9 @@
                     8 /* bufferCount */,
                     NULL,
                     NULL,
-                    (audio_output_flags_t)pcmFlags);
+                    (audio_output_flags_t)pcmFlags,
+                    NULL,
+                    true /* doNotReconnect */);
         if (err == OK) {
             err = mAudioSink->setPlaybackRate(mPlaybackSettings);
         }
@@ -1668,9 +1671,7 @@
     if (audioSinkChanged) {
         onAudioSinkChanged();
     }
-    if (offloadingAudio()) {
-        mAudioOffloadTornDown = false;
-    }
+    mAudioTornDown = false;
     return OK;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 928b71b..fbdf5bf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -82,16 +82,16 @@
     void closeAudioSink();
 
     enum {
-        kWhatEOS                 = 'eos ',
-        kWhatFlushComplete       = 'fluC',
-        kWhatPosition            = 'posi',
-        kWhatVideoRenderingStart = 'vdrd',
-        kWhatMediaRenderingStart = 'mdrd',
-        kWhatAudioOffloadTearDown = 'aOTD',
+        kWhatEOS                      = 'eos ',
+        kWhatFlushComplete            = 'fluC',
+        kWhatPosition                 = 'posi',
+        kWhatVideoRenderingStart      = 'vdrd',
+        kWhatMediaRenderingStart      = 'mdrd',
+        kWhatAudioTearDown            = 'adTD',
         kWhatAudioOffloadPauseTimeout = 'aOPT',
     };
 
-    enum AudioOffloadTearDownReason {
+    enum AudioTearDownReason {
         kDueToError = 0,
         kDueToTimeout,
     };
@@ -179,7 +179,7 @@
     int64_t mLastPositionUpdateUs;
 
     int32_t mAudioOffloadPauseTimeoutGeneration;
-    bool mAudioOffloadTornDown;
+    bool mAudioTornDown;
     audio_offload_info_t mCurrentOffloadInfo;
 
     struct PcmInfo {
@@ -242,7 +242,7 @@
     int32_t getQueueGeneration(bool audio);
     int32_t getDrainGeneration(bool audio);
     bool getSyncQueues();
-    void onAudioOffloadTearDown(AudioOffloadTearDownReason reason);
+    void onAudioTearDown(AudioTearDownReason reason);
     status_t onOpenAudioSink(
             const sp<AMessage> &format,
             bool offloadOnly,
@@ -255,7 +255,7 @@
     void notifyPosition();
     void notifyVideoLateBy(int64_t lateByUs);
     void notifyVideoRenderingStart();
-    void notifyAudioOffloadTearDown();
+    void notifyAudioTearDown();
 
     void flushQueue(List<QueueEntry> *queue);
     bool dropBufferIfStale(bool audio, const sp<AMessage> &msg);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 34bd4c7..70480a2 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2857,7 +2857,9 @@
             break;
     }
 
-    ALOGI("setupVideoEncoder succeeded");
+    if (err == OK) {
+        ALOGI("setupVideoEncoder succeeded");
+    }
 
     return err;
 }
@@ -5124,7 +5126,7 @@
     sp<CodecObserver> observer = new CodecObserver;
     IOMX::node_id node = 0;
 
-    status_t err = OMX_ErrorComponentNotFound;
+    status_t err = NAME_NOT_FOUND;
     for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
             ++matchIndex) {
         componentName = matchingCodecs.itemAt(matchIndex).mName.string();
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index e5a6a9b..34f0148 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -85,6 +85,9 @@
                     this,
                     frameCount /*notificationFrames*/);
         mInitCheck = mRecord->initCheck();
+        if (mInitCheck != OK) {
+            mRecord.clear();
+        }
     } else {
         mInitCheck = status;
     }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 46c154d..6f22e26 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -26,6 +26,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
+#include <gui/BufferQueue.h>
 #include <gui/Surface.h>
 #include <media/ICrypto.h>
 #include <media/IOMX.h>
@@ -320,6 +321,27 @@
     CHECK_EQ(client.connect(), (status_t)OK);
     sp<IOMX> omx = client.interface();
 
+    const sp<IMediaCodecList> mediaCodecList = MediaCodecList::getInstance();
+    if (mediaCodecList == NULL) {
+        ALOGE("Failed to obtain MediaCodecList!");
+        return NULL; // if called from Java should raise IOException
+    }
+
+    AString tmp;
+    sp<AMessage> globalSettings = mediaCodecList->getGlobalSettings();
+    if (globalSettings == NULL || !globalSettings->findString(
+            kMaxEncoderInputBuffers, &tmp)) {
+        ALOGE("Failed to get encoder input buffer count!");
+        return NULL;
+    }
+
+    int32_t bufferCount = strtol(tmp.c_str(), NULL, 10);
+    if (bufferCount <= 0
+            || bufferCount > BufferQueue::MAX_MAX_ACQUIRED_BUFFERS) {
+        ALOGE("Encoder input buffer count is invalid!");
+        return NULL;
+    }
+
     sp<IGraphicBufferProducer> bufferProducer;
     sp<IGraphicBufferConsumer> bufferConsumer;
 
@@ -331,6 +353,14 @@
         return NULL;
     }
 
+    err = bufferConsumer->setMaxAcquiredBufferCount(bufferCount);
+
+    if (err != NO_ERROR) {
+        ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
+                bufferCount, err);
+        return NULL;
+    }
+
     return new PersistentSurface(bufferProducer, bufferConsumer);
 }
 
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index d2352bc..6708828 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -42,6 +42,8 @@
 
 namespace android {
 
+const char *kMaxEncoderInputBuffers = "max-video-encoder-input-buffers";
+
 static Mutex sInitMutex;
 
 static MediaCodecList *gCodecList = NULL;
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 0d95676..006454d 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -25,8 +25,10 @@
 #include <media/IMediaCodecList.h>
 #include <media/MediaCodecInfo.h>
 #include <media/MediaResourcePolicy.h>
+#include <media/openmax/OMX_IVCommon.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
 
 namespace android {
 
@@ -86,6 +88,7 @@
         int32_t bitrate = 0;
         getMeasureBitrate(caps, &bitrate);
         format->setInt32("bitrate", bitrate);
+        format->setInt32("encoder", 1);
     }
 
     if (mime.startsWith("video/")) {
@@ -114,15 +117,67 @@
     return format;
 }
 
+static size_t doProfileEncoderInputBuffers(
+        AString name, AString mime, sp<MediaCodecInfo::Capabilities> caps) {
+    ALOGV("doProfileEncoderInputBuffers: name %s, mime %s", name.c_str(), mime.c_str());
+
+    sp<AMessage> format = getMeasureFormat(true /* isEncoder */, mime, caps);
+    if (format == NULL) {
+        return 0;
+    }
+
+    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
+    ALOGV("doProfileEncoderInputBuffers: format %s", format->debugString().c_str());
+
+    status_t err = OK;
+    sp<ALooper> looper = new ALooper;
+    looper->setName("MediaCodec_looper");
+    looper->start(
+            false /* runOnCallingThread */, false /* canCallJava */, ANDROID_PRIORITY_AUDIO);
+
+    sp<MediaCodec> codec = MediaCodec::CreateByComponentName(looper, name.c_str(), &err);
+    if (err != OK) {
+        ALOGE("Failed to create codec: %s", name.c_str());
+        return 0;
+    }
+
+    err = codec->configure(format, NULL, NULL, MediaCodec::CONFIGURE_FLAG_ENCODE);
+    if (err != OK) {
+        ALOGE("Failed to configure codec: %s with mime: %s", name.c_str(), mime.c_str());
+        codec->release();
+        return 0;
+    }
+
+    sp<IGraphicBufferProducer> bufferProducer;
+    err = codec->createInputSurface(&bufferProducer);
+    if (err != OK) {
+        ALOGE("Failed to create surface: %s with mime: %s", name.c_str(), mime.c_str());
+        codec->release();
+        return 0;
+    }
+
+    int minUndequeued = 0;
+    err = bufferProducer->query(
+            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeued);
+    if (err != OK) {
+        ALOGE("Failed to query NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS");
+        minUndequeued = 0;
+    }
+
+    err = codec->release();
+    if (err != OK) {
+        ALOGW("Failed to release codec: %s with mime: %s", name.c_str(), mime.c_str());
+    }
+
+    return minUndequeued;
+}
+
 static size_t doProfileCodecs(
         bool isEncoder, AString name, AString mime, sp<MediaCodecInfo::Capabilities> caps) {
     sp<AMessage> format = getMeasureFormat(isEncoder, mime, caps);
     if (format == NULL) {
         return 0;
     }
-    if (isEncoder) {
-        format->setInt32("encoder", 1);
-    }
     ALOGV("doProfileCodecs %s %s %s %s",
             name.c_str(), mime.c_str(), isEncoder ? "encoder" : "decoder",
             format->debugString().c_str());
@@ -144,7 +199,7 @@
         }
         const sp<Surface> nativeWindow;
         const sp<ICrypto> crypto;
-        uint32_t flags = 0;
+        uint32_t flags = isEncoder ? MediaCodec::CONFIGURE_FLAG_ENCODE : 0;
         ALOGV("doProfileCodecs configure");
         err = codec->configure(format, nativeWindow, crypto, flags);
         if (err != OK) {
@@ -211,6 +266,7 @@
         bool forceToMeasure) {
     KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
     AString supportMultipleSecureCodecs = "true";
+    size_t maxEncoderInputBuffers = 0;
     for (size_t i = 0; i < infos.size(); ++i) {
         const sp<MediaCodecInfo> info = infos[i];
         AString name = info->getCodecName();
@@ -251,9 +307,21 @@
                         supportMultipleSecureCodecs = "false";
                     }
                 }
+                if (info->isEncoder() && mimes[i].startsWith("video/")) {
+                    size_t encoderInputBuffers =
+                        doProfileEncoderInputBuffers(name, mimes[i], caps);
+                    if (encoderInputBuffers > maxEncoderInputBuffers) {
+                        maxEncoderInputBuffers = encoderInputBuffers;
+                    }
+                }
             }
         }
     }
+    if (maxEncoderInputBuffers > 0) {
+        char tmp[32];
+        sprintf(tmp, "%zu", maxEncoderInputBuffers);
+        global_results->add(kMaxEncoderInputBuffers, tmp);
+    }
     global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
 }
 
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 1c53b40..f82636b 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -583,6 +583,13 @@
 
     Mutex::Autolock autoLock(mLock);
 
+    // If we're disconnecting, return EOS and don't access *data pointer.
+    // data could be on the stack of the caller to NuCachedSource2::readAt(),
+    // which may have exited already.
+    if (mDisconnecting) {
+        return ERROR_END_OF_STREAM;
+    }
+
     if (!mFetching) {
         mLastAccessPos = offset;
         restartPrefetcherIfNecessary_l(
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 4dd340c..8eb8f6c 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -20,7 +20,9 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
 #include <utils/threads.h>
+#include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 
 namespace android {
@@ -54,10 +56,21 @@
 
     Vector<sp<AnotherPacketSource> > mSourceImpls;
 
+    Vector<KeyedVector<int64_t, off64_t> > mSyncPoints;
+    // Sync points used for seeking --- normally one for video track is used.
+    // If no video track is present, audio track will be used instead.
+    KeyedVector<int64_t, off64_t> *mSeekSyncPoints;
+
     off64_t mOffset;
 
     void init();
     status_t feedMore();
+    status_t seek(int64_t seekTimeUs,
+            const MediaSource::ReadOptions::SeekMode& seekMode);
+    status_t queueDiscontinuityForSeek(int64_t actualSeekTimeUs);
+    status_t seekBeyond(int64_t seekTimeUs);
+
+    status_t feedUntilBufferAvailable(const sp<AnotherPacketSource> &impl);
 
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSExtractor);
 };
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index ad1e181..3c032f9 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -151,12 +151,11 @@
         OMX::buffer_id mID;
     };
     Vector<ActiveBuffer> mActiveBuffers;
-#ifdef __LP64__
+    // for buffer ptr to buffer id translation
     Mutex mBufferIDLock;
     uint32_t mBufferIDCount;
     KeyedVector<OMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
     KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
-#endif
 
     // For debug support
     char *mName;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index e8b2219..53423ec 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -54,10 +54,13 @@
     bool parsePSISection(
             unsigned pid, ABitReader *br, status_t *err);
 
+    // Pass to appropriate stream according to pid, and set event if it's a PES
+    // with a sync frame.
+    // Note that the method itself does not touch event.
     bool parsePID(
             unsigned pid, unsigned continuity_counter,
             unsigned payload_unit_start_indicator,
-            ABitReader *br, status_t *err);
+            ABitReader *br, status_t *err, SyncEvent *event);
 
     void signalDiscontinuity(
             DiscontinuityType type, const sp<AMessage> &extra);
@@ -118,10 +121,14 @@
     unsigned pid() const { return mElementaryPID; }
     void setPID(unsigned pid) { mElementaryPID = pid; }
 
+    // Parse the payload and set event when PES with a sync frame is detected.
+    // This method knows when a PES starts; so record mPesStartOffset in that
+    // case.
     status_t parse(
             unsigned continuity_counter,
             unsigned payload_unit_start_indicator,
-            ABitReader *br);
+            ABitReader *br,
+            SyncEvent *event);
 
     void signalDiscontinuity(
             DiscontinuityType type, const sp<AMessage> &extra);
@@ -150,17 +157,24 @@
     bool mEOSReached;
 
     uint64_t mPrevPTS;
+    off64_t mPesStartOffset;
 
     ElementaryStreamQueue *mQueue;
 
-    status_t flush();
-    status_t parsePES(ABitReader *br);
+    // Flush accumulated payload if necessary --- i.e. at EOS or at the start of
+    // another payload. event is set if the flushed payload is PES with a sync
+    // frame.
+    status_t flush(SyncEvent *event);
+    // Strip and parse PES headers and pass remaining payload into onPayload
+    // with parsed metadata. event is set if the PES contains a sync frame.
+    status_t parsePES(ABitReader *br, SyncEvent *event);
 
+    // Feed the payload into mQueue and if a packet is identified, queue it
+    // into mSource. If the packet is a sync frame. set event with start offset
+    // and timestamp of the packet.
     void onPayloadData(
             unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
-            const uint8_t *data, size_t size);
-
-    void extractAACFrames(const sp<ABuffer> &buffer);
+            const uint8_t *data, size_t size, SyncEvent *event);
 
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
@@ -190,6 +204,17 @@
     DISALLOW_EVIL_CONSTRUCTORS(PSISection);
 };
 
+ATSParser::SyncEvent::SyncEvent(off64_t offset)
+    : mInit(false), mOffset(offset), mTimeUs(0) {}
+
+void ATSParser::SyncEvent::init(off64_t offset, const sp<MediaSource> &source,
+        int64_t timeUs) {
+    mInit = true;
+    mOffset = offset;
+    mMediaSource = source;
+    mTimeUs = timeUs;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 ATSParser::Program::Program(
@@ -220,7 +245,7 @@
 bool ATSParser::Program::parsePID(
         unsigned pid, unsigned continuity_counter,
         unsigned payload_unit_start_indicator,
-        ABitReader *br, status_t *err) {
+        ABitReader *br, status_t *err, SyncEvent *event) {
     *err = OK;
 
     ssize_t index = mStreams.indexOfKey(pid);
@@ -229,7 +254,7 @@
     }
 
     *err = mStreams.editValueAt(index)->parse(
-            continuity_counter, payload_unit_start_indicator, br);
+            continuity_counter, payload_unit_start_indicator, br, event);
 
     return true;
 }
@@ -628,7 +653,8 @@
 
 status_t ATSParser::Stream::parse(
         unsigned continuity_counter,
-        unsigned payload_unit_start_indicator, ABitReader *br) {
+        unsigned payload_unit_start_indicator, ABitReader *br,
+        SyncEvent *event) {
     if (mQueue == NULL) {
         return OK;
     }
@@ -659,12 +685,13 @@
     mExpectedContinuityCounter = (continuity_counter + 1) & 0x0f;
 
     if (payload_unit_start_indicator) {
+        off64_t offset = (event != NULL) ? event->getOffset() : 0;
         if (mPayloadStarted) {
             // Otherwise we run the danger of receiving the trailing bytes
             // of a PES packet that we never saw the start of and assuming
             // we have a a complete PES packet.
 
-            status_t err = flush();
+            status_t err = flush(event);
 
             if (err != OK) {
                 return err;
@@ -672,6 +699,7 @@
         }
 
         mPayloadStarted = true;
+        mPesStartOffset = offset;
     }
 
     if (!mPayloadStarted) {
@@ -785,10 +813,10 @@
         mSource->signalEOS(finalResult);
     }
     mEOSReached = true;
-    flush();
+    flush(NULL);
 }
 
-status_t ATSParser::Stream::parsePES(ABitReader *br) {
+status_t ATSParser::Stream::parsePES(ABitReader *br, SyncEvent *event) {
     unsigned packet_startcode_prefix = br->getBits(24);
 
     ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
@@ -973,13 +1001,13 @@
             }
 
             onPayloadData(
-                    PTS_DTS_flags, PTS, DTS, br->data(), dataLength);
+                    PTS_DTS_flags, PTS, DTS, br->data(), dataLength, event);
 
             br->skipBits(dataLength * 8);
         } else {
             onPayloadData(
                     PTS_DTS_flags, PTS, DTS,
-                    br->data(), br->numBitsLeft() / 8);
+                    br->data(), br->numBitsLeft() / 8, event);
 
             size_t payloadSizeBits = br->numBitsLeft();
             if (payloadSizeBits % 8 != 0u) {
@@ -1003,8 +1031,8 @@
     return OK;
 }
 
-status_t ATSParser::Stream::flush() {
-    if (mBuffer->size() == 0) {
+status_t ATSParser::Stream::flush(SyncEvent *event) {
+    if (mBuffer == NULL || mBuffer->size() == 0) {
         return OK;
     }
 
@@ -1012,7 +1040,7 @@
 
     ABitReader br(mBuffer->data(), mBuffer->size());
 
-    status_t err = parsePES(&br);
+    status_t err = parsePES(&br, event);
 
     mBuffer->setRange(0, 0);
 
@@ -1021,7 +1049,7 @@
 
 void ATSParser::Stream::onPayloadData(
         unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */,
-        const uint8_t *data, size_t size) {
+        const uint8_t *data, size_t size, SyncEvent *event) {
 #if 0
     ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld",
           mStreamType,
@@ -1048,6 +1076,7 @@
     }
 
     sp<ABuffer> accessUnit;
+    bool found = false;
     while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) {
         if (mSource == NULL) {
             sp<MetaData> meta = mQueue->getFormat();
@@ -1075,6 +1104,17 @@
             }
             mSource->queueAccessUnit(accessUnit);
         }
+
+        if ((event != NULL) && !found && mQueue->getFormat() != NULL) {
+            int32_t sync = 0;
+            if (accessUnit->meta()->findInt32("isSync", &sync) && sync) {
+                int64_t timeUs;
+                if (accessUnit->meta()->findInt64("timeUs", &timeUs)) {
+                    found = true;
+                    event->init(mPesStartOffset, mSource, timeUs);
+                }
+            }
+        }
     }
 }
 
@@ -1127,14 +1167,15 @@
 ATSParser::~ATSParser() {
 }
 
-status_t ATSParser::feedTSPacket(const void *data, size_t size) {
+status_t ATSParser::feedTSPacket(const void *data, size_t size,
+        SyncEvent *event) {
     if (size != kTSPacketSize) {
         ALOGE("Wrong TS packet size");
         return BAD_VALUE;
     }
 
     ABitReader br((const uint8_t *)data, kTSPacketSize);
-    return parseTS(&br);
+    return parseTS(&br, event);
 }
 
 void ATSParser::signalDiscontinuity(
@@ -1262,7 +1303,8 @@
 status_t ATSParser::parsePID(
         ABitReader *br, unsigned PID,
         unsigned continuity_counter,
-        unsigned payload_unit_start_indicator) {
+        unsigned payload_unit_start_indicator,
+        SyncEvent *event) {
     ssize_t sectionIndex = mPSISections.indexOfKey(PID);
 
     if (sectionIndex >= 0) {
@@ -1334,7 +1376,7 @@
         status_t err;
         if (mPrograms.editItemAt(i)->parsePID(
                     PID, continuity_counter, payload_unit_start_indicator,
-                    br, &err)) {
+                    br, &err, event)) {
             if (err != OK) {
                 return err;
             }
@@ -1405,7 +1447,7 @@
     return OK;
 }
 
-status_t ATSParser::parseTS(ABitReader *br) {
+status_t ATSParser::parseTS(ABitReader *br, SyncEvent *event) {
     ALOGV("---");
 
     unsigned sync_byte = br->getBits(8);
@@ -1444,8 +1486,8 @@
     }
     if (err == OK) {
         if (adaptation_field_control == 1 || adaptation_field_control == 3) {
-            err = parsePID(
-                    br, PID, continuity_counter, payload_unit_start_indicator);
+            err = parsePID(br, PID, continuity_counter,
+                    payload_unit_start_indicator, event);
         }
     }
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 4def333..430a8d5 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -22,6 +22,7 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaSource.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/RefBase.h>
@@ -30,7 +31,6 @@
 
 class ABitReader;
 struct ABuffer;
-struct MediaSource;
 
 struct ATSParser : public RefBase {
     enum DiscontinuityType {
@@ -62,9 +62,43 @@
         ALIGNED_VIDEO_DATA         = 2,
     };
 
+    // Event is used to signal sync point event at feedTSPacket().
+    struct SyncEvent {
+        SyncEvent(off64_t offset);
+
+        void init(off64_t offset, const sp<MediaSource> &source,
+                int64_t timeUs);
+
+        bool isInit() { return mInit; }
+        off64_t getOffset() { return mOffset; }
+        const sp<MediaSource> &getMediaSource() { return mMediaSource; }
+        int64_t getTimeUs() { return mTimeUs; }
+
+    private:
+        bool mInit;
+        /*
+         * mInit == false: the current offset
+         * mInit == true: the start offset of sync payload
+         */
+        off64_t mOffset;
+        /* The media source object for this event. */
+        sp<MediaSource> mMediaSource;
+        /* The timestamp of the sync frame. */
+        int64_t mTimeUs;
+    };
+
     ATSParser(uint32_t flags = 0);
 
-    status_t feedTSPacket(const void *data, size_t size);
+    // Feed a TS packet into the parser. uninitialized event with the start
+    // offset of this TS packet goes in, and if the parser detects PES with
+    // a sync frame, the event will be initiailzed with the start offset of the
+    // PES. Note that the offset of the event can be different from what we fed,
+    // as a PES may consist of multiple TS packets.
+    //
+    // Even in the case feedTSPacket() returns non-OK value, event still may be
+    // initialized if the parsing failed after the detection.
+    status_t feedTSPacket(
+            const void *data, size_t size, SyncEvent *event = NULL);
 
     void signalDiscontinuity(
             DiscontinuityType type, const sp<AMessage> &extra);
@@ -126,15 +160,25 @@
 
     void parseProgramAssociationTable(ABitReader *br);
     void parseProgramMap(ABitReader *br);
-    void parsePES(ABitReader *br);
+    // Parse PES packet where br is pointing to. If the PES contains a sync
+    // frame, set event with the time and the start offset of this PES.
+    // Note that the method itself does not touch event.
+    void parsePES(ABitReader *br, SyncEvent *event);
 
+    // Strip remaining packet headers and pass to appropriate program/stream
+    // to parse the payload. If the payload turns out to be PES and contains
+    // a sync frame, event shall be set with the time and start offset of the
+    // PES.
+    // Note that the method itself does not touch event.
     status_t parsePID(
         ABitReader *br, unsigned PID,
         unsigned continuity_counter,
-        unsigned payload_unit_start_indicator);
+        unsigned payload_unit_start_indicator,
+        SyncEvent *event);
 
     status_t parseAdaptationField(ABitReader *br, unsigned PID);
-    status_t parseTS(ABitReader *br);
+    // see feedTSPacket().
+    status_t parseTS(ABitReader *br, SyncEvent *event);
 
     void updatePCR(unsigned PID, uint64_t PCR, size_t byteOffsetFromStart);
 
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index f5c33cf..e0ee87b 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -16,17 +16,22 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MPEG2TSExtractor"
+
+#include <inttypes.h>
 #include <utils/Log.h>
 
 #include "include/MPEG2TSExtractor.h"
 #include "include/NuCachedSource2.h"
 
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
+#include <media/IStreamSource.h>
 #include <utils/String8.h>
 
 #include "AnotherPacketSource.h"
@@ -40,7 +45,7 @@
     MPEG2TSSource(
             const sp<MPEG2TSExtractor> &extractor,
             const sp<AnotherPacketSource> &impl,
-            bool seekable);
+            bool doesSeek);
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -54,8 +59,8 @@
     sp<AnotherPacketSource> mImpl;
 
     // If there are both audio and video streams, only the video stream
-    // will be seekable, otherwise the single stream will be seekable.
-    bool mSeekable;
+    // will signal seek on the extractor; otherwise the single stream will seek.
+    bool mDoesSeek;
 
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource);
 };
@@ -63,10 +68,10 @@
 MPEG2TSSource::MPEG2TSSource(
         const sp<MPEG2TSExtractor> &extractor,
         const sp<AnotherPacketSource> &impl,
-        bool seekable)
+        bool doesSeek)
     : mExtractor(extractor),
       mImpl(impl),
-      mSeekable(seekable) {
+      mDoesSeek(doesSeek) {
 }
 
 status_t MPEG2TSSource::start(MetaData *params) {
@@ -85,27 +90,18 @@
         MediaBuffer **out, const ReadOptions *options) {
     *out = NULL;
 
-    status_t finalResult;
-    while (!mImpl->hasBufferAvailable(&finalResult)) {
-        if (finalResult != OK) {
-            return ERROR_END_OF_STREAM;
-        }
-
-        status_t err = mExtractor->feedMore();
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode seekMode;
+    if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
+        // seek is needed
+        status_t err = mExtractor->seek(seekTimeUs, seekMode);
         if (err != OK) {
-            mImpl->signalEOS(err);
+            return err;
         }
     }
 
-    int64_t seekTimeUs;
-    ReadOptions::SeekMode seekMode;
-    if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
-        // A seek was requested, but we don't actually support seeking and so can only "seek" to
-        // the current position
-        int64_t nextBufTimeUs;
-        if (mImpl->nextBufferTime(&nextBufTimeUs) != OK || seekTimeUs != nextBufTimeUs) {
-            return ERROR_UNSUPPORTED;
-        }
+    if (mExtractor->feedUntilBufferAvailable(mImpl) != OK) {
+        return ERROR_END_OF_STREAM;
     }
 
     return mImpl->read(out, options);
@@ -129,23 +125,10 @@
         return NULL;
     }
 
-    bool seekable = true;
-    if (mSourceImpls.size() > 1) {
-        if (mSourceImpls.size() != 2u) {
-            ALOGE("Wrong size");
-            return NULL;
-        }
-
-        sp<MetaData> meta = mSourceImpls.editItemAt(index)->getFormat();
-        const char *mime;
-        CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-        if (!strncasecmp("audio/", mime, 6)) {
-            seekable = false;
-        }
-    }
-
-    return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), seekable);
+    // The seek reference track (video if present; audio otherwise) performs
+    // seek requests, while other tracks ignore requests.
+    return new MPEG2TSSource(this, mSourceImpls.editItemAt(index),
+            (mSeekSyncPoints == &mSyncPoints.editItemAt(index)));
 }
 
 sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
@@ -164,7 +147,7 @@
 void MPEG2TSExtractor::init() {
     bool haveAudio = false;
     bool haveVideo = false;
-    int numPacketsParsed = 0;
+    int64_t startTime = ALooper::GetNowUs();
 
     while (feedMore() == OK) {
         if (haveAudio && haveVideo) {
@@ -178,6 +161,8 @@
             if (impl != NULL) {
                 haveVideo = true;
                 mSourceImpls.push(impl);
+                mSyncPoints.push();
+                mSeekSyncPoints = &mSyncPoints.editTop();
             }
         }
 
@@ -189,15 +174,69 @@
             if (impl != NULL) {
                 haveAudio = true;
                 mSourceImpls.push(impl);
+                mSyncPoints.push();
+                if (!haveVideo) {
+                    mSeekSyncPoints = &mSyncPoints.editTop();
+                }
             }
         }
 
-        if (++numPacketsParsed > 10000) {
+        // Wait only for 2 seconds to detect audio/video streams.
+        if (ALooper::GetNowUs() - startTime > 2000000ll) {
             break;
         }
     }
 
-    ALOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
+    off64_t size;
+    if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) {
+        sp<AnotherPacketSource> impl = haveVideo
+                ? (AnotherPacketSource *)mParser->getSource(
+                        ATSParser::VIDEO).get()
+                : (AnotherPacketSource *)mParser->getSource(
+                        ATSParser::AUDIO).get();
+        int64_t prevBufferedDurationUs = 0;
+        int64_t durationUs = -1;
+        List<int64_t> durations;
+        // Estimate duration --- stabilize until you get <500ms deviation.
+        while (feedMore() == OK && ALooper::GetNowUs() - startTime <= 2000000ll) {
+            status_t err;
+            int64_t bufferedDurationUs = impl->getBufferedDurationUs(&err);
+            if (err != OK) {
+                break;
+            }
+            if (bufferedDurationUs != prevBufferedDurationUs) {
+                durationUs = size * bufferedDurationUs / mOffset;
+                durations.push_back(durationUs);
+                if (durations.size() > 5) {
+                    durations.erase(durations.begin());
+                    int64_t min = *durations.begin();
+                    int64_t max = *durations.begin();
+                    for (List<int64_t>::iterator i = durations.begin();
+                            i != durations.end();
+                            ++i) {
+                        if (min > *i) {
+                            min = *i;
+                        }
+                        if (max < *i) {
+                            max = *i;
+                        }
+                    }
+                    if (max - min < 500 * 1000) {
+                        break;
+                    }
+                }
+                prevBufferedDurationUs = bufferedDurationUs;
+            }
+        }
+        if (durationUs > 0) {
+            const sp<MetaData> meta = impl->getFormat();
+            meta->setInt64(kKeyDuration, durationUs);
+            impl->setFormat(meta);
+        }
+    }
+
+    ALOGI("haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
+            haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
 }
 
 status_t MPEG2TSExtractor::feedMore() {
@@ -213,12 +252,195 @@
         return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
     }
 
+    ATSParser::SyncEvent event(mOffset);
     mOffset += n;
-    return mParser->feedTSPacket(packet, kTSPacketSize);
+    status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
+    if (event.isInit()) {
+        for (size_t i = 0; i < mSourceImpls.size(); ++i) {
+            if (mSourceImpls[i].get() == event.getMediaSource().get()) {
+                mSyncPoints.editItemAt(i).add(
+                        event.getTimeUs(), event.getOffset());
+                break;
+            }
+        }
+    }
+    return err;
 }
 
 uint32_t MPEG2TSExtractor::flags() const {
-    return CAN_PAUSE;
+    return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD;
+}
+
+status_t MPEG2TSExtractor::seek(int64_t seekTimeUs,
+        const MediaSource::ReadOptions::SeekMode &seekMode) {
+    if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) {
+        ALOGW("No sync point to seek to.");
+        // ... and therefore we have nothing useful to do here.
+        return OK;
+    }
+
+    // Determine whether we're seeking beyond the known area.
+    bool shouldSeekBeyond =
+            (seekTimeUs > mSeekSyncPoints->keyAt(mSeekSyncPoints->size() - 1));
+
+    // Determine the sync point to seek.
+    size_t index = 0;
+    for (; index < mSeekSyncPoints->size(); ++index) {
+        int64_t timeUs = mSeekSyncPoints->keyAt(index);
+        if (timeUs > seekTimeUs) {
+            break;
+        }
+    }
+
+    switch (seekMode) {
+        case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
+            if (index == mSeekSyncPoints->size()) {
+                ALOGW("Next sync not found; starting from the latest sync.");
+                --index;
+            }
+            break;
+        case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
+        case MediaSource::ReadOptions::SEEK_CLOSEST:
+            ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC",
+                    seekMode);
+            // fall-through
+        case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
+            if (index == 0) {
+                ALOGW("Previous sync not found; starting from the earliest "
+                        "sync.");
+            } else {
+                --index;
+            }
+            break;
+    }
+    if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) {
+        int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index);
+        mOffset = mSeekSyncPoints->valueAt(index);
+        status_t err = queueDiscontinuityForSeek(actualSeekTimeUs);
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    if (shouldSeekBeyond) {
+        status_t err = seekBeyond(seekTimeUs);
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    // Fast-forward to sync frame.
+    for (size_t i = 0; i < mSourceImpls.size(); ++i) {
+        const sp<AnotherPacketSource> &impl = mSourceImpls[i];
+        status_t err;
+        feedUntilBufferAvailable(impl);
+        while (impl->hasBufferAvailable(&err)) {
+            sp<AMessage> meta = impl->getMetaAfterLastDequeued(0);
+            sp<ABuffer> buffer;
+            if (meta == NULL) {
+                return UNKNOWN_ERROR;
+            }
+            int32_t sync;
+            if (meta->findInt32("isSync", &sync) && sync) {
+                break;
+            }
+            err = impl->dequeueAccessUnit(&buffer);
+            if (err != OK) {
+                return err;
+            }
+            feedUntilBufferAvailable(impl);
+        }
+    }
+
+    return OK;
+}
+
+status_t MPEG2TSExtractor::queueDiscontinuityForSeek(int64_t actualSeekTimeUs) {
+    // Signal discontinuity
+    sp<AMessage> extra(new AMessage);
+    extra->setInt64(IStreamListener::kKeyMediaTimeUs, actualSeekTimeUs);
+    mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_TIME, extra);
+
+    // After discontinuity, impl should only have discontinuities
+    // with the last being what we queued. Dequeue them all here.
+    for (size_t i = 0; i < mSourceImpls.size(); ++i) {
+        const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
+        sp<ABuffer> buffer;
+        status_t err;
+        while (impl->hasBufferAvailable(&err)) {
+            if (err != OK) {
+                return err;
+            }
+            err = impl->dequeueAccessUnit(&buffer);
+            // If the source contains anything but discontinuity, that's
+            // a programming mistake.
+            CHECK(err == INFO_DISCONTINUITY);
+        }
+    }
+
+    // Feed until we have a buffer for each source.
+    for (size_t i = 0; i < mSourceImpls.size(); ++i) {
+        const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
+        sp<ABuffer> buffer;
+        status_t err = feedUntilBufferAvailable(impl);
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+status_t MPEG2TSExtractor::seekBeyond(int64_t seekTimeUs) {
+    // If we're seeking beyond where we know --- read until we reach there.
+    size_t syncPointsSize = mSeekSyncPoints->size();
+
+    while (seekTimeUs > mSeekSyncPoints->keyAt(
+            mSeekSyncPoints->size() - 1)) {
+        status_t err;
+        if (syncPointsSize < mSeekSyncPoints->size()) {
+            syncPointsSize = mSeekSyncPoints->size();
+            int64_t syncTimeUs = mSeekSyncPoints->keyAt(syncPointsSize - 1);
+            // Dequeue buffers before sync point in order to avoid too much
+            // cache building up.
+            sp<ABuffer> buffer;
+            for (size_t i = 0; i < mSourceImpls.size(); ++i) {
+                const sp<AnotherPacketSource> &impl = mSourceImpls[i];
+                int64_t timeUs;
+                while ((err = impl->nextBufferTime(&timeUs)) == OK) {
+                    if (timeUs < syncTimeUs) {
+                        impl->dequeueAccessUnit(&buffer);
+                    } else {
+                        break;
+                    }
+                }
+                if (err != OK && err != -EWOULDBLOCK) {
+                    return err;
+                }
+            }
+        }
+        if (feedMore() != OK) {
+            return ERROR_END_OF_STREAM;
+        }
+    }
+
+    return OK;
+}
+
+status_t MPEG2TSExtractor::feedUntilBufferAvailable(
+        const sp<AnotherPacketSource> &impl) {
+    status_t finalResult;
+    while (!impl->hasBufferAvailable(&finalResult)) {
+        if (finalResult != OK) {
+            return finalResult;
+        }
+
+        status_t err = feedMore();
+        if (err != OK) {
+            impl->signalEOS(err);
+        }
+    }
+    return OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 91cee73..753eb28 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -868,17 +868,9 @@
     consumer->setConsumerName(name);
     consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
 
-    status_t err = consumer->setMaxAcquiredBufferCount(
-            BufferQueue::MAX_MAX_ACQUIRED_BUFFERS);
-    if (err != NO_ERROR) {
-        ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
-                BufferQueue::MAX_MAX_ACQUIRED_BUFFERS, err);
-        return err;
-    }
-
     sp<BufferQueue::ProxyConsumerListener> proxy =
         new BufferQueue::ProxyConsumerListener(NULL);
-    err = consumer->consumerConnect(proxy, false);
+    status_t err = consumer->consumerConnect(proxy, false);
     if (err != NO_ERROR) {
         ALOGE("Error connecting to BufferQueue: %s (%d)",
                 strerror(-err), err);
@@ -1037,6 +1029,12 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+    // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
+    // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.
+    if (rangeOffset > header->nAllocLen
+            || rangeLength > header->nAllocLen - rangeOffset) {
+        return BAD_VALUE;
+    }
     header->nFilledLen = rangeLength;
     header->nOffset = rangeOffset;
 
@@ -1422,8 +1420,6 @@
     }
 }
 
-#ifdef __LP64__
-
 OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
     if (bufferHeader == NULL) {
         return 0;
@@ -1466,23 +1462,4 @@
     mBufferIDToBufferHeader.removeItem(buffer);
 }
 
-#else
-
-OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
-    return (OMX::buffer_id)bufferHeader;
-}
-
-OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) {
-    return (OMX_BUFFERHEADERTYPE *)buffer;
-}
-
-OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
-    return (OMX::buffer_id)bufferHeader;
-}
-
-void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer __unused) {
-}
-
-#endif
-
 }  // namespace android
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index ba17e90..e64a7a1 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1737,7 +1737,7 @@
         }
 
         if (!mAllTracksHaveTime) {
-            bool allTracksHaveTime = true;
+            bool allTracksHaveTime = (mTracks.size() > 0);
             for (size_t i = 0; i < mTracks.size(); ++i) {
                 TrackInfo *track = &mTracks.editItemAt(i);
                 if (track->mNTPAnchorUs < 0) {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 93b1642..52fce34 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -181,7 +181,8 @@
       mIsLowRamDevice(true),
       mIsDeviceTypeKnown(false),
       mGlobalEffectEnableTime(0),
-      mPrimaryOutputSampleRate(0)
+      mPrimaryOutputSampleRate(0),
+      mSystemReady(false)
 {
     getpid_cached = getpid();
     char value[PROPERTY_VALUE_MAX];
@@ -1722,6 +1723,26 @@
     return (audio_hw_sync_t)value;
 }
 
+status_t AudioFlinger::systemReady()
+{
+    Mutex::Autolock _l(mLock);
+    ALOGI("%s", __FUNCTION__);
+    if (mSystemReady) {
+        ALOGW("%s called twice", __FUNCTION__);
+        return NO_ERROR;
+    }
+    mSystemReady = true;
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        ThreadBase *thread = (ThreadBase *)mPlaybackThreads.valueAt(i).get();
+        thread->systemReady();
+    }
+    for (size_t i = 0; i < mRecordThreads.size(); i++) {
+        ThreadBase *thread = (ThreadBase *)mRecordThreads.valueAt(i).get();
+        thread->systemReady();
+    }
+    return NO_ERROR;
+}
+
 // setAudioHwSyncForSession_l() must be called with AudioFlinger::mLock held
 void AudioFlinger::setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId)
 {
@@ -1794,15 +1815,15 @@
 
         PlaybackThread *thread;
         if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-            thread = new OffloadThread(this, outputStream, *output, devices);
+            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
             ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread);
         } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                 || !isValidPcmSinkFormat(config->format)
                 || !isValidPcmSinkChannelMask(config->channel_mask)) {
-            thread = new DirectOutputThread(this, outputStream, *output, devices);
+            thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
             ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread);
         } else {
-            thread = new MixerThread(this, outputStream, *output, devices);
+            thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
             ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread);
         }
         mPlaybackThreads.add(*output, thread);
@@ -1873,7 +1894,7 @@
     }
 
     audio_io_handle_t id = nextUniqueId();
-    DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
+    DuplicatingThread *thread = new DuplicatingThread(this, thread1, id, mSystemReady);
     thread->addOutputTrack(thread2);
     mPlaybackThreads.add(id, thread);
     // notify client processes of the new output creation
@@ -2120,7 +2141,8 @@
                                   inputStream,
                                   *input,
                                   primaryOutputDevice_l(),
-                                  devices
+                                  devices,
+                                  mSystemReady
 #ifdef TEE_SINK
                                   , teeSink
 #endif
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 51b2610..d087ced 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -257,6 +257,9 @@
     /* Get the HW synchronization source used for an audio session */
     virtual audio_hw_sync_t getAudioHwSyncForSession(audio_session_t sessionId);
 
+    /* Indicate JAVA services are ready (scheduling, power management ...) */
+    virtual status_t systemReady();
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -356,6 +359,15 @@
             // check that channelMask is the "canonical" one we expect for the channelCount.
             return channelMask == audio_channel_out_mask_from_count(channelCount);
             }
+        case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+            if (kEnableExtendedChannels) {
+                const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
+                if (channelCount >= FCC_2 // mono is not supported at this time
+                        && channelCount <= AudioMixer::MAX_NUM_CHANNELS) {
+                    return true;
+                }
+            }
+            return false;
         default:
             return false;
         }
@@ -752,6 +764,7 @@
 
     uint32_t    mPrimaryOutputSampleRate;   // sample rate of the primary output, or zero if none
                                             // protected by mHardwareLock
+    bool       mSystemReady;
 };
 
 #undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 586c737..01efc53 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -66,6 +66,13 @@
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 #endif
 
+// TODO: Move these macro/inlines to a header file.
+template <typename T>
+static inline
+T max(const T& x, const T& y) {
+    return x > y ? x : y;
+}
+
 // Set kUseNewMixer to true to use the new mixer engine always. Otherwise the
 // original code will be used for stereo sinks, the new mixer for multichannel.
 static const bool kUseNewMixer = true;
@@ -499,41 +506,99 @@
 static inline bool setVolumeRampVariables(float newVolume, int32_t ramp,
         int16_t *pIntSetVolume, int32_t *pIntPrevVolume, int32_t *pIntVolumeInc,
         float *pSetVolume, float *pPrevVolume, float *pVolumeInc) {
+    // check floating point volume to see if it is identical to the previously
+    // set volume.
+    // We do not use a tolerance here (and reject changes too small)
+    // as it may be confusing to use a different value than the one set.
+    // If the resulting volume is too small to ramp, it is a direct set of the volume.
     if (newVolume == *pSetVolume) {
         return false;
     }
-    /* set the floating point volume variables */
-    if (ramp != 0) {
-        *pVolumeInc = (newVolume - *pSetVolume) / ramp;
-        *pPrevVolume = *pSetVolume;
+    if (newVolume < 0) {
+        newVolume = 0; // should not have negative volumes
     } else {
-        *pVolumeInc = 0;
-        *pPrevVolume = newVolume;
+        switch (fpclassify(newVolume)) {
+        case FP_SUBNORMAL:
+        case FP_NAN:
+            newVolume = 0;
+            break;
+        case FP_ZERO:
+            break; // zero volume is fine
+        case FP_INFINITE:
+            // Infinite volume could be handled consistently since
+            // floating point math saturates at infinities,
+            // but we limit volume to unity gain float.
+            // ramp = 0; break;
+            //
+            newVolume = AudioMixer::UNITY_GAIN_FLOAT;
+            break;
+        case FP_NORMAL:
+        default:
+            // Floating point does not have problems with overflow wrap
+            // that integer has.  However, we limit the volume to
+            // unity gain here.
+            // TODO: Revisit the volume limitation and perhaps parameterize.
+            if (newVolume > AudioMixer::UNITY_GAIN_FLOAT) {
+                newVolume = AudioMixer::UNITY_GAIN_FLOAT;
+            }
+            break;
+        }
     }
-    *pSetVolume = newVolume;
 
-    /* set the legacy integer volume variables */
-    int32_t intVolume = newVolume * AudioMixer::UNITY_GAIN_INT;
-    if (intVolume > AudioMixer::UNITY_GAIN_INT) {
-        intVolume = AudioMixer::UNITY_GAIN_INT;
-    } else if (intVolume < 0) {
-        ALOGE("negative volume %.7g", newVolume);
-        intVolume = 0; // should never happen, but for safety check.
+    // set floating point volume ramp
+    if (ramp != 0) {
+        // when the ramp completes, *pPrevVolume is set to *pSetVolume, so there
+        // is no computational mismatch; hence equality is checked here.
+        ALOGD_IF(*pPrevVolume != *pSetVolume, "previous float ramp hasn't finished,"
+                " prev:%f  set_to:%f", *pPrevVolume, *pSetVolume);
+        const float inc = (newVolume - *pPrevVolume) / ramp; // could be inf, nan, subnormal
+        const float maxv = max(newVolume, *pPrevVolume); // could be inf, cannot be nan, subnormal
+
+        if (isnormal(inc) // inc must be a normal number (no subnormals, infinite, nan)
+                && maxv + inc != maxv) { // inc must make forward progress
+            *pVolumeInc = inc;
+            // ramp is set now.
+            // Note: if newVolume is 0, then near the end of the ramp,
+            // it may be possible that the ramped volume may be subnormal or
+            // temporarily negative by a small amount or subnormal due to floating
+            // point inaccuracies.
+        } else {
+            ramp = 0; // ramp not allowed
+        }
     }
-    if (intVolume == *pIntSetVolume) {
-        *pIntVolumeInc = 0;
-        /* TODO: integer/float workaround: ignore floating volume ramp */
+
+    // compute and check integer volume, no need to check negative values
+    // The integer volume is limited to "unity_gain" to avoid wrapping and other
+    // audio artifacts, so it never reaches the range limit of U4.28.
+    // We safely use signed 16 and 32 bit integers here.
+    const float scaledVolume = newVolume * AudioMixer::UNITY_GAIN_INT; // not neg, subnormal, nan
+    const int32_t intVolume = (scaledVolume >= (float)AudioMixer::UNITY_GAIN_INT) ?
+            AudioMixer::UNITY_GAIN_INT : (int32_t)scaledVolume;
+
+    // set integer volume ramp
+    if (ramp != 0) {
+        // integer volume is U4.12 (to use 16 bit multiplies), but ramping uses U4.28.
+        // when the ramp completes, *pIntPrevVolume is set to *pIntSetVolume << 16, so there
+        // is no computational mismatch; hence equality is checked here.
+        ALOGD_IF(*pIntPrevVolume != *pIntSetVolume << 16, "previous int ramp hasn't finished,"
+                " prev:%d  set_to:%d", *pIntPrevVolume, *pIntSetVolume << 16);
+        const int32_t inc = ((intVolume << 16) - *pIntPrevVolume) / ramp;
+
+        if (inc != 0) { // inc must make forward progress
+            *pIntVolumeInc = inc;
+        } else {
+            ramp = 0; // ramp not allowed
+        }
+    }
+
+    // if no ramp, or ramp not allowed, then clear float and integer increments
+    if (ramp == 0) {
         *pVolumeInc = 0;
         *pPrevVolume = newVolume;
-        return true;
-    }
-    if (ramp != 0) {
-        *pIntVolumeInc = ((intVolume - *pIntSetVolume) << 16) / ramp;
-        *pIntPrevVolume = (*pIntVolumeInc == 0 ? intVolume : *pIntSetVolume) << 16;
-    } else {
         *pIntVolumeInc = 0;
         *pIntPrevVolume = intVolume << 16;
     }
+    *pSetVolume = newVolume;
     *pIntSetVolume = intVolume;
     return true;
 }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d9b4249..721f6af 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -487,7 +487,7 @@
 }
 
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        audio_devices_t outDevice, audio_devices_t inDevice, type_t type)
+        audio_devices_t outDevice, audio_devices_t inDevice, type_t type, bool systemReady)
     :   Thread(false /*canCallJava*/),
         mType(type),
         mAudioFlinger(audioFlinger),
@@ -498,7 +498,8 @@
         mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
         mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
-        mDeathRecipient(new PMDeathRecipient(this))
+        mDeathRecipient(new PMDeathRecipient(this)),
+        mSystemReady(systemReady)
 {
     memset(&mPatch, 0, sizeof(struct audio_patch));
 }
@@ -567,6 +568,11 @@
 {
     status_t status = NO_ERROR;
 
+    if (event->mRequiresSystemReady && !mSystemReady) {
+        event->mWaitStatus = false;
+        mPendingConfigEvents.add(event);
+        return status;
+    }
     mConfigEvents.add(event);
     ALOGV("sendConfigEvent_l() num events %d event %d", mConfigEvents.size(), event->mType);
     mWaitWorkCV.signal();
@@ -598,6 +604,12 @@
     sendConfigEvent_l(configEvent);
 }
 
+void AudioFlinger::ThreadBase::sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio)
+{
+    Mutex::Autolock _l(mLock);
+    sendPrioConfigEvent_l(pid, tid, prio);
+}
+
 // sendPrioConfigEvent_l() must be called with ThreadBase::mLock held
 void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio)
 {
@@ -697,49 +709,62 @@
 
 String8 channelMaskToString(audio_channel_mask_t mask, bool output) {
     String8 s;
-    if (output) {
-        if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT) s.append("front-left, ");
-        if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT) s.append("front-right, ");
-        if (mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) s.append("front-center, ");
-        if (mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) s.append("low freq, ");
-        if (mask & AUDIO_CHANNEL_OUT_BACK_LEFT) s.append("back-left, ");
-        if (mask & AUDIO_CHANNEL_OUT_BACK_RIGHT) s.append("back-right, ");
-        if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER) s.append("front-left-of-center, ");
-        if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) s.append("front-right-of-center, ");
-        if (mask & AUDIO_CHANNEL_OUT_BACK_CENTER) s.append("back-center, ");
-        if (mask & AUDIO_CHANNEL_OUT_SIDE_LEFT) s.append("side-left, ");
-        if (mask & AUDIO_CHANNEL_OUT_SIDE_RIGHT) s.append("side-right, ");
-        if (mask & AUDIO_CHANNEL_OUT_TOP_CENTER) s.append("top-center ,");
-        if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT) s.append("top-front-left, ");
-        if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER) s.append("top-front-center, ");
-        if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT) s.append("top-front-right, ");
-        if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, ");
-        if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " );
-        if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " );
-        if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown,  ");
-    } else {
-        if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, ");
-        if (mask & AUDIO_CHANNEL_IN_RIGHT) s.append("right, ");
-        if (mask & AUDIO_CHANNEL_IN_FRONT) s.append("front, ");
-        if (mask & AUDIO_CHANNEL_IN_BACK) s.append("back, ");
-        if (mask & AUDIO_CHANNEL_IN_LEFT_PROCESSED) s.append("left-processed, ");
-        if (mask & AUDIO_CHANNEL_IN_RIGHT_PROCESSED) s.append("right-processed, ");
-        if (mask & AUDIO_CHANNEL_IN_FRONT_PROCESSED) s.append("front-processed, ");
-        if (mask & AUDIO_CHANNEL_IN_BACK_PROCESSED) s.append("back-processed, ");
-        if (mask & AUDIO_CHANNEL_IN_PRESSURE) s.append("pressure, ");
-        if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, ");
-        if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, ");
-        if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, ");
-        if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, ");
-        if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, ");
-        if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown,  ");
+    const audio_channel_representation_t representation = audio_channel_mask_get_representation(mask);
+
+    switch (representation) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION: {
+        if (output) {
+            if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT) s.append("front-left, ");
+            if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT) s.append("front-right, ");
+            if (mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) s.append("front-center, ");
+            if (mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) s.append("low freq, ");
+            if (mask & AUDIO_CHANNEL_OUT_BACK_LEFT) s.append("back-left, ");
+            if (mask & AUDIO_CHANNEL_OUT_BACK_RIGHT) s.append("back-right, ");
+            if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER) s.append("front-left-of-center, ");
+            if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) s.append("front-right-of-center, ");
+            if (mask & AUDIO_CHANNEL_OUT_BACK_CENTER) s.append("back-center, ");
+            if (mask & AUDIO_CHANNEL_OUT_SIDE_LEFT) s.append("side-left, ");
+            if (mask & AUDIO_CHANNEL_OUT_SIDE_RIGHT) s.append("side-right, ");
+            if (mask & AUDIO_CHANNEL_OUT_TOP_CENTER) s.append("top-center ,");
+            if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT) s.append("top-front-left, ");
+            if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER) s.append("top-front-center, ");
+            if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT) s.append("top-front-right, ");
+            if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, ");
+            if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " );
+            if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " );
+            if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown,  ");
+        } else {
+            if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, ");
+            if (mask & AUDIO_CHANNEL_IN_RIGHT) s.append("right, ");
+            if (mask & AUDIO_CHANNEL_IN_FRONT) s.append("front, ");
+            if (mask & AUDIO_CHANNEL_IN_BACK) s.append("back, ");
+            if (mask & AUDIO_CHANNEL_IN_LEFT_PROCESSED) s.append("left-processed, ");
+            if (mask & AUDIO_CHANNEL_IN_RIGHT_PROCESSED) s.append("right-processed, ");
+            if (mask & AUDIO_CHANNEL_IN_FRONT_PROCESSED) s.append("front-processed, ");
+            if (mask & AUDIO_CHANNEL_IN_BACK_PROCESSED) s.append("back-processed, ");
+            if (mask & AUDIO_CHANNEL_IN_PRESSURE) s.append("pressure, ");
+            if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, ");
+            if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, ");
+            if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, ");
+            if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, ");
+            if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, ");
+            if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown,  ");
+        }
+        const int len = s.length();
+        if (len > 2) {
+            char *str = s.lockBuffer(len); // needed?
+            s.unlockBuffer(len - 2);       // remove trailing ", "
+        }
+        return s;
     }
-    int len = s.length();
-    if (s.length() > 2) {
-        char *str = s.lockBuffer(len);
-        s.unlockBuffer(len - 2);
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        s.appendFormat("index mask, bits:%#x", audio_channel_mask_get_bits(mask));
+        return s;
+    default:
+        s.appendFormat("unknown mask, representation:%d  bits:%#x",
+                representation, audio_channel_mask_get_bits(mask));
+        return s;
     }
-    return s;
 }
 
 void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __unused)
@@ -880,8 +905,7 @@
 }
 
 void AudioFlinger::ThreadBase::getPowerManager_l() {
-
-    if (mPowerManager == 0) {
+    if (mSystemReady && mPowerManager == 0) {
         // use checkService() to avoid blocking if power service is not up yet
         sp<IBinder> binder =
             defaultServiceManager()->checkService(String16("power"));
@@ -895,7 +919,6 @@
 }
 
 void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) {
-
     getPowerManager_l();
     if (mWakeLockToken == NULL) {
         ALOGE("no wake lock to update!");
@@ -1337,6 +1360,20 @@
                             AUDIO_PORT_CONFIG_FORMAT;
 }
 
+void AudioFlinger::ThreadBase::systemReady()
+{
+    Mutex::Autolock _l(mLock);
+    if (mSystemReady) {
+        return;
+    }
+    mSystemReady = true;
+
+    for (size_t i = 0; i < mPendingConfigEvents.size(); i++) {
+        sendConfigEvent_l(mPendingConfigEvents.editItemAt(i));
+    }
+    mPendingConfigEvents.clear();
+}
+
 
 // ----------------------------------------------------------------------------
 //      Playback
@@ -1346,8 +1383,9 @@
                                              AudioStreamOut* output,
                                              audio_io_handle_t id,
                                              audio_devices_t device,
-                                             type_t type)
-    :   ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type),
+                                             type_t type,
+                                             bool systemReady)
+    :   ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady),
         mNormalFrameCount(0), mSinkBuffer(NULL),
         mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
         mMixerBuffer(NULL),
@@ -1572,10 +1610,12 @@
             ) &&
             // PCM data
             audio_is_linear_pcm(format) &&
-            // identical channel mask to sink, or mono in and stereo sink
+            // TODO: extract as a data library function that checks that a computationally
+            // expensive downmixer is not required: isFastOutputChannelConversion()
             (channelMask == mChannelMask ||
-                    (channelMask == AUDIO_CHANNEL_OUT_MONO &&
-                            mChannelMask == AUDIO_CHANNEL_OUT_STEREO)) &&
+                    mChannelMask != AUDIO_CHANNEL_OUT_STEREO ||
+                    (channelMask == AUDIO_CHANNEL_OUT_MONO
+                            /* && mChannelMask == AUDIO_CHANNEL_OUT_STEREO */)) &&
             // hardware sample rate
             (sampleRate == mSampleRate) &&
             // normal mixer has an associated fast mixer
@@ -3118,8 +3158,8 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-        audio_io_handle_t id, audio_devices_t device, type_t type)
-    :   PlaybackThread(audioFlinger, output, id, device, type),
+        audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
+    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady),
         // mAudioMixer below
         // mFastMixer below
         mFastMixerFutex(0)
@@ -3252,11 +3292,7 @@
         // start the fast mixer
         mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastMixer->getTid();
-        int err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
-        if (err != 0) {
-            ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
-                    kPriorityFastMixer, getpid_cached, tid, err);
-        }
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer);
 
 #ifdef AUDIO_WATCHDOG
         // create and start the watchdog
@@ -3264,11 +3300,7 @@
         mAudioWatchdog->setDump(&mAudioWatchdogDump);
         mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
         tid = mAudioWatchdog->getTid();
-        err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
-        if (err != 0) {
-            ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
-                    kPriorityFastMixer, getpid_cached, tid, err);
-        }
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer);
 #endif
 
     }
@@ -4294,16 +4326,16 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device)
-    :   PlaybackThread(audioFlinger, output, id, device, DIRECT)
+        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
+    :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
         // mLeftVolFloat, mRightVolFloat
 {
 }
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
         AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
-        ThreadBase::type_t type)
-    :   PlaybackThread(audioFlinger, output, id, device, type)
+        ThreadBase::type_t type, bool systemReady)
+    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
         // mLeftVolFloat, mRightVolFloat
 {
 }
@@ -4832,8 +4864,8 @@
 
 // ----------------------------------------------------------------------------
 AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, uint32_t device)
-    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD),
+        AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
+    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
         mPausedBytesRemaining(0)
 {
     //FIXME: mStandby should be set to true by ThreadBase constructor
@@ -5110,9 +5142,9 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
-        AudioFlinger::MixerThread* mainThread, audio_io_handle_t id)
+        AudioFlinger::MixerThread* mainThread, audio_io_handle_t id, bool systemReady)
     :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->outDevice(),
-                DUPLICATING),
+                    systemReady, DUPLICATING),
         mWaitTimeMs(UINT_MAX)
 {
     addOutputTrack(mainThread);
@@ -5292,12 +5324,13 @@
                                          AudioStreamIn *input,
                                          audio_io_handle_t id,
                                          audio_devices_t outDevice,
-                                         audio_devices_t inDevice
+                                         audio_devices_t inDevice,
+                                         bool systemReady
 #ifdef TEE_SINK
                                          , const sp<NBAIO_Sink>& teeSink
 #endif
                                          ) :
-    ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
+    ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
     mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
     // mRsmpInFrames and mRsmpInFramesP2 are set by readInputParameters_l()
     mRsmpInRear(0)
@@ -5416,12 +5449,7 @@
         // start the fast capture
         mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastCapture->getTid();
-        int err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
-        if (err != 0) {
-            ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
-                    kPriorityFastCapture, getpid_cached, tid, err);
-        }
-
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer);
 #ifdef AUDIO_WATCHDOG
         // FIXME
 #endif
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 37bacae..aa20525 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -35,7 +35,8 @@
     static const char *threadTypeToString(type_t type);
 
     ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                audio_devices_t outDevice, audio_devices_t inDevice, type_t type);
+                audio_devices_t outDevice, audio_devices_t inDevice, type_t type,
+                bool systemReady);
     virtual             ~ThreadBase();
 
     virtual status_t    readyToRun();
@@ -92,10 +93,13 @@
         Condition mCond; // condition for status return
         status_t mStatus; // status communicated to sender
         bool mWaitStatus; // true if sender is waiting for status
+        bool mRequiresSystemReady; // true if must wait for system ready to enter event queue
         sp<ConfigEventData> mData;     // event specific parameter data
 
     protected:
-        ConfigEvent(int type) : mType(type), mStatus(NO_ERROR), mWaitStatus(false), mData(NULL) {}
+        ConfigEvent(int type, bool requiresSystemReady = false) :
+            mType(type), mStatus(NO_ERROR), mWaitStatus(false),
+            mRequiresSystemReady(requiresSystemReady), mData(NULL) {}
     };
 
     class IoConfigEventData : public ConfigEventData {
@@ -136,7 +140,7 @@
     class PrioConfigEvent : public ConfigEvent {
     public:
         PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
-            ConfigEvent(CFG_EVENT_PRIO) {
+            ConfigEvent(CFG_EVENT_PRIO, true) {
             mData = new PrioConfigEventData(pid, tid, prio);
         }
         virtual ~PrioConfigEvent() {}
@@ -258,6 +262,7 @@
                 status_t    sendConfigEvent_l(sp<ConfigEvent>& event);
                 void        sendIoConfigEvent(audio_io_config_event event);
                 void        sendIoConfigEvent_l(audio_io_config_event event);
+                void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio);
                 void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
                 status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
                 status_t    sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
@@ -359,6 +364,8 @@
 
                 virtual sp<IMemory> pipeMemory() const { return 0; }
 
+                        void systemReady();
+
     mutable     Mutex                   mLock;
 
 protected:
@@ -418,6 +425,7 @@
                 size_t                  mBufferSize;       // HAL buffer size for read() or write()
 
                 Vector< sp<ConfigEvent> >     mConfigEvents;
+                Vector< sp<ConfigEvent> >     mPendingConfigEvents; // events awaiting system ready
 
                 // These fields are written and read by thread itself without lock or barrier,
                 // and read by other threads without lock or barrier via standby(), outDevice()
@@ -445,6 +453,7 @@
                                         mSuspendedSessions;
                 static const size_t     kLogSize = 4 * 1024;
                 sp<NBLog::Writer>       mNBLogWriter;
+                bool                    mSystemReady;
 };
 
 // --- PlaybackThread ---
@@ -470,7 +479,7 @@
     static const int8_t kMaxTrackRetriesOffload = 20;
 
     PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                   audio_io_handle_t id, audio_devices_t device, type_t type);
+                   audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
     virtual             ~PlaybackThread();
 
                 void        dump(int fd, const Vector<String16>& args);
@@ -842,6 +851,7 @@
                 AudioStreamOut* output,
                 audio_io_handle_t id,
                 audio_devices_t device,
+                bool systemReady,
                 type_t type = MIXER);
     virtual             ~MixerThread();
 
@@ -903,7 +913,7 @@
 public:
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                       audio_io_handle_t id, audio_devices_t device);
+                       audio_io_handle_t id, audio_devices_t device, bool systemReady);
     virtual                 ~DirectOutputThread();
 
     // Thread virtuals
@@ -933,7 +943,8 @@
     float mRightVolFloat;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, uint32_t device, ThreadBase::type_t type);
+                        audio_io_handle_t id, uint32_t device, ThreadBase::type_t type,
+                        bool systemReady);
     void processVolume_l(Track *track, bool lastTrack);
 
     // prepareTracks_l() tells threadLoop_mix() the name of the single active track
@@ -946,7 +957,7 @@
 public:
 
     OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, uint32_t device);
+                        audio_io_handle_t id, uint32_t device, bool systemReady);
     virtual                 ~OffloadThread() {};
     virtual     void        flushHw_l();
 
@@ -1001,7 +1012,7 @@
 class DuplicatingThread : public MixerThread {
 public:
     DuplicatingThread(const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread,
-                      audio_io_handle_t id);
+                      audio_io_handle_t id, bool systemReady);
     virtual                 ~DuplicatingThread();
 
     // Thread virtuals
@@ -1177,7 +1188,8 @@
                     AudioStreamIn *input,
                     audio_io_handle_t id,
                     audio_devices_t outDevice,
-                    audio_devices_t inDevice
+                    audio_devices_t inDevice,
+                    bool systemReady
 #ifdef TEE_SINK
                     , const sp<NBAIO_Sink>& teeSink
 #endif
@@ -1294,6 +1306,7 @@
             // one-time initialization, no locks required
             sp<FastCapture>                     mFastCapture;   // non-0 if there is also
                                                                 // a fast capture
+
             // FIXME audio watchdog thread
 
             // contents are not guaranteed to be consistent, no locks required
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index d1ee400..665cce9 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -171,7 +171,7 @@
         }
 
         updateDevicesAndOutputs();
-        if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) {
+        if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
             audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
             updateCallRouting(newDevice);
         }
@@ -261,7 +261,7 @@
 
         closeAllInputs();
 
-        if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) {
+        if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
             audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
             updateCallRouting(newDevice);
         }
@@ -302,6 +302,9 @@
     audio_patch_handle_t afPatchHandle;
     DeviceVector deviceList;
 
+    if(!hasPrimaryOutput()) {
+        return;
+    }
     audio_devices_t txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
     ALOGV("updateCallRouting device rxDevice %08x txDevice %08x", rxDevice, txDevice);
 
@@ -449,8 +452,6 @@
     checkOutputForAllStrategies();
     updateDevicesAndOutputs();
 
-    sp<SwAudioOutputDescriptor> hwOutputDesc = mPrimaryOutput;
-
     int delayMs = 0;
     if (isStateInCall(state)) {
         nsecs_t sysTime = systemTime();
@@ -477,29 +478,31 @@
         }
     }
 
-    // Note that despite the fact that getNewOutputDevice() is called on the primary output,
-    // the device returned is not necessarily reachable via this output
-    audio_devices_t rxDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
-    // force routing command to audio hardware when ending call
-    // even if no device change is needed
-    if (isStateInCall(oldState) && rxDevice == AUDIO_DEVICE_NONE) {
-        rxDevice = hwOutputDesc->device();
-    }
+    if (hasPrimaryOutput()) {
+        // Note that despite the fact that getNewOutputDevice() is called on the primary output,
+        // the device returned is not necessarily reachable via this output
+        audio_devices_t rxDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
+        // force routing command to audio hardware when ending call
+        // even if no device change is needed
+        if (isStateInCall(oldState) && rxDevice == AUDIO_DEVICE_NONE) {
+            rxDevice = mPrimaryOutput->device();
+        }
 
-    if (state == AUDIO_MODE_IN_CALL) {
-        updateCallRouting(rxDevice, delayMs);
-    } else if (oldState == AUDIO_MODE_IN_CALL) {
-        if (mCallRxPatch != 0) {
-            mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
-            mCallRxPatch.clear();
+        if (state == AUDIO_MODE_IN_CALL) {
+            updateCallRouting(rxDevice, delayMs);
+        } else if (oldState == AUDIO_MODE_IN_CALL) {
+            if (mCallRxPatch != 0) {
+                mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
+                mCallRxPatch.clear();
+            }
+            if (mCallTxPatch != 0) {
+                mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
+                mCallTxPatch.clear();
+            }
+            setOutputDevice(mPrimaryOutput, rxDevice, force, 0);
+        } else {
+            setOutputDevice(mPrimaryOutput, rxDevice, force, 0);
         }
-        if (mCallTxPatch != 0) {
-            mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
-            mCallTxPatch.clear();
-        }
-        setOutputDevice(mPrimaryOutput, rxDevice, force, 0);
-    } else {
-        setOutputDevice(mPrimaryOutput, rxDevice, force, 0);
     }
     // if entering in call state, handle special case of active streams
     // pertaining to sonification strategy see handleIncallSonification()
@@ -543,7 +546,7 @@
     checkA2dpSuspend();
     checkOutputForAllStrategies();
     updateDevicesAndOutputs();
-    if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) {
+    if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
         audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/);
         updateCallRouting(newDevice);
     }
@@ -579,24 +582,43 @@
                                                                audio_channel_mask_t channelMask,
                                                                audio_output_flags_t flags)
 {
+    // only retain flags that will drive the direct output profile selection
+    // if explicitly requested
+    static const uint32_t kRelevantFlags =
+            (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+    flags =
+        (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
+
+    sp<IOProfile> profile;
+
     for (size_t i = 0; i < mHwModules.size(); i++) {
         if (mHwModules[i]->mHandle == 0) {
             continue;
         }
         for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
-            sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
-            bool found = profile->isCompatibleProfile(device, String8(""),
+            sp<IOProfile> curProfile = mHwModules[i]->mOutputProfiles[j];
+            if (!curProfile->isCompatibleProfile(device, String8(""),
                     samplingRate, NULL /*updatedSamplingRate*/,
                     format, NULL /*updatedFormat*/,
                     channelMask, NULL /*updatedChannelMask*/,
-                    flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ?
-                        AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT);
-            if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) {
-                return profile;
+                    flags)) {
+                continue;
+            }
+            // reject profiles not corresponding to a device currently available
+            if ((mAvailableOutputDevices.types() & curProfile->mSupportedDevices.types()) == 0) {
+                continue;
+            }
+            // if several profiles are compatible, give priority to one with offload capability
+            if (profile != 0 && ((curProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
+                continue;
+            }
+            profile = curProfile;
+            if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+                break;
             }
         }
     }
-    return 0;
+    return profile;
 }
 
 audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
@@ -819,10 +841,27 @@
         if (outputDesc != NULL) {
             closeOutput(outputDesc->mIoHandle);
         }
+
+        // if the selected profile is offloaded and no offload info was specified,
+        // create a default one
+        audio_offload_info_t defaultOffloadInfo = AUDIO_INFO_INITIALIZER;
+        if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
+            flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+            defaultOffloadInfo.sample_rate = samplingRate;
+            defaultOffloadInfo.channel_mask = channelMask;
+            defaultOffloadInfo.format = format;
+            defaultOffloadInfo.stream_type = stream;
+            defaultOffloadInfo.bit_rate = 0;
+            defaultOffloadInfo.duration_us = -1;
+            defaultOffloadInfo.has_video = true; // conservative
+            defaultOffloadInfo.is_streaming = true; // likely
+            offloadInfo = &defaultOffloadInfo;
+        }
+
         outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface);
         outputDesc->mDevice = device;
         outputDesc->mLatency = 0;
-        outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags);
+        outputDesc->mFlags = (audio_output_flags_t)(outputDesc->mFlags | flags);
         audio_config_t config = AUDIO_CONFIG_INITIALIZER;
         config.sample_rate = samplingRate;
         config.channel_mask = channelMask;
@@ -854,10 +893,6 @@
             if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) {
                 goto non_direct_output;
             }
-            // fall back to mixer output if possible when the direct output could not be open
-            if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) {
-                goto non_direct_output;
-            }
             return AUDIO_IO_HANDLE_NONE;
         }
         outputDesc->mSamplingRate = config.sample_rate;
@@ -1226,7 +1261,7 @@
             // If effects where present on the output, audioflinger moved them to the primary
             // output by default: move them back to the appropriate output.
             audio_io_handle_t dstOutput = getOutputForEffect();
-            if (dstOutput != mPrimaryOutput->mIoHandle) {
+            if (hasPrimaryOutput() && dstOutput != mPrimaryOutput->mIoHandle) {
                 mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX,
                                                mPrimaryOutput->mIoHandle, dstOutput);
             }
@@ -1934,7 +1969,8 @@
     snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
     result.append(buffer);
 
-    snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput->mIoHandle);
+    snprintf(buffer, SIZE, " Primary Output: %d\n",
+             hasPrimaryOutput() ? mPrimaryOutput->mIoHandle : AUDIO_IO_HANDLE_NONE);
     result.append(buffer);
     snprintf(buffer, SIZE, " Phone state: %d\n", mEngine->getPhoneState());
     result.append(buffer);
@@ -2896,7 +2932,7 @@
 
 status_t AudioPolicyManager::initCheck()
 {
-    return (mPrimaryOutput == 0) ? NO_INIT : NO_ERROR;
+    return hasPrimaryOutput() ? NO_ERROR : NO_INIT;
 }
 
 #ifdef AUDIO_POLICY_TEST
@@ -3271,7 +3307,8 @@
                         policyMix->setOutput(desc);
                         desc->mPolicyMix = policyMix->getMix();
 
-                    } else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+                    } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
+                                    hasPrimaryOutput()) {
                         // no duplicated output for direct outputs and
                         // outputs used by dynamic policy mixes
                         audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;
@@ -4600,6 +4637,10 @@
 void AudioPolicyManager::handleIncallSonification(audio_stream_type_t stream,
                                                       bool starting, bool stateChange)
 {
+    if(!hasPrimaryOutput()) {
+        return;
+    }
+
     // if the stream pertains to sonification strategy and we are in call we must
     // mute the stream if it is low visibility. If it is high visibility, we must play a tone
     // in the device used for phone strategy and play the tone if the selected device does not
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index ea16864..f9d1198 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -553,10 +553,16 @@
 
         audio_devices_t availablePrimaryOutputDevices() const
         {
+            if (!hasPrimaryOutput()) {
+                return AUDIO_DEVICE_NONE;
+            }
             return mPrimaryOutput->supportedDevices() & mAvailableOutputDevices.types();
         }
         audio_devices_t availablePrimaryInputDevices() const
         {
+            if (!hasPrimaryOutput()) {
+                return AUDIO_DEVICE_NONE;
+            }
             return mAvailableInputDevices.getDevicesFromHwModule(mPrimaryOutput->getModuleHandle());
         }
 
@@ -576,6 +582,8 @@
         void clearSessionRoutes(uid_t uid);
         void checkStrategyRoute(routing_strategy strategy, audio_io_handle_t ouptutToSkip);
 
+        status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
+
         uid_t mUidCached;
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index fc9a332..79e73f9 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -33,6 +33,7 @@
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
 #include <binder/ProcessInfoService.h>
+#include <camera/ICameraServiceProxy.h>
 #include <cutils/atomic.h>
 #include <cutils/properties.h>
 #include <gui/Surface.h>
@@ -224,6 +225,18 @@
     }
 
     CameraDeviceFactory::registerService(this);
+
+    CameraService::pingCameraServiceProxy();
+}
+
+void CameraService::pingCameraServiceProxy() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.camera.proxy"));
+    if (binder == nullptr) {
+        return;
+    }
+    sp<ICameraServiceProxy> proxyBinder = interface_cast<ICameraServiceProxy>(binder);
+    proxyBinder->pingForUserUpdate();
 }
 
 CameraService::~CameraService() {
@@ -959,6 +972,10 @@
                         "(PID %" PRId32 ", priority %" PRId32 ")", i->getKey().string(),
                         String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
                         i->getPriority());
+                ALOGE("   Conflicts with: Device %s, client package %s (PID %"
+                        PRId32 ", priority %" PRId32 ")", i->getKey().string(),
+                        String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
+                        i->getPriority());
             }
 
             // Log the client's attempt
@@ -1975,7 +1992,7 @@
         auto conflicting = i->getConflicting();
         auto clientSp = i->getValue();
         String8 packageName;
-        userid_t clientUserId;
+        userid_t clientUserId = 0;
         if (clientSp.get() != nullptr) {
             packageName = String8{clientSp->getPackageName()};
             uid_t clientUid = clientSp->getClientUid();
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 9b7163a..ce3cb44 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -702,6 +702,8 @@
 
     static String8 toString(std::set<userid_t> intSet);
 
+    static void pingCameraServiceProxy();
+
 };
 
 template<class Func>
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 05ede92..f2d6ab2 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1881,6 +1881,16 @@
     mCaptureSequencer->notifyAutoExposure(newState, triggerId);
 }
 
+void Camera2Client::notifyShutter(const CaptureResultExtras& resultExtras,
+                                  nsecs_t timestamp) {
+    (void)resultExtras;
+    (void)timestamp;
+
+    ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64,
+            __FUNCTION__, resultExtras.requestId, timestamp);
+    mCaptureSequencer->notifyShutter(resultExtras, timestamp);
+}
+
 camera2::SharedParameters& Camera2Client::getParameters() {
     return mParameters;
 }
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index a988037..3784aab 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -106,6 +106,8 @@
 
     virtual void notifyAutoFocus(uint8_t newState, int triggerId);
     virtual void notifyAutoExposure(uint8_t newState, int triggerId);
+    virtual void notifyShutter(const CaptureResultExtras& resultExtras,
+                               nsecs_t timestamp);
 
     /**
      * Interface used by independent components of Camera2Client.
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 9849f4d..d847e0f 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -43,6 +43,8 @@
         mNewFrameReceived(false),
         mNewCaptureReceived(false),
         mShutterNotified(false),
+        mHalNotifiedShutter(false),
+        mShutterCaptureId(-1),
         mClient(client),
         mCaptureState(IDLE),
         mStateTransitionCount(0),
@@ -106,6 +108,16 @@
     }
 }
 
+void CaptureSequencer::notifyShutter(const CaptureResultExtras& resultExtras,
+                                     nsecs_t timestamp) {
+    ATRACE_CALL();
+    Mutex::Autolock l(mInputMutex);
+    if (!mHalNotifiedShutter && resultExtras.requestId == mShutterCaptureId) {
+        mHalNotifiedShutter = true;
+        mShutterNotifySignal.signal();
+    }
+}
+
 void CaptureSequencer::onResultAvailable(const CaptureResult &result) {
     ATRACE_CALL();
     ALOGV("%s: New result available.", __FUNCTION__);
@@ -335,6 +347,11 @@
     } else {
         nextState = STANDARD_START;
     }
+    {
+        Mutex::Autolock l(mInputMutex);
+        mShutterCaptureId = mCaptureId;
+        mHalNotifiedShutter = false;
+    }
     mShutterNotified = false;
 
     return nextState;
@@ -541,6 +558,7 @@
             return DONE;
         }
     }
+
     // TODO: Capture should be atomic with setStreamingRequest here
     res = client->getCameraDevice()->capture(captureCopy);
     if (res != OK) {
@@ -560,6 +578,31 @@
     ATRACE_CALL();
     Mutex::Autolock l(mInputMutex);
 
+
+    // Wait for shutter callback
+    while (!mHalNotifiedShutter) {
+        if (mTimeoutCount <= 0) {
+            break;
+        }
+        res = mShutterNotifySignal.waitRelative(mInputMutex, kWaitDuration);
+        if (res == TIMED_OUT) {
+            mTimeoutCount--;
+            return STANDARD_CAPTURE_WAIT;
+        }
+    }
+
+    if (mHalNotifiedShutter) {
+        if (!mShutterNotified) {
+            SharedParameters::Lock l(client->getParameters());
+            /* warning: this also locks a SharedCameraCallbacks */
+            shutterNotifyLocked(l.mParameters, client, mMsgType);
+            mShutterNotified = true;
+        }
+    } else if (mTimeoutCount <= 0) {
+        ALOGW("Timed out waiting for shutter notification");
+        return DONE;
+    }
+
     // Wait for new metadata result (mNewFrame)
     while (!mNewFrameReceived) {
         res = mNewFrameSignal.waitRelative(mInputMutex, kWaitDuration);
@@ -569,15 +612,6 @@
         }
     }
 
-    // Approximation of the shutter being closed
-    // - TODO: use the hal3 exposure callback in Camera3Device instead
-    if (mNewFrameReceived && !mShutterNotified) {
-        SharedParameters::Lock l(client->getParameters());
-        /* warning: this also locks a SharedCameraCallbacks */
-        shutterNotifyLocked(l.mParameters, client, mMsgType);
-        mShutterNotified = true;
-    }
-
     // Wait until jpeg was captured by JpegProcessor
     while (mNewFrameReceived && !mNewCaptureReceived) {
         res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
@@ -591,6 +625,7 @@
         return DONE;
     }
     if (mNewFrameReceived && mNewCaptureReceived) {
+
         if (mNewFrameId != mCaptureId) {
             ALOGW("Mismatched capture frame IDs: Expected %d, got %d",
                     mCaptureId, mNewFrameId);
@@ -667,7 +702,6 @@
         sp<Camera2Client> &/*client*/) {
     status_t res;
     ATRACE_CALL();
-
     while (!mNewCaptureReceived) {
         res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
         if (res == TIMED_OUT) {
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index d42ab13..10252fb 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -62,6 +62,10 @@
     // Notifications about AE state changes
     void notifyAutoExposure(uint8_t newState, int triggerId);
 
+    // Notifications about shutter (capture start)
+    void notifyShutter(const CaptureResultExtras& resultExtras,
+                       nsecs_t timestamp);
+
     // Notification from the frame processor
     virtual void onResultAvailable(const CaptureResult &result);
 
@@ -95,7 +99,10 @@
     sp<MemoryBase> mCaptureBuffer;
     Condition mNewCaptureSignal;
 
-    bool mShutterNotified;
+    bool mShutterNotified; // Has CaptureSequencer sent shutter to Client
+    bool mHalNotifiedShutter; // Has HAL sent shutter to CaptureSequencer
+    int32_t mShutterCaptureId; // The captureId which is waiting for shutter notification
+    Condition mShutterNotifySignal;
 
     /**
      * Internal to CaptureSequencer
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 081aff7..9de6fe2 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -787,6 +787,7 @@
                 mHwDevice->stop_recognition(mHwDevice, model->mHandle);
                 // keep model in ACTIVE state so that event is processed by onCallbackEvent()
                 struct sound_trigger_phrase_recognition_event phraseEvent;
+                memset(&phraseEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event));
                 switch (model->mType) {
                 case SOUND_MODEL_TYPE_KEYPHRASE:
                     phraseEvent.num_phrases = model->mConfig.num_phrases;