Merge "Support for an MPEG2 Program Stream extractor."
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index 0dcab6b..c6087b4 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -88,6 +88,8 @@
 const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
 const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
 const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
+const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
+const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
 
 const char CameraParameters::TRUE[] = "true";
 const char CameraParameters::FALSE[] = "false";
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index a520a6a..ef4cf5c 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -283,7 +283,8 @@
     // outside the current field of view, even when using zoom.
     //
     // Focus area only has effect if the current focus mode is FOCUS_MODE_AUTO,
-    // FOCUS_MODE_MACRO, or FOCUS_MODE_CONTINOUS_VIDEO.
+    // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or
+    // FOCUS_MODE_CONTINUOUS_PICTURE.
     // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
     static const char KEY_FOCUS_AREAS[];
     // Focal length in millimeter.
@@ -504,6 +505,25 @@
     // Example value: "true" or "false". Read only.
     static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
 
+    // The state of the video stabilization. If set to true, both the
+    // preview stream and the recorded video stream are stabilized by
+    // the camera. Only valid to set if KEY_VIDEO_STABILIZATION_SUPPORTED is
+    // set to true.
+    //
+    // The value of this key can be changed any time the camera is
+    // open. If preview or recording is active, it is acceptable for
+    // there to be a slight video glitch when video stabilization is
+    // toggled on and off.
+    //
+    // This only stabilizes video streams (between-frames stabilization), and
+    // has no effect on still image capture.
+    static const char KEY_VIDEO_STABILIZATION[];
+
+    // Returns true if video stabilization is supported. That is, applications
+    // can set KEY_VIDEO_STABILIZATION to true and have a stabilized preview
+    // stream and record stabilized videos.
+    static const char KEY_VIDEO_STABILIZATION_SUPPORTED[];
+
     // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
     static const char TRUE[];
     static const char FALSE[];
@@ -610,19 +630,29 @@
     // recording because the focus changes smoothly . Applications still can
     // call CameraHardwareInterface.takePicture in this mode but the subject may
     // not be in focus. Auto focus starts when the parameter is set.
-    // Applications should not call CameraHardwareInterface.autoFocus in this
-    // mode. To stop continuous focus, applications should change the focus mode
-    // to other modes.
+    //
+    // Applications can call CameraHardwareInterface.autoFocus in this mode. The
+    // focus callback will immediately return with a boolean that indicates
+    // whether the focus is sharp or not. The focus position is locked after
+    // autoFocus call. If applications want to resume the continuous focus,
+    // cancelAutoFocus must be called. Restarting the preview will not resume
+    // the continuous autofocus. To stop continuous focus, applications should
+    // change the focus mode to other modes.
     static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
     // Continuous auto focus mode intended for taking pictures. The camera
     // continuously tries to focus. The speed of focus change is more aggressive
     // than FOCUS_MODE_CONTINUOUS_VIDEO. Auto focus starts when the parameter is
-    // set. If applications call autoFocus in this mode, the focus callback will
-    // immediately return with a boolean that indicates the focus is sharp or
-    // not. The apps can then decide if they want to take a picture immediately
-    // or to change the focus mode to auto, and run a full autofocus cycle. To
-    // stop continuous focus, applications should change the focus mode to other
-    // modes.
+    // set.
+    //
+    // If applications call CameraHardwareInterface.autoFocus in this mode, the
+    // focus callback will immediately return with a boolean that indicates
+    // whether the focus is sharp or not. The apps can then decide if they want
+    // to take a picture immediately or to change the focus mode to auto, and
+    // run a full autofocus cycle. The focus position is locked after autoFocus
+    // call. If applications want to resume the continuous focus,
+    // cancelAutoFocus must be called. Restarting the preview will not resume
+    // the continuous autofocus. To stop continuous focus, applications should
+    // change the focus mode to other modes.
     static const char FOCUS_MODE_CONTINUOUS_PICTURE[];
 
 private:
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 21b8c74..0d5a726 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -319,6 +319,8 @@
     void initOutputFormat(const sp<MetaData> &inputFormat);
     status_t initNativeWindow();
 
+    void initNativeWindowCrop();
+
     void dumpPortStatus(OMX_U32 portIndex);
 
     status_t configureCodec(const sp<MetaData> &meta);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 6fdb726..6981668 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -554,7 +554,7 @@
 }
 
 status_t StagefrightRecorder::setParamGeoDataLongitude(
-    int32_t longitudex10000) {
+    int64_t longitudex10000) {
 
     if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
         return BAD_VALUE;
@@ -564,7 +564,7 @@
 }
 
 status_t StagefrightRecorder::setParamGeoDataLatitude(
-    int32_t latitudex10000) {
+    int64_t latitudex10000) {
 
     if (latitudex10000 > 900000 || latitudex10000 < -900000) {
         return BAD_VALUE;
@@ -602,13 +602,13 @@
             return setParam64BitFileOffset(use64BitOffset != 0);
         }
     } else if (key == "param-geotag-longitude") {
-        int32_t longitudex10000;
-        if (safe_strtoi32(value.string(), &longitudex10000)) {
+        int64_t longitudex10000;
+        if (safe_strtoi64(value.string(), &longitudex10000)) {
             return setParamGeoDataLongitude(longitudex10000);
         }
     } else if (key == "param-geotag-latitude") {
-        int32_t latitudex10000;
-        if (safe_strtoi32(value.string(), &latitudex10000)) {
+        int64_t latitudex10000;
+        if (safe_strtoi64(value.string(), &latitudex10000)) {
             return setParamGeoDataLatitude(latitudex10000);
         }
     } else if (key == "param-track-time-status") {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 5c5f05c..ec5ce7e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -173,8 +173,8 @@
     status_t setParamMaxFileDurationUs(int64_t timeUs);
     status_t setParamMaxFileSizeBytes(int64_t bytes);
     status_t setParamMovieTimeScale(int32_t timeScale);
-    status_t setParamGeoDataLongitude(int32_t longitudex10000);
-    status_t setParamGeoDataLatitude(int32_t latitudex10000);
+    status_t setParamGeoDataLongitude(int64_t longitudex10000);
+    status_t setParamGeoDataLatitude(int64_t latitudex10000);
     void clipVideoBitRate();
     void clipVideoFrameRate();
     void clipVideoFrameWidth();
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 060f3d8..0ddc83a 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -2006,6 +2006,11 @@
             mConnectingDataSource->setUID(mUID);
         }
 
+        String8 cacheConfig;
+        bool disconnectAtHighwatermark;
+        NuCachedSource2::RemoveCacheSpecificHeaders(
+                &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark);
+
         mLock.unlock();
         status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
         mLock.lock();
@@ -2025,7 +2030,10 @@
                     new ThrottledSource(
                         mConnectingDataSource, 50 * 1024 /* bytes/sec */));
 #else
-            mCachedSource = new NuCachedSource2(mConnectingDataSource);
+            mCachedSource = new NuCachedSource2(
+                    mConnectingDataSource,
+                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                    disconnectAtHighwatermark);
 #endif
 
             dataSource = mCachedSource;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 3b79f06..1e24599 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1972,6 +1972,12 @@
                     sampleIndex, &syncSampleIndex, findFlags);
         }
 
+        uint32_t sampleTime;
+        if (err == OK) {
+            err = mSampleTable->getMetaDataForSample(
+                    sampleIndex, NULL, NULL, &sampleTime);
+        }
+
         if (err != OK) {
             if (err == ERROR_OUT_OF_RANGE) {
                 // An attempt to seek past the end of the stream would
@@ -1984,10 +1990,6 @@
             return err;
         }
 
-        uint32_t sampleTime;
-        CHECK_EQ((status_t)OK, mSampleTable->getMetaDataForSample(
-                    sampleIndex, NULL, NULL, &sampleTime));
-
         if (mode == ReadOptions::SEEK_CLOSEST) {
             targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
         }
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 4edb613..4f183f5 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -21,6 +21,7 @@
 #include "include/NuCachedSource2.h"
 #include "include/HTTPBase.h"
 
+#include <cutils/properties.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaErrors.h>
@@ -176,7 +177,10 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-NuCachedSource2::NuCachedSource2(const sp<DataSource> &source)
+NuCachedSource2::NuCachedSource2(
+        const sp<DataSource> &source,
+        const char *cacheConfig,
+        bool disconnectAtHighwatermark)
     : mSource(source),
       mReflector(new AHandlerReflector<NuCachedSource2>(this)),
       mLooper(new ALooper),
@@ -186,7 +190,27 @@
       mLastAccessPos(0),
       mFetching(true),
       mLastFetchTimeUs(-1),
-      mNumRetriesLeft(kMaxNumRetries) {
+      mNumRetriesLeft(kMaxNumRetries),
+      mHighwaterThresholdBytes(kDefaultHighWaterThreshold),
+      mLowwaterThresholdBytes(kDefaultLowWaterThreshold),
+      mKeepAliveIntervalUs(kDefaultKeepAliveIntervalUs),
+      mDisconnectAtHighwatermark(disconnectAtHighwatermark) {
+    // We are NOT going to support disconnect-at-highwatermark indefinitely
+    // and we are not guaranteeing support for client-specified cache
+    // parameters. Both of these are temporary measures to solve a specific
+    // problem that will be solved in a better way going forward.
+
+    updateCacheParamsFromSystemProperty();
+
+    if (cacheConfig != NULL) {
+        updateCacheParamsFromString(cacheConfig);
+    }
+
+    if (mDisconnectAtHighwatermark) {
+        // Makes no sense to disconnect and do keep-alives...
+        mKeepAliveIntervalUs = 0;
+    }
+
     mLooper->setName("NuCachedSource2");
     mLooper->registerHandler(mReflector);
     mLooper->start();
@@ -318,7 +342,8 @@
     bool keepAlive =
         !mFetching
             && mFinalStatus == OK
-            && ALooper::GetNowUs() >= mLastFetchTimeUs + kKeepAliveIntervalUs;
+            && mKeepAliveIntervalUs > 0
+            && ALooper::GetNowUs() >= mLastFetchTimeUs + mKeepAliveIntervalUs;
 
     if (mFetching || keepAlive) {
         if (keepAlive) {
@@ -329,9 +354,15 @@
 
         mLastFetchTimeUs = ALooper::GetNowUs();
 
-        if (mFetching && mCache->totalSize() >= kHighWaterThreshold) {
+        if (mFetching && mCache->totalSize() >= mHighwaterThresholdBytes) {
             LOGI("Cache full, done prefetching for now");
             mFetching = false;
+
+            if (mDisconnectAtHighwatermark
+                    && (mSource->flags() & DataSource::kIsHTTPBasedSource)) {
+                LOGV("Disconnecting at high watermark");
+                static_cast<HTTPBase *>(mSource.get())->disconnect();
+            }
         }
     } else {
         Mutex::Autolock autoLock(mLock);
@@ -392,7 +423,7 @@
 
     if (!ignoreLowWaterThreshold && !force
             && mCacheOffset + mCache->totalSize() - mLastAccessPos
-                >= kLowWaterThreshold) {
+                >= mLowwaterThresholdBytes) {
         return;
     }
 
@@ -482,7 +513,7 @@
 }
 
 ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) {
-    CHECK_LE(size, (size_t)kHighWaterThreshold);
+    CHECK_LE(size, (size_t)mHighwaterThresholdBytes);
 
     LOGV("readInternal offset %lld size %d", offset, size);
 
@@ -580,4 +611,84 @@
     return mSource->getMIMEType();
 }
 
+void NuCachedSource2::updateCacheParamsFromSystemProperty() {
+    char value[PROPERTY_VALUE_MAX];
+    if (!property_get("media.stagefright.cache-params", value, NULL)) {
+        return;
+    }
+
+    updateCacheParamsFromString(value);
+}
+
+void NuCachedSource2::updateCacheParamsFromString(const char *s) {
+    ssize_t lowwaterMarkKb, highwaterMarkKb;
+    int keepAliveSecs;
+
+    if (sscanf(s, "%ld/%ld/%d",
+               &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) {
+        LOGE("Failed to parse cache parameters from '%s'.", s);
+        return;
+    }
+
+    if (lowwaterMarkKb >= 0) {
+        mLowwaterThresholdBytes = lowwaterMarkKb * 1024;
+    } else {
+        mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
+    }
+
+    if (highwaterMarkKb >= 0) {
+        mHighwaterThresholdBytes = highwaterMarkKb * 1024;
+    } else {
+        mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
+    }
+
+    if (mLowwaterThresholdBytes >= mHighwaterThresholdBytes) {
+        LOGE("Illegal low/highwater marks specified, reverting to defaults.");
+
+        mLowwaterThresholdBytes = kDefaultLowWaterThreshold;
+        mHighwaterThresholdBytes = kDefaultHighWaterThreshold;
+    }
+
+    if (keepAliveSecs >= 0) {
+        mKeepAliveIntervalUs = keepAliveSecs * 1000000ll;
+    } else {
+        mKeepAliveIntervalUs = kDefaultKeepAliveIntervalUs;
+    }
+
+    LOGV("lowwater = %d bytes, highwater = %d bytes, keepalive = %lld us",
+         mLowwaterThresholdBytes,
+         mHighwaterThresholdBytes,
+         mKeepAliveIntervalUs);
+}
+
+// static
+void NuCachedSource2::RemoveCacheSpecificHeaders(
+        KeyedVector<String8, String8> *headers,
+        String8 *cacheConfig,
+        bool *disconnectAtHighwatermark) {
+    *cacheConfig = String8();
+    *disconnectAtHighwatermark = false;
+
+    if (headers == NULL) {
+        return;
+    }
+
+    ssize_t index;
+    if ((index = headers->indexOfKey(String8("x-cache-config"))) >= 0) {
+        *cacheConfig = headers->valueAt(index);
+
+        headers->removeItemsAt(index);
+
+        LOGV("Using special cache config '%s'", cacheConfig->string());
+    }
+
+    if ((index = headers->indexOfKey(
+                    String8("x-disconnect-at-highwatermark"))) >= 0) {
+        *disconnectAtHighwatermark = true;
+        headers->removeItemsAt(index);
+
+        LOGV("Client requested disconnection at highwater mark");
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index dffaf67..86bd267 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2360,22 +2360,6 @@
                     formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) {
                     mOutputPortSettingsHaveChanged = true;
 
-                    if (mNativeWindow != NULL) {
-                        int32_t left, top, right, bottom;
-                        CHECK(mOutputFormat->findRect(
-                                    kKeyCropRect,
-                                    &left, &top, &right, &bottom));
-
-                        android_native_rect_t crop;
-                        crop.left = left;
-                        crop.top = top;
-                        crop.right = right + 1;
-                        crop.bottom = bottom + 1;
-
-                        // We'll ignore any errors here, if the surface is
-                        // already invalid, we'll know soon enough.
-                        native_window_set_crop(mNativeWindow.get(), &crop);
-                    }
                 } else if (data2 == OMX_IndexConfigCommonScale) {
                     OMX_CONFIG_SCALEFACTORTYPE scale;
                     InitOMXParams(&scale);
@@ -4192,6 +4176,24 @@
     return OK;
 }
 
+void OMXCodec::initNativeWindowCrop() {
+    int32_t left, top, right, bottom;
+
+    CHECK(mOutputFormat->findRect(
+                        kKeyCropRect,
+                        &left, &top, &right, &bottom));
+
+    android_native_rect_t crop;
+    crop.left = left;
+    crop.top = top;
+    crop.right = right + 1;
+    crop.bottom = bottom + 1;
+
+    // We'll ignore any errors here, if the surface is
+    // already invalid, we'll know soon enough.
+    native_window_set_crop(mNativeWindow.get(), &crop);
+}
+
 void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
     mOutputFormat = new MetaData;
     mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
@@ -4375,6 +4377,10 @@
                             video_def->nFrameWidth - 1,
                             video_def->nFrameHeight - 1);
                 }
+
+                if (mNativeWindow != NULL) {
+                     initNativeWindowCrop();
+                }
             }
             break;
         }
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 22b2855..7a03e7e 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -28,7 +28,10 @@
 struct PageCache;
 
 struct NuCachedSource2 : public DataSource {
-    NuCachedSource2(const sp<DataSource> &source);
+    NuCachedSource2(
+            const sp<DataSource> &source,
+            const char *cacheConfig = NULL,
+            bool disconnectAtHighwatermark = false);
 
     virtual status_t initCheck() const;
 
@@ -56,6 +59,11 @@
     status_t getEstimatedBandwidthKbps(int32_t *kbps);
     status_t setCacheStatCollectFreq(int32_t freqMs);
 
+    static void RemoveCacheSpecificHeaders(
+            KeyedVector<String8, String8> *headers,
+            String8 *cacheConfig,
+            bool *disconnectAtHighwatermark);
+
 protected:
     virtual ~NuCachedSource2();
 
@@ -63,13 +71,13 @@
     friend struct AHandlerReflector<NuCachedSource2>;
 
     enum {
-        kPageSize            = 65536,
-        kHighWaterThreshold  = 20 * 1024 * 1024,
-        kLowWaterThreshold   = 4 * 1024 * 1024,
+        kPageSize                       = 65536,
+        kDefaultHighWaterThreshold      = 20 * 1024 * 1024,
+        kDefaultLowWaterThreshold       = 4 * 1024 * 1024,
 
         // Read data after a 15 sec timeout whether we're actively
         // fetching or not.
-        kKeepAliveIntervalUs = 15000000,
+        kDefaultKeepAliveIntervalUs     = 15000000,
     };
 
     enum {
@@ -99,6 +107,14 @@
 
     int32_t mNumRetriesLeft;
 
+    size_t mHighwaterThresholdBytes;
+    size_t mLowwaterThresholdBytes;
+
+    // If the keep-alive interval is 0, keep-alives are disabled.
+    int64_t mKeepAliveIntervalUs;
+
+    bool mDisconnectAtHighwatermark;
+
     void onMessageReceived(const sp<AMessage> &msg);
     void onFetch();
     void onRead(const sp<AMessage> &msg);
@@ -112,6 +128,9 @@
     void restartPrefetcherIfNecessary_l(
             bool ignoreLowWaterThreshold = false, bool force = false);
 
+    void updateCacheParamsFromSystemProperty();
+    void updateCacheParamsFromString(const char *s);
+
     DISALLOW_EVIL_CONSTRUCTORS(NuCachedSource2);
 };
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index e13464e..72f1282 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -724,8 +724,10 @@
         const uint8_t *data, size_t size) {
     LOGV("onPayloadData mStreamType=0x%02x", mStreamType);
 
-    CHECK(PTS_DTS_flags == 2 || PTS_DTS_flags == 3);
-    int64_t timeUs = mProgram->convertPTSToTimestamp(PTS);
+    int64_t timeUs = 0ll;  // no presentation timestamp available.
+    if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+        timeUs = mProgram->convertPTSToTimestamp(PTS);
+    }
 
     status_t err = mQueue->appendData(data, size, timeUs);
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 1045e09..b9a4826 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -444,6 +444,10 @@
         }
     }
 
+    if (timeUs == 0ll) {
+        LOGV("Returning 0 timestamp");
+    }
+
     return timeUs;
 }
 
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index a9b539b..dc6c011 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -947,7 +947,12 @@
 
     if (mSendObjectFileSize - initialData > 0) {
         mfr.offset = initialData;
-        mfr.length = mSendObjectFileSize - initialData;
+        if (mSendObjectFileSize == 0xFFFFFFFF) {
+            // tell driver to read until it receives a short packet
+            mfr.length = 0xFFFFFFFF;
+        } else {
+            mfr.length = mSendObjectFileSize - initialData;
+        }
 
         LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
         // transfer the file
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 01f5a6f..ab49f93 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -5550,7 +5550,7 @@
 
     // remove chain first. This is useful only if reconfiguring effect chain on same output thread,
     // so that a new chain is created with correct parameters when first effect is added. This is
-    // otherwise unecessary as removeEffect_l() will remove the chain when last effect is
+    // otherwise unnecessary as removeEffect_l() will remove the chain when last effect is
     // removed.
     srcThread->removeEffectChain_l(chain);
 
@@ -5563,6 +5563,11 @@
     while (effect != 0) {
         srcThread->removeEffect_l(effect);
         dstThread->addEffect_l(effect);
+        // removeEffect_l() has stopped the effect if it was active so it must be restarted
+        if (effect->state() == EffectModule::ACTIVE ||
+                effect->state() == EffectModule::STOPPING) {
+            effect->start();
+        }
         // if the move request is not received from audio policy manager, the effect must be
         // re-registered with the new strategy and output
         if (dstChain == 0) {
@@ -6350,6 +6355,12 @@
     return status;
 }
 
+status_t AudioFlinger::EffectModule::start()
+{
+    Mutex::Autolock _l(mLock);
+    return start_l();
+}
+
 status_t AudioFlinger::EffectModule::start_l()
 {
     if (mEffectInterface == NULL) {
@@ -7214,7 +7225,10 @@
             // calling stop here will remove pre-processing effect from the audio HAL.
             // This is safe as we hold the EffectChain mutex which guarantees that we are not in
             // the middle of a read from audio HAL
-            mEffects[i]->stop();
+            if (mEffects[i]->state() == EffectModule::ACTIVE ||
+                    mEffects[i]->state() == EffectModule::STOPPING) {
+                mEffects[i]->stop();
+            }
             if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
                 delete[] effect->inBuffer();
             } else {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2e05593..ed9d81e 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1117,6 +1117,7 @@
         status_t         setDevice(uint32_t device);
         status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
         status_t         setMode(uint32_t mode);
+        status_t         start();
         status_t         stop();
         void             setSuspended(bool suspended);
         bool             suspended();
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
index 31544b3..c3ced4c 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -80,24 +80,33 @@
 
 class CameraHardwareInterface : public virtual RefBase {
 public:
-    CameraHardwareInterface(hw_module_t *module, const char *name)
+    CameraHardwareInterface(const char *name)
     {
         mDevice = 0;
         mName = name;
-        LOGI("Opening camera %s, this %p", name, this);
-        int rc = module->methods->open(module, name,
-                                       (hw_device_t **)&mDevice);
-        if (rc != OK)
-            LOGE("Could not open camera %s: %d", name, rc);
-        initHalPreviewWindow();
     }
 
     ~CameraHardwareInterface()
     {
         LOGI("Destroying camera %s", mName.string());
-        int rc = mDevice->common.close(&mDevice->common);
-        if (rc != OK)
-            LOGE("Could not close camera %s: %d", mName.string(), rc);
+        if(mDevice) {
+            int rc = mDevice->common.close(&mDevice->common);
+            if (rc != OK)
+                LOGE("Could not close camera %s: %d", mName.string(), rc);
+        }
+    }
+
+    status_t initialize(hw_module_t *module)
+    {
+        LOGI("Opening camera %s", mName.string());
+        int rc = module->methods->open(module, mName.string(),
+                                       (hw_device_t **)&mDevice);
+        if (rc != OK) {
+            LOGE("Could not open camera %s: %d", mName.string(), rc);
+            return rc;
+        }
+        initHalPreviewWindow();
+        return rc;
     }
 
     /** Set the ANativeWindow to which preview frames are sent */
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b178fd9..f306e4a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -133,6 +133,8 @@
 sp<ICamera> CameraService::connect(
         const sp<ICameraClient>& cameraClient, int cameraId) {
     int callingPid = getCallingPid();
+    sp<CameraHardwareInterface> hardware = NULL;
+
     LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
 
     if (!mModule) {
@@ -187,10 +189,13 @@
     char camera_device_name[10];
     snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
 
-    client = new Client(this, cameraClient,
-                new CameraHardwareInterface(&mModule->common,
-                                            camera_device_name),
-                cameraId, info.facing, callingPid);
+    hardware = new CameraHardwareInterface(camera_device_name);
+    if (hardware->initialize(&mModule->common) != OK) {
+        hardware.clear();
+        return NULL;
+    }
+
+    client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
     mClient[cameraId] = client;
     LOG1("CameraService::connect X");
     return client;
@@ -278,9 +283,20 @@
 // media players.
 
 static MediaPlayer* newMediaPlayer(const char *file) {
+    // Read the system property to determine if we have need to use the
+    // AUDIO_STREAM_ENFORCED_AUDIBLE type.
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.camera.sound.forced", value, "0");
+    int audioStreamType;
+    if (strcmp(value, "0") != 0) {
+        audioStreamType = AUDIO_STREAM_ENFORCED_AUDIBLE;
+    } else {
+        audioStreamType = AUDIO_STREAM_MUSIC;
+    }
+
     MediaPlayer* mp = new MediaPlayer();
     if (mp->setDataSource(file, NULL) == NO_ERROR) {
-        mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
+        mp->setAudioStreamType(audioStreamType);
         mp->prepare();
     } else {
         LOGE("Failed to load CameraService sounds: %s", file);
@@ -849,16 +865,16 @@
     if (result != NO_ERROR) return result;
 
     if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
-        // The orientation cannot be set during preview.
-        if (mHardware->previewEnabled()) {
-            return INVALID_OPERATION;
-        }
         // Mirror the preview if the camera is front-facing.
         orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
         if (orientation == -1) return BAD_VALUE;
 
         if (mOrientation != orientation) {
             mOrientation = orientation;
+            if (mPreviewWindow != 0) {
+                native_window_set_buffers_transform(mPreviewWindow.get(),
+                        mOrientation);
+            }
         }
         return OK;
     } else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {