Merge "audio policy: fix relative priorities of PHONE and ENFORCED_AUDIBLE" into lmp-dev
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 5f566ca..3720085 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -1286,12 +1286,6 @@
     CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask));
     CHECK(msg->findInt32("resumeMask", (int32_t *)&resumeMask));
 
-    for (size_t i = 0; i < kMaxStreams; ++i) {
-        if (streamMask & indexToType(i)) {
-            CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri));
-        }
-    }
-
     int64_t timeUs;
     int32_t pickTrack;
     bool switching = false;
@@ -1307,7 +1301,20 @@
         mRealTimeBaseUs = ALooper::GetNowUs() - timeUs;
     }
 
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (streamMask & indexToType(i)) {
+            if (switching) {
+                CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mNewUri));
+            } else {
+                CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri));
+            }
+        }
+    }
+
     mNewStreamMask = streamMask | resumeMask;
+    if (switching) {
+        mSwapMask = mStreamMask & ~resumeMask;
+    }
 
     // Of all existing fetchers:
     // * Resume fetchers that are still needed and assign them original packet sources.
@@ -1357,7 +1364,7 @@
         }
 
         AString uri;
-        uri = mStreams[i].mUri;
+        uri = switching ? mStreams[i].mNewUri : mStreams[i].mUri;
 
         sp<PlaylistFetcher> fetcher = addFetcher(uri.c_str());
         CHECK(fetcher != NULL);
@@ -1370,7 +1377,8 @@
 
         // TRICKY: looping from i as earlier streams are already removed from streamMask
         for (size_t j = i; j < kMaxStreams; ++j) {
-            if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) {
+            const AString &streamUri = switching ? mStreams[j].mNewUri : mStreams[j].mUri;
+            if ((streamMask & indexToType(j)) && uri == streamUri) {
                 sources[j] = mPacketSources.valueFor(indexToType(j));
 
                 if (timeUs >= 0) {
@@ -1459,7 +1467,6 @@
     mReconfigurationInProgress = false;
     if (switching) {
         mSwitchInProgress = true;
-        mSwapMask = streamMask;
     } else {
         mStreamMask = mNewStreamMask;
     }
@@ -1478,6 +1485,15 @@
 
     int32_t stream;
     CHECK(msg->findInt32("stream", &stream));
+
+    ssize_t idx = typeToIndex(stream);
+    CHECK(idx >= 0);
+    if ((mNewStreamMask & stream) && mStreams[idx].mNewUri.empty()) {
+        ALOGW("swapping stream type %d %s to empty stream", stream, mStreams[idx].mUri.c_str());
+    }
+    mStreams[idx].mUri = mStreams[idx].mNewUri;
+    mStreams[idx].mNewUri.clear();
+
     mSwapMask &= ~stream;
     if (mSwapMask != 0) {
         return;
@@ -1489,6 +1505,15 @@
         StreamType extraStream = (StreamType) (extraStreams & ~(extraStreams - 1));
         swapPacketSource(extraStream);
         extraStreams &= ~extraStream;
+
+        idx = typeToIndex(extraStream);
+        CHECK(idx >= 0);
+        if (mStreams[idx].mNewUri.empty()) {
+            ALOGW("swapping extra stream type %d %s to empty stream",
+                    extraStream, mStreams[idx].mUri.c_str());
+        }
+        mStreams[idx].mUri = mStreams[idx].mNewUri;
+        mStreams[idx].mNewUri.clear();
     }
 
     tryToFinishBandwidthSwitch();
@@ -1569,6 +1594,28 @@
     mSwitchGeneration++;
     mSwitchInProgress = false;
     mSwapMask = 0;
+
+    for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
+        FetcherInfo& info = mFetcherInfos.editValueAt(i);
+        if (info.mToBeRemoved) {
+            info.mToBeRemoved = false;
+        }
+    }
+
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (!mStreams[i].mNewUri.empty()) {
+            ssize_t j = mFetcherInfos.indexOfKey(mStreams[i].mNewUri);
+            if (j < 0) {
+                mStreams[i].mNewUri.clear();
+                continue;
+            }
+
+            const FetcherInfo &info = mFetcherInfos.valueAt(j);
+            info.mFetcher->stopAsync();
+            mFetcherInfos.removeItemsAt(j);
+            mStreams[i].mNewUri.clear();
+        }
+    }
 }
 
 bool LiveSession::canSwitchBandwidthTo(size_t bandwidthIndex) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 26df543..6be86cf 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -126,7 +126,7 @@
 
     struct StreamItem {
         const char *mType;
-        AString mUri;
+        AString mUri, mNewUri;
         size_t mCurDiscontinuitySeq;
         int64_t mLastDequeuedTimeUs;
         int64_t mLastSampleDurationUs;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 6f4a507..10038c5 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -921,6 +921,13 @@
                         "stop preview: %s (%d)",
                         __FUNCTION__, mCameraId, strerror(-res), res);
             }
+            {
+                // Ideally we should recover the override after recording stopped, but
+                // right now recording stream will live until here, so we are forced to
+                // recover here. TODO: find a better way to handle that (b/17495165)
+                SharedParameters::Lock l(mParameters);
+                l.mParameters.recoverOverriddenJpegSize();
+            }
             // no break
         case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
             SharedParameters::Lock l(mParameters);
@@ -1075,34 +1082,65 @@
     // and we can't fail record start without stagefright asserting.
     params.previewCallbackFlags = 0;
 
-    res = updateProcessorStream<
-            StreamingProcessor,
-            &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
-                                                        params);
+    bool recordingStreamNeedsUpdate;
+    res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
     if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
-                __FUNCTION__, mCameraId, strerror(-res), res);
+        ALOGE("%s: Camera %d: Can't query recording stream",
+                __FUNCTION__, mCameraId);
         return res;
     }
 
+    if (recordingStreamNeedsUpdate) {
+        // Need to stop stream here in case updateRecordingStream fails
+        // Right now camera device cannot handle configureStream failure gracefully
+        // when device is streaming
+        res = mStreamingProcessor->stopStream();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't stop streaming to update record stream",
+                    __FUNCTION__, mCameraId);
+            return res;
+        }
+        res = mDevice->waitUntilDrained();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+        }
+        res = updateProcessorStream<
+                StreamingProcessor,
+                &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
+                                                            params);
+
+        // updateRecordingStream might trigger a configureStream call and device might fail
+        // configureStream due to jpeg size > video size. Try again with jpeg size overridden
+        // to video size.
+        // TODO: This may not be needed after we add stop streaming above. Remove that if
+        // it's the case.
+        if (res == BAD_VALUE) {
+            overrideVideoSnapshotSize(params);
+            res = updateProcessorStream<
+                    StreamingProcessor,
+                    &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
+                                                                params);
+        }
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
     Vector<int32_t> outputStreams;
     outputStreams.push(getPreviewStreamId());
     outputStreams.push(getRecordingStreamId());
 
     res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
             outputStreams);
-    // try to reconfigure jpeg to video size if configureStreams failed
-    if (res == BAD_VALUE) {
 
-        ALOGV("%s: Camera %d: configure still size to video size before recording"
-                , __FUNCTION__, mCameraId);
-        params.overrideJpegSizeByVideoSize();
-        res = updateProcessorStream(mJpegProcessor, params);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Can't configure still image size to video size: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
-            return res;
-        }
+    // startStream might trigger a configureStream call and device might fail
+    // configureStream due to jpeg size > video size. Try again with jpeg size overridden
+    // to video size.
+    if (res == BAD_VALUE) {
+        overrideVideoSnapshotSize(params);
         res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
                 outputStreams);
     }
@@ -1146,7 +1184,6 @@
 
     mCameraService->playSound(CameraService::SOUND_RECORDING);
 
-    l.mParameters.recoverOverriddenJpegSize();
     res = startPreviewL(l.mParameters, true);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to return to preview",
@@ -1923,6 +1960,18 @@
     return res;
 }
 
+status_t Camera2Client::overrideVideoSnapshotSize(Parameters &params) {
+    ALOGV("%s: Camera %d: configure still size to video size before recording"
+            , __FUNCTION__, mCameraId);
+    params.overrideJpegSizeByVideoSize();
+    status_t res = updateProcessorStream(mJpegProcessor, params);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Can't override video snapshot size to video size: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+    }
+    return res;
+}
+
 const char* Camera2Client::kAutofocusLabel = "autofocus";
 const char* Camera2Client::kTakepictureLabel = "take_picture";
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index f5c3a30..d68bb29 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -208,6 +208,9 @@
 
     // Wait until the camera device has received the latest control settings
     status_t syncWithDevice();
+
+    // Video snapshot jpeg size overriding helper function
+    status_t overrideVideoSnapshotSize(Parameters &params);
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 8d00590..ed9137f 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -76,9 +76,29 @@
     res = getFilteredSizes(MAX_VIDEO_SIZE, &availableVideoSizes);
     if (res != OK) return res;
 
-    // TODO: Pick more intelligently
-    previewWidth = availablePreviewSizes[0].width;
-    previewHeight = availablePreviewSizes[0].height;
+    // Select initial preview and video size that's under the initial bound and
+    // on the list of both preview and recording sizes
+    previewWidth = 0;
+    previewHeight = 0;
+    for (size_t i = 0 ; i < availablePreviewSizes.size(); i++) {
+        int newWidth = availablePreviewSizes[i].width;
+        int newHeight = availablePreviewSizes[i].height;
+        if (newWidth >= previewWidth && newHeight >= previewHeight &&
+                newWidth <= MAX_INITIAL_PREVIEW_WIDTH &&
+                newHeight <= MAX_INITIAL_PREVIEW_HEIGHT) {
+            for (size_t j = 0; j < availableVideoSizes.size(); j++) {
+                if (availableVideoSizes[j].width == newWidth &&
+                        availableVideoSizes[j].height == newHeight) {
+                    previewWidth = newWidth;
+                    previewHeight = newHeight;
+                }
+            }
+        }
+    }
+    if (previewWidth == 0) {
+        ALOGE("%s: No initial preview size can be found!", __FUNCTION__);
+        return BAD_VALUE;
+    }
     videoWidth = previewWidth;
     videoHeight = previewHeight;
 
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 5e6e6ab..815cc55 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -179,8 +179,13 @@
     // Number of zoom steps to simulate
     static const unsigned int NUM_ZOOM_STEPS = 100;
     // Max preview size allowed
+    // This is set to a 1:1 value to allow for any aspect ratio that has
+    // a max long side of 1920 pixels
     static const unsigned int MAX_PREVIEW_WIDTH = 1920;
-    static const unsigned int MAX_PREVIEW_HEIGHT = 1080;
+    static const unsigned int MAX_PREVIEW_HEIGHT = 1920;
+    // Initial max preview/recording size bound
+    static const int MAX_INITIAL_PREVIEW_WIDTH = 1920;
+    static const int MAX_INITIAL_PREVIEW_HEIGHT = 1080;
     // Aspect ratio tolerance
     static const float ASPECT_RATIO_TOLERANCE = 0.001;
 
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index ab0af0d..9e7fff8 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -318,6 +318,44 @@
     return OK;
 }
 
+status_t StreamingProcessor::recordingStreamNeedsUpdate(
+        const Parameters &params, bool *needsUpdate) {
+    status_t res;
+
+    if (needsUpdate == 0) {
+        ALOGE("%s: Camera %d: invalid argument", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+
+    if (mRecordingStreamId == NO_STREAM) {
+        *needsUpdate = true;
+        return OK;
+    }
+
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+
+    uint32_t currentWidth, currentHeight;
+    res = device->getStreamInfo(mRecordingStreamId,
+            &currentWidth, &currentHeight, 0);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Error querying recording output stream info: "
+                "%s (%d)", __FUNCTION__, mId,
+                strerror(-res), res);
+        return res;
+    }
+
+    if (mRecordingConsumer == 0 || currentWidth != (uint32_t)params.videoWidth ||
+            currentHeight != (uint32_t)params.videoHeight) {
+        *needsUpdate = true;
+    }
+    *needsUpdate = false;
+    return res;
+}
+
 status_t StreamingProcessor::updateRecordingStream(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index 833bb8f..8466af4 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -54,6 +54,9 @@
 
     status_t setRecordingBufferCount(size_t count);
     status_t updateRecordingRequest(const Parameters &params);
+    // If needsUpdate is set to true, a updateRecordingStream call with params will recreate
+    // recording stream
+    status_t recordingStreamNeedsUpdate(const Parameters &params, bool *needsUpdate);
     status_t updateRecordingStream(const Parameters &params);
     status_t deleteRecordingStream();
     int getRecordingStreamId() const;