Merge "audio policy: favor mixed over direct output for PCM format" into lmp-dev
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index dd63a23..f8c0198 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -320,6 +320,8 @@
                                            audio_devices_t *device);
     static status_t releaseSoundTriggerSession(audio_session_t session);
 
+    static audio_mode_t getPhoneState();
+
     // ----------------------------------------------------------------------------
 
     class AudioPortCallback : public RefBase
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index c251439..16fe9cf 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -142,6 +142,8 @@
                                            audio_devices_t *device) = 0;
 
     virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0;
+
+    virtual audio_mode_t getPhoneState() = 0;
 };
 
 
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 1742fbe..dda3657 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -939,6 +939,15 @@
     if (aps == 0) return PERMISSION_DENIED;
     return aps->releaseSoundTriggerSession(session);
 }
+
+audio_mode_t AudioSystem::getPhoneState()
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return AUDIO_MODE_INVALID;
+    return aps->getPhoneState();
+}
+
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ea7b279..e3beba5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2124,9 +2124,16 @@
 
     // usage to stream type mapping
     switch (aa.usage) {
+    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+        // TODO once AudioPolicyManager fully supports audio_attributes_t,
+        //   remove stream change based on phone state
+        if (AudioSystem::getPhoneState() == AUDIO_MODE_RINGTONE) {
+            mStreamType = AUDIO_STREAM_RING;
+            break;
+        }
+        /// FALL THROUGH
     case AUDIO_USAGE_MEDIA:
     case AUDIO_USAGE_GAME:
-    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
     case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
         mStreamType = AUDIO_STREAM_MUSIC;
         return;
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index b57f747..256cb3f 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -67,7 +67,8 @@
     REGISTER_CLIENT,
     GET_OUTPUT_FOR_ATTR,
     ACQUIRE_SOUNDTRIGGER_SESSION,
-    RELEASE_SOUNDTRIGGER_SESSION
+    RELEASE_SOUNDTRIGGER_SESSION,
+    GET_PHONE_STATE
 };
 
 class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
@@ -607,6 +608,17 @@
         }
         return (status_t)reply.readInt32();
     }
+
+    virtual audio_mode_t getPhoneState()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_PHONE_STATE, data, &reply);
+        if (status != NO_ERROR) {
+            return AUDIO_MODE_INVALID;
+        }
+        return (audio_mode_t)reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1057,6 +1069,12 @@
             return NO_ERROR;
         } break;
 
+        case GET_PHONE_STATE: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            reply->writeInt32((int32_t)getPhoneState());
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmediaplayerservice/VideoFrameScheduler.cpp b/media/libmediaplayerservice/VideoFrameScheduler.cpp
index 4251c4e..1a5f3e0 100644
--- a/media/libmediaplayerservice/VideoFrameScheduler.cpp
+++ b/media/libmediaplayerservice/VideoFrameScheduler.cpp
@@ -152,7 +152,7 @@
 
 #endif
 
-void VideoFrameScheduler::PLL::fit(
+bool VideoFrameScheduler::PLL::fit(
         nsecs_t phase, nsecs_t period, size_t numSamplesToUse,
         int64_t *a, int64_t *b, int64_t *err) {
     if (numSamplesToUse > mNumSamples) {
@@ -187,6 +187,10 @@
     }
 
     int64_t div   = numSamplesToUse * sumXX - sumX * sumX;
+    if (div == 0) {
+        return false;
+    }
+
     int64_t a_nom = numSamplesToUse * sumXY - sumX * sumY;
     int64_t b_nom = sumXX * sumY            - sumX * sumXY;
     *a = divRound(a_nom, div);
@@ -198,6 +202,7 @@
             (long long)*a,   (*a / (float)(1 << kPrecision)),
             (long long)*b,   (*b / (float)(1 << kPrecision)),
             (long long)*err, (*err / (float)(1 << (kPrecision * 2))));
+    return true;
 }
 
 void VideoFrameScheduler::PLL::prime(size_t numSamplesToUse) {
@@ -226,7 +231,7 @@
     deltas.sort(compare<nsecs_t>);
     size_t numDeltas = deltas.size();
     if (numDeltas > 1) {
-        nsecs_t deltaMinLimit = min(deltas[0] / kMultiplesThresholdDiv, kMinPeriod);
+        nsecs_t deltaMinLimit = max(deltas[0] / kMultiplesThresholdDiv, kMinPeriod);
         nsecs_t deltaMaxLimit = deltas[numDeltas / 2] * kMultiplesThresholdDiv;
         for (size_t i = numDeltas / 2 + 1; i < numDeltas; ++i) {
             if (deltas[i] > deltaMaxLimit) {
@@ -314,8 +319,15 @@
 
         if (doFit) {
             int64_t a, b, err;
+            if (!fit(mPhase, mPeriod, kMaxSamplesToEstimatePeriod, &a, &b, &err)) {
+                // samples are not suitable for fitting.  this means they are
+                // also not suitable for priming.
+                ALOGV("could not fit - keeping old period:%lld", (long long)mPeriod);
+                return mPeriod;
+            }
+
             mRefitAt = time + kRefitRefreshPeriod;
-            fit(mPhase, mPeriod, kMaxSamplesToEstimatePeriod, &a, &b, &err);
+
             mPhase += (mPeriod * b) >> kPrecision;
             mPeriod = (mPeriod * a) >> kPrecision;
             ALOGV("new phase:%lld period:%lld", (long long)mPhase, (long long)mPeriod);
diff --git a/media/libmediaplayerservice/VideoFrameScheduler.h b/media/libmediaplayerservice/VideoFrameScheduler.h
index 19f0787..84b27b4 100644
--- a/media/libmediaplayerservice/VideoFrameScheduler.h
+++ b/media/libmediaplayerservice/VideoFrameScheduler.h
@@ -71,7 +71,8 @@
         nsecs_t mTimes[kHistorySize];
 
         void test();
-        void fit(nsecs_t phase, nsecs_t period, size_t numSamples,
+        // returns whether fit was successful
+        bool fit(nsecs_t phase, nsecs_t period, size_t numSamples,
                 int64_t *a, int64_t *b, int64_t *err);
         void prime(size_t numSamples);
     };
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index bd75034..f84decd 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1198,10 +1198,17 @@
     switch (trackType) {
         case MEDIA_TRACK_TYPE_VIDEO:
             track = &mVideoTrack;
+            if (mIsWidevine) {
+                maxBuffers = 2;
+            }
             break;
         case MEDIA_TRACK_TYPE_AUDIO:
             track = &mAudioTrack;
-            maxBuffers = 64;
+            if (mIsWidevine) {
+                maxBuffers = 8;
+            } else {
+                maxBuffers = 64;
+            }
             break;
         case MEDIA_TRACK_TYPE_SUBTITLE:
             track = &mSubtitleTrack;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index ceedb40..ca596fd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -559,7 +559,7 @@
                         static_cast<NativeWindowWrapper *>(obj.get())));
 
             if (obj != NULL) {
-                if (mStarted && mVideoDecoder != NULL) {
+                if (mStarted && mSource->getFormat(false /* audio */) != NULL) {
                     // Issue a seek to refresh the video screen only if started otherwise
                     // the extractor may not yet be started and will assert.
                     // If the video decoder is not set (perhaps audio only in this case)
@@ -832,24 +832,31 @@
 
                 finishFlushIfPossible();
             } else if (what == Decoder::kWhatError) {
-                ALOGE("Received error from %s decoder, aborting playback.",
-                     audio ? "audio" : "video");
-
                 status_t err;
                 if (!msg->findInt32("err", &err)) {
                     err = UNKNOWN_ERROR;
                 }
-                mRenderer->queueEOS(audio, err);
+                ALOGE("received error from %s decoder %#x", audio ? "audio" : "video", err);
+
+                ALOGI("shutting down %s", audio ? "audio" : "video");
                 if (audio && mFlushingAudio != NONE) {
+                    mRenderer->queueEOS(audio, err);
                     mAudioDecoder.clear();
                     ++mAudioDecoderGeneration;
                     mFlushingAudio = SHUT_DOWN;
-                } else if (!audio && mFlushingVideo != NONE){
+                    finishFlushIfPossible();
+                } else if (!audio && mFlushingVideo != NONE) {
+                    mRenderer->queueEOS(audio, err);
                     mVideoDecoder.clear();
                     ++mVideoDecoderGeneration;
                     mFlushingVideo = SHUT_DOWN;
+                    finishFlushIfPossible();
+                }  else {
+                    mDeferredActions.push_back(
+                            new ShutdownDecoderAction(audio, !audio /* video */));
+                    processDeferredActions();
+                    notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
                 }
-                finishFlushIfPossible();
             } else if (what == Decoder::kWhatDrainThisBuffer) {
                 renderBuffer(audio, msg);
             } else {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index cdb860c..1a066b7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -53,6 +53,10 @@
 }
 
 NuPlayer::Decoder::~Decoder() {
+    mDecoderLooper->unregisterHandler(id());
+    mDecoderLooper->stop();
+
+    releaseAndResetMediaBuffers();
 }
 
 static
@@ -223,7 +227,11 @@
 
 void NuPlayer::Decoder::handleError(int32_t err)
 {
-    mCodec->release();
+    // We cannot immediately release the codec due to buffers still outstanding
+    // in the renderer.  We signal to the player the error so it can shutdown/release the
+    // decoder after flushing and increment the generation to discard unnecessary messages.
+
+    ++mBufferGeneration;
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatError);
@@ -238,6 +246,8 @@
             mComponentName.c_str(), res == OK ? (int)bufferIx : res);
     if (res != OK) {
         if (res != -EAGAIN) {
+            ALOGE("Failed to dequeue input buffer for %s (err=%d)",
+                    mComponentName.c_str(), res);
             handleError(res);
         }
         return false;
@@ -311,7 +321,7 @@
         }
     }
 
-    mInputBufferIsDequeued.editItemAt(bufferIx) = false;
+
 
     if (buffer == NULL /* includes !hasBuffer */) {
         int32_t streamErr = ERROR_END_OF_STREAM;
@@ -329,12 +339,18 @@
                 0,
                 0,
                 MediaCodec::BUFFER_FLAG_EOS);
-        if (streamErr == ERROR_END_OF_STREAM && err != OK) {
+        if (err == OK) {
+            mInputBufferIsDequeued.editItemAt(bufferIx) = false;
+        } else if (streamErr == ERROR_END_OF_STREAM) {
             streamErr = err;
             // err will not be ERROR_END_OF_STREAM
         }
 
         if (streamErr != ERROR_END_OF_STREAM) {
+            ALOGE("Stream error for %s (err=%d), EOS %s queued",
+                    mComponentName.c_str(),
+                    streamErr,
+                    err == OK ? "successfully" : "unsuccessfully");
             handleError(streamErr);
         }
     } else {
@@ -364,14 +380,18 @@
                         timeUs,
                         flags);
         if (err != OK) {
+            if (mediaBuffer != NULL) {
+                mediaBuffer->release();
+            }
             ALOGE("Failed to queue input buffer for %s (err=%d)",
                     mComponentName.c_str(), err);
             handleError(err);
-        }
-
-        if (mediaBuffer != NULL) {
-            CHECK(mMediaBuffers[bufferIx] == NULL);
-            mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
+        } else {
+            mInputBufferIsDequeued.editItemAt(bufferIx) = false;
+            if (mediaBuffer != NULL) {
+                CHECK(mMediaBuffers[bufferIx] == NULL);
+                mMediaBuffers.editItemAt(bufferIx) = mediaBuffer;
+            }
         }
     }
 }
@@ -422,6 +442,8 @@
         return true;
     } else if (res != OK) {
         if (res != -EAGAIN) {
+            ALOGE("Failed to dequeue output buffer for %s (err=%d)",
+                    mComponentName.c_str(), res);
             handleError(res);
         }
         return false;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 3c04859..4589ed1 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2933,13 +2933,6 @@
     image.mNumPlanes = 0;
 
     const OMX_COLOR_FORMATTYPE fmt = params.eColorFormat;
-    // we need stride and slice-height to be non-zero
-    if (params.nStride == 0 || params.nSliceHeight == 0) {
-        ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
-                fmt, fmt, params.nStride, params.nSliceHeight);
-        return false;
-    }
-
     image.mWidth = params.nFrameWidth;
     image.mHeight = params.nFrameHeight;
 
@@ -2952,6 +2945,20 @@
         return false;
     }
 
+    // TEMPORARY FIX for some vendors that advertise sliceHeight as 0
+    if (params.nStride != 0 && params.nSliceHeight == 0) {
+        ALOGW("using sliceHeight=%u instead of what codec advertised (=0)",
+                params.nFrameHeight);
+        params.nSliceHeight = params.nFrameHeight;
+    }
+
+    // we need stride and slice-height to be non-zero
+    if (params.nStride == 0 || params.nSliceHeight == 0) {
+        ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
+                fmt, fmt, params.nStride, params.nSliceHeight);
+        return false;
+    }
+
     // set-up YUV format
     image.mType = MediaImage::MEDIA_IMAGE_TYPE_YUV;
     image.mNumPlanes = 3;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 6c98c52..b56819c 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -589,7 +589,12 @@
     if (index < buffers->size()) {
         const BufferInfo &info = buffers->itemAt(index);
         if (info.mOwnedByClient) {
-            *buffer = info.mData;
+            // by the time buffers array is initialized, crypto is set
+            if (portIndex == kPortIndexInput && mCrypto != NULL) {
+                *buffer = info.mEncryptedData;
+            } else {
+                *buffer = info.mData;
+            }
             *format = info.mFormat;
         }
     }
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index be2a873..f469d4d 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -254,6 +254,10 @@
             // set mDisconnecting to true, if a fetch returns after
             // this, the source will be marked as EOS.
             mDisconnecting = true;
+
+            // explicitly signal mCondition so that the pending readAt()
+            // will immediately return
+            mCondition.signal();
         }
 
         // explicitly disconnect from the source, to allow any
@@ -325,7 +329,11 @@
 
         Mutex::Autolock autoLock(mLock);
 
-        if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
+        if (mDisconnecting) {
+            mNumRetriesLeft = 0;
+            mFinalStatus = ERROR_END_OF_STREAM;
+            return;
+        } else if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
             // These are errors that are not likely to go away even if we
             // retry, i.e. the server doesn't support range requests or similar.
             mNumRetriesLeft = 0;
@@ -515,10 +523,14 @@
     CHECK(mAsyncResult == NULL);
     msg->post();
 
-    while (mAsyncResult == NULL) {
+    while (mAsyncResult == NULL && !mDisconnecting) {
         mCondition.wait(mLock);
     }
 
+    if (mDisconnecting) {
+        return ERROR_END_OF_STREAM;
+    }
+
     int32_t result;
     CHECK(mAsyncResult->findInt32("result", &result));
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index fb27dca..e701e9e 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -974,11 +974,15 @@
         mDecodedSizes.clear();
         mLastInHeader = NULL;
     } else {
-        while (outputDelayRingBufferSamplesAvailable() > 0) {
-            int32_t ns = outputDelayRingBufferGetSamples(0,
-                    mStreamInfo->frameSize * mStreamInfo->numChannels);
-            if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) {
+        int avail;
+        while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) {
+            if (avail > mStreamInfo->frameSize * mStreamInfo->numChannels) {
+                avail = mStreamInfo->frameSize * mStreamInfo->numChannels;
+            }
+            int32_t ns = outputDelayRingBufferGetSamples(0, avail);
+            if (ns != avail) {
                 ALOGE("not a complete frame of samples available");
+                break;
             }
             mOutputBufferCount++;
         }
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index 5b2ab84..d98fa80 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -295,19 +295,23 @@
     ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
             disp_width, disp_height, buf_width, buf_height);
 
-    bool cropChanged = false;
-    if (mCropWidth != disp_width || mCropHeight != disp_height) {
-        mCropLeft = 0;
-        mCropTop = 0;
-        mCropWidth = disp_width;
-        mCropHeight = disp_height;
-        cropChanged = true;
+    CropSettingsMode cropSettingsMode = kCropUnSet;
+    if (disp_width != buf_width || disp_height != buf_height) {
+        cropSettingsMode = kCropSet;
+
+        if (mCropWidth != disp_width || mCropHeight != disp_height) {
+            mCropLeft = 0;
+            mCropTop = 0;
+            mCropWidth = disp_width;
+            mCropHeight = disp_height;
+            cropSettingsMode = kCropChanged;
+        }
     }
 
     bool portWillReset = false;
     const bool fakeStride = true;
     SoftVideoDecoderOMXComponent::handlePortSettingsChange(
-            &portWillReset, buf_width, buf_height, cropChanged, fakeStride);
+            &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride);
     if (portWillReset) {
         if (mMode == MODE_H263) {
             PVCleanUpVideoDecoder(mHandle);
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
index cf3c3e3..168208f 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
@@ -160,10 +160,11 @@
                     H264SwDecInfo decoderInfo;
                     CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK);
 
-                    bool cropChanged = handleCropChange(decoderInfo);
+                    SoftVideoDecoderOMXComponent::CropSettingsMode cropSettingsMode =
+                        handleCropParams(decoderInfo);
                     handlePortSettingsChange(
                             &portWillReset, decoderInfo.picWidth, decoderInfo.picHeight,
-                            cropChanged);
+                            cropSettingsMode);
                 }
             } else {
                 if (portWillReset) {
@@ -209,9 +210,10 @@
     }
 }
 
-bool SoftAVC::handleCropChange(const H264SwDecInfo& decInfo) {
+SoftVideoDecoderOMXComponent::CropSettingsMode SoftAVC::handleCropParams(
+        const H264SwDecInfo& decInfo) {
     if (!decInfo.croppingFlag) {
-        return false;
+        return kCropUnSet;
     }
 
     const CropParams& crop = decInfo.cropParams;
@@ -219,14 +221,14 @@
         mCropTop == crop.cropTopOffset &&
         mCropWidth == crop.cropOutWidth &&
         mCropHeight == crop.cropOutHeight) {
-        return false;
+        return kCropSet;
     }
 
     mCropLeft = crop.cropLeftOffset;
     mCropTop = crop.cropTopOffset;
     mCropWidth = crop.cropOutWidth;
     mCropHeight = crop.cropOutHeight;
-    return true;
+    return kCropChanged;
 }
 
 void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) {
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
index 253a406..069107d 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
@@ -73,7 +73,7 @@
     void drainAllOutputBuffers(bool eos);
     void drainOneOutputBuffer(int32_t picId, uint8_t *data);
     void saveFirstOutputBuffer(int32_t pidId, uint8_t *data);
-    bool handleCropChange(const H264SwDecInfo& decInfo);
+    CropSettingsMode handleCropParams(const H264SwDecInfo& decInfo);
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftAVC);
 };
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index c97be28..1cbef39 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -73,22 +73,22 @@
     <Encoders>
         <MediaCodec name="OMX.google.h263.encoder" type="video/3gpp">
             <!-- profiles and levels:  ProfileBaseline : Level45 -->
-            <Limit name="size" min="2x2" max="176x144" />
-            <Limit name="alignment" value="2x2" />
+            <Limit name="size" min="16x16" max="176x144" />
+            <Limit name="alignment" value="16x16" />
             <Limit name="bitrate" range="1-128000" />
         </MediaCodec>
         <MediaCodec name="OMX.google.h264.encoder" type="video/avc">
             <!-- profiles and levels:  ProfileBaseline : Level2 -->
-            <Limit name="size" min="2x2" max="896x896" />
-            <Limit name="alignment" value="2x2" />
+            <Limit name="size" min="16x16" max="896x896" />
+            <Limit name="alignment" value="16x16" />
             <Limit name="block-size" value="16x16" />
             <Limit name="blocks-per-second" range="1-11880" />
             <Limit name="bitrate" range="1-2000000" />
         </MediaCodec>
         <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es">
             <!-- profiles and levels:  ProfileCore : Level2 -->
-            <Limit name="size" min="2x2" max="176x144" />
-            <Limit name="alignment" value="2x2" />
+            <Limit name="size" min="16x16" max="176x144" />
+            <Limit name="alignment" value="16x16" />
             <Limit name="block-size" value="16x16" />
             <Limit name="blocks-per-second" range="12-1485" />
             <Limit name="bitrate" range="1-64000" />
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index bc3e3fb..795e8a6 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -485,7 +485,7 @@
             {
                 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
 
-                if (buffer != NULL && buffer->size() <= 64) {
+                if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
                     tmp = StringPrintf("Buffer %s = {\n", item.mName);
                     hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
                     appendIndent(&tmp, indent + 2);
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index a289637..7a9a1a3 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -353,10 +353,6 @@
     sp<AMessage> response;
     status_t err = msg->postAndAwaitResponse(&response);
 
-    uint32_t replyID;
-    CHECK(response == mSeekReply && 0 != mSeekReplyID);
-    mSeekReply.clear();
-    mSeekReplyID = 0;
     return err;
 }
 
@@ -382,12 +378,16 @@
 
         case kWhatSeek:
         {
-            CHECK(msg->senderAwaitsResponse(&mSeekReplyID));
+            uint32_t seekReplyID;
+            CHECK(msg->senderAwaitsResponse(&seekReplyID));
+            mSeekReplyID = seekReplyID;
+            mSeekReply = new AMessage;
 
             status_t err = onSeek(msg);
 
-            mSeekReply = new AMessage;
-            mSeekReply->setInt32("err", err);
+            if (err != OK) {
+                msg->post(50000);
+            }
             break;
         }
 
@@ -422,7 +422,10 @@
 
                             if (mSeekReplyID != 0) {
                                 CHECK(mSeekReply != NULL);
+                                mSeekReply->setInt32("err", OK);
                                 mSeekReply->postReply(mSeekReplyID);
+                                mSeekReplyID = 0;
+                                mSeekReply.clear();
                             }
                         }
                     }
@@ -1094,10 +1097,11 @@
     CHECK(msg->findInt64("timeUs", &timeUs));
 
     if (!mReconfigurationInProgress) {
-        changeConfiguration(timeUs, getBandwidthIndex());
+        changeConfiguration(timeUs, mCurBandwidthIndex);
+        return OK;
+    } else {
+        return -EWOULDBLOCK;
     }
-
-    return OK;
 }
 
 status_t LiveSession::getDuration(int64_t *durationUs) const {
@@ -1254,7 +1258,10 @@
 
         if (mSeekReplyID != 0) {
             CHECK(mSeekReply != NULL);
+            mSeekReply->setInt32("err", OK);
             mSeekReply->postReply(mSeekReplyID);
+            mSeekReplyID = 0;
+            mSeekReply.clear();
         }
     }
 }
diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
index 37b1fe1..9e97ebd 100644
--- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
+++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
@@ -68,9 +68,14 @@
     uint32_t outputBufferWidth();
     uint32_t outputBufferHeight();
 
+    enum CropSettingsMode {
+        kCropUnSet = 0,
+        kCropSet,
+        kCropChanged,
+    };
     void handlePortSettingsChange(
             bool *portWillReset, uint32_t width, uint32_t height,
-            bool cropChanged = false, bool fakeStride = false);
+            CropSettingsMode cropSettingsMode = kCropUnSet, bool fakeStride = false);
 
     void copyYV12FrameToOutputBuffer(
             uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 5853469..3d20a79 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -160,15 +160,17 @@
 }
 
 void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
-        bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged, bool fakeStride) {
+        bool *portWillReset, uint32_t width, uint32_t height,
+        CropSettingsMode cropSettingsMode, bool fakeStride) {
     *portWillReset = false;
     bool sizeChanged = (width != mWidth || height != mHeight);
+    bool updateCrop = (cropSettingsMode == kCropUnSet);
+    bool cropChanged = (cropSettingsMode == kCropChanged);
 
     if (sizeChanged || cropChanged) {
         mWidth = width;
         mHeight = height;
 
-        bool updateCrop = !cropChanged;
         if ((sizeChanged && !mIsAdaptive)
             || width > mAdaptiveMaxWidth
             || height > mAdaptiveMaxHeight) {
@@ -343,6 +345,40 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamPortDefinition:
+        {
+            OMX_PARAM_PORTDEFINITIONTYPE *newParams =
+                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+            OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
+            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
+
+            uint32_t oldWidth = def->format.video.nFrameWidth;
+            uint32_t oldHeight = def->format.video.nFrameHeight;
+            uint32_t newWidth = video_def->nFrameWidth;
+            uint32_t newHeight = video_def->nFrameHeight;
+            if (newWidth != oldWidth || newHeight != oldHeight) {
+                bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
+                def->format.video.nFrameWidth =
+                    (mIsAdaptive && outputPort) ? mAdaptiveMaxWidth : newWidth;
+                def->format.video.nFrameHeight =
+                    (mIsAdaptive && outputPort) ? mAdaptiveMaxHeight : newHeight;
+                def->format.video.nStride = def->format.video.nFrameWidth;
+                def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+                def->nBufferSize =
+                    def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3 / 2;
+                if (outputPort) {
+                    mWidth = newWidth;
+                    mHeight = newHeight;
+                    mCropLeft = 0;
+                    mCropTop = 0;
+                    mCropWidth = newWidth;
+                    mCropHeight = newHeight;
+                }
+                newParams->nBufferSize = def->nBufferSize;
+            }
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, params);
     }
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index 2c51e25..b212ca6 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -80,9 +80,16 @@
 
     Mutex::Autolock _l(mLock);
     mAudioPolicyManager->setPhoneState(state);
+    mPhoneState = state;
     return NO_ERROR;
 }
 
+audio_mode_t AudioPolicyService::getPhoneState()
+{
+    Mutex::Autolock _l(mLock);
+    return mPhoneState;
+}
+
 status_t AudioPolicyService::setForceUse(audio_policy_force_use_t usage,
                                          audio_policy_forced_cfg_t config)
 {
diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
index f20c070..1e40bc3 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
@@ -84,9 +84,16 @@
 
     Mutex::Autolock _l(mLock);
     mpAudioPolicy->set_phone_state(mpAudioPolicy, state);
+    mPhoneState = state;
     return NO_ERROR;
 }
 
+audio_mode_t AudioPolicyService::getPhoneState()
+{
+    Mutex::Autolock _l(mLock);
+    return mPhoneState;
+}
+
 status_t AudioPolicyService::setForceUse(audio_policy_force_use_t usage,
                                          audio_policy_forced_cfg_t config)
 {
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 50bb8c7..647cda4 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -59,7 +59,7 @@
 
 AudioPolicyService::AudioPolicyService()
     : BnAudioPolicyService(), mpAudioPolicyDev(NULL), mpAudioPolicy(NULL),
-      mAudioPolicyManager(NULL), mAudioPolicyClient(NULL)
+      mAudioPolicyManager(NULL), mAudioPolicyClient(NULL), mPhoneState(AUDIO_MODE_INVALID)
 {
     char value[PROPERTY_VALUE_MAX];
     const struct hw_module_t *module;
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 0044e7a..2cea40b 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -174,6 +174,8 @@
 
     virtual status_t releaseSoundTriggerSession(audio_session_t session);
 
+    virtual audio_mode_t getPhoneState();
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   int session = 0);
@@ -493,6 +495,7 @@
 
     // Manage all effects configured in audio_effects.conf
     sp<AudioPolicyEffects> mAudioPolicyEffects;
+    audio_mode_t mPhoneState;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index aa9d746..9818c96 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -643,11 +643,10 @@
         params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
                 supportedFlashModes);
     } else {
-        flashMode = Parameters::FLASH_MODE_OFF;
-        params.set(CameraParameters::KEY_FLASH_MODE,
-                CameraParameters::FLASH_MODE_OFF);
-        params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
-                CameraParameters::FLASH_MODE_OFF);
+        // No flash means null flash mode and supported flash modes keys, so
+        // remove them just to be safe
+        params.remove(CameraParameters::KEY_FLASH_MODE);
+        params.remove(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
     }
 
     camera_metadata_ro_entry_t minFocusDistance =
@@ -1617,7 +1616,9 @@
     if (validatedParams.flashMode != flashMode) {
         camera_metadata_ro_entry_t flashAvailable =
             staticInfo(ANDROID_FLASH_INFO_AVAILABLE, 1, 1);
-        if (!flashAvailable.data.u8[0] &&
+        bool isFlashAvailable =
+                flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE;
+        if (!isFlashAvailable &&
                 validatedParams.flashMode != Parameters::FLASH_MODE_OFF) {
             ALOGE("%s: Requested flash mode \"%s\" is not supported: "
                     "No flash on device", __FUNCTION__,
@@ -1642,9 +1643,11 @@
                     newParams.get(CameraParameters::KEY_FLASH_MODE));
             return BAD_VALUE;
         }
-        // Update in case of override
-        newParams.set(CameraParameters::KEY_FLASH_MODE,
-                flashModeEnumToString(validatedParams.flashMode));
+        // Update in case of override, but only if flash is supported
+        if (isFlashAvailable) {
+            newParams.set(CameraParameters::KEY_FLASH_MODE,
+                    flashModeEnumToString(validatedParams.flashMode));
+        }
     }
 
     // WHITE_BALANCE
@@ -2386,7 +2389,7 @@
         const char *flashMode) {
     return
         !flashMode ?
-            Parameters::FLASH_MODE_INVALID :
+            Parameters::FLASH_MODE_OFF :
         !strcmp(flashMode, CameraParameters::FLASH_MODE_OFF) ?
             Parameters::FLASH_MODE_OFF :
         !strcmp(flashMode, CameraParameters::FLASH_MODE_AUTO) ?
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 169eb82..77ad503 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -37,7 +37,8 @@
         Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
                             /*maxSize*/0, format),
         mConsumer(consumer),
-        mTransform(0) {
+        mTransform(0),
+        mTraceFirstBuffer(true) {
 
     if (mConsumer == NULL) {
         ALOGE("%s: Consumer is NULL!", __FUNCTION__);
@@ -51,7 +52,8 @@
         Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize,
                             format),
         mConsumer(consumer),
-        mTransform(0) {
+        mTransform(0),
+        mTraceFirstBuffer(true) {
 
     if (format != HAL_PIXEL_FORMAT_BLOB) {
         ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
@@ -202,6 +204,15 @@
                   " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
         }
     } else {
+        if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
+            {
+                char traceLog[48];
+                snprintf(traceLog, sizeof(traceLog), "Stream %d: first full buffer\n", mId);
+                ATRACE_NAME(traceLog);
+            }
+            mTraceFirstBuffer = false;
+        }
+
         res = currentConsumer->queueBuffer(currentConsumer.get(),
                 container_of(buffer.buffer, ANativeWindowBuffer, handle),
                 anwReleaseFence);
@@ -257,6 +268,7 @@
 status_t Camera3OutputStream::configureQueueLocked() {
     status_t res;
 
+    mTraceFirstBuffer = true;
     if ((res = Camera3IOStreamBase::configureQueueLocked()) != OK) {
         return res;
     }
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index f963326..be278c5 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -84,6 +84,8 @@
 
     virtual status_t  setTransformLocked(int transform);
 
+    bool mTraceFirstBuffer;
+
     /**
      * Internal Camera3Stream interface
      */