Merge "Support querying active record sources" into jb-mr1-dev
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index d856bac..8ab9abe 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -36,6 +36,8 @@
 #include <arpa/inet.h>
 #include <cutils/properties.h>
 
+#include <ctype.h>
+
 namespace android {
 
 WifiDisplaySource::WifiDisplaySource(
@@ -46,6 +48,7 @@
       mClient(client),
       mSessionID(0),
       mStopReplyID(0),
+      mChosenRTPPort(-1),
       mUsingPCMAudio(false),
       mClientSessionID(0),
       mReaperPending(false),
@@ -532,11 +535,6 @@
         transportString = "TCP";
     }
 
-    if (property_get("media.wfd.use-pcm-audio", val, NULL)
-            && (!strcasecmp("true", val) || !strcmp("1", val))) {
-        ALOGI("Using PCM audio.");
-        mUsingPCMAudio = true;
-    }
     // For 720p60:
     //   use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n"
     // For 720p30:
@@ -548,11 +546,11 @@
         "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
         "wfd_audio_codecs: %s\r\n"
         "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n"
-        "wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n",
+        "wfd_client_rtp_ports: RTP/AVP/%s;unicast %d 0 mode=play\r\n",
         (mUsingPCMAudio
             ? "LPCM 00000002 00" // 2 ch PCM 48kHz
             : "AAC 00000001 00"),  // 2 ch AAC 48kHz
-        mClientInfo.mLocalIP.c_str(), transportString.c_str());
+        mClientInfo.mLocalIP.c_str(), transportString.c_str(), mChosenRTPPort);
 
     AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
     AppendCommonResponse(&request, mNextCSeq);
@@ -649,6 +647,36 @@
     return OK;
 }
 
+// sink_audio_list := ("LPCM"|"AAC"|"AC3" HEXDIGIT*8 HEXDIGIT*2)
+//                       (", " sink_audio_list)*
+static void GetAudioModes(const char *s, const char *prefix, uint32_t *modes) {
+    *modes = 0;
+
+    size_t prefixLen = strlen(prefix);
+
+    while (*s != '0') {
+        if (!strncmp(s, prefix, prefixLen) && s[prefixLen] == ' ') {
+            unsigned latency;
+            if (sscanf(&s[prefixLen + 1], "%08x %02x", modes, &latency) != 2) {
+                *modes = 0;
+            }
+
+            return;
+        }
+
+        char *commaPos = strchr(s, ',');
+        if (commaPos != NULL) {
+            s = commaPos + 1;
+
+            while (isspace(*s)) {
+                ++s;
+            }
+        } else {
+            break;
+        }
+    }
+}
+
 status_t WifiDisplaySource::onReceiveM3Response(
         int32_t sessionID, const sp<ParsedMessage> &msg) {
     int32_t statusCode;
@@ -667,8 +695,63 @@
         return ERROR_MALFORMED;
     }
 
-#if REQUIRE_HDCP
     AString value;
+    if (!params->findParameter("wfd_client_rtp_ports", &value)) {
+        ALOGE("Sink doesn't report its choice of wfd_client_rtp_ports.");
+        return ERROR_MALFORMED;
+    }
+
+    unsigned port0, port1;
+    if (sscanf(value.c_str(),
+               "RTP/AVP/UDP;unicast %u %u mode=play",
+               &port0,
+               &port1) != 2
+        || port0 == 0 || port0 > 65535 || port1 != 0) {
+        ALOGE("Sink chose its wfd_client_rtp_ports poorly (%s)",
+              value.c_str());
+
+        return ERROR_MALFORMED;
+    }
+
+    mChosenRTPPort = port0;
+
+    if (!params->findParameter("wfd_audio_codecs", &value)) {
+        ALOGE("Sink doesn't report its choice of wfd_audio_codecs.");
+        return ERROR_MALFORMED;
+    }
+
+    if  (value == "none") {
+        ALOGE("Sink doesn't support audio at all.");
+        return ERROR_UNSUPPORTED;
+    }
+
+    uint32_t modes;
+    GetAudioModes(value.c_str(), "AAC", &modes);
+
+    bool supportsAAC = (modes & 1) != 0;  // AAC 2ch 48kHz
+
+    GetAudioModes(value.c_str(), "LPCM", &modes);
+
+    bool supportsPCM = (modes & 2) != 0;  // LPCM 2ch 48kHz
+
+    char val[PROPERTY_VALUE_MAX];
+    if (supportsPCM
+            && property_get("media.wfd.use-pcm-audio", val, NULL)
+            && (!strcasecmp("true", val) || !strcmp("1", val))) {
+        ALOGI("Using PCM audio.");
+        mUsingPCMAudio = true;
+    } else if (supportsAAC) {
+        ALOGI("Using AAC audio.");
+        mUsingPCMAudio = false;
+    } else if (supportsPCM) {
+        ALOGI("Using PCM audio.");
+        mUsingPCMAudio = true;
+    } else {
+        ALOGI("Sink doesn't support an audio format we do.");
+        return ERROR_UNSUPPORTED;
+    }
+
+#if REQUIRE_HDCP
     if (!params->findParameter("wfd_content_protection", &value)) {
         ALOGE("Sink doesn't appear to support content protection.");
         return -EACCES;
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 0692cde..9e748dd 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -114,6 +114,8 @@
 
     uint32_t mStopReplyID;
 
+    int32_t mChosenRTPPort;  // extracted from "wfd_client_rtp_ports"
+
     bool mUsingPCMAudio;
     int32_t mClientSessionID;
 
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 7a6e344..0ab4e8c 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -65,10 +65,10 @@
 
 status_t Camera2Client::checkPid(const char* checkLocation) const {
     int callingPid = getCallingPid();
-    if (callingPid == mClientPid || callingPid == mServicePid) return NO_ERROR;
+    if (callingPid == mClientPid) return NO_ERROR;
 
     ALOGE("%s: attempt to use a locked camera from a different process"
-            " (old pid %d, new pid %d, servicePid %d)", checkLocation, mClientPid, callingPid, mServicePid);
+            " (old pid %d, new pid %d)", checkLocation, mClientPid, callingPid);
     return PERMISSION_DENIED;
 }
 
@@ -139,19 +139,7 @@
 
     mDestructionStarted = true;
 
-    Parameters::State state;
-    // warning:
-    //   holding on to locks more than necessary may be hazardous to your health
-    {
-        SharedParameters::Lock l(mParameters);
-        state = l.mParameters.state;
-    }
-
-    if (state != Parameters::DISCONNECTED) {
-        // Rewrite mClientPid to allow shutdown by CameraService
-        mClientPid = getCallingPid();
-        disconnect();
-    }
+    disconnect();
 
     ALOGI("Camera %d: Closed", mCameraId);
 }
@@ -372,7 +360,10 @@
     ATRACE_CALL();
     Mutex::Autolock icl(mICameraLock);
     status_t res;
-    if ( (res = checkPid(__FUNCTION__) ) != OK) return;
+
+    // Allow both client and the media server to disconnect at all times
+    int callingPid = getCallingPid();
+    if (callingPid != mClientPid && callingPid != mServicePid) return;
 
     if (mDevice == 0) return;
 
@@ -382,6 +373,7 @@
 
     {
         SharedParameters::Lock l(mParameters);
+        if (l.mParameters.state == Parameters::DISCONNECTED) return;
         l.mParameters.state = Parameters::DISCONNECTED;
     }
 
@@ -462,9 +454,13 @@
     ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
             __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
 
-    // TODO: Check for uninterruptable conditions
-
     if (mClientPid == getCallingPid()) {
+        SharedParameters::Lock l(mParameters);
+        if (l.mParameters.state == Parameters::RECORD ||
+                l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
+            ALOGD("Not allowed to unlock camera during recording.");
+            return INVALID_OPERATION;
+        }
         mClientPid = 0;
         mCameraClient.clear();
         mSharedCameraClient.clear();
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp
index 5b59ef9..b930c02 100644
--- a/services/camera/libcameraservice/CameraClient.cpp
+++ b/services/camera/libcameraservice/CameraClient.cpp
@@ -73,6 +73,7 @@
     if (res != OK) {
         ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
+        mHardware.clear();
         return NO_INIT;
     }
 
@@ -101,8 +102,6 @@
     int callingPid = getCallingPid();
     LOG1("CameraClient::~CameraClient E (pid %d, this %p)", callingPid, this);
 
-    // set mClientPid to let disconnet() tear down the hardware
-    mClientPid = callingPid;
     disconnect();
     LOG1("CameraClient::~CameraClient X (pid %d, this %p)", callingPid, this);
 }
@@ -124,7 +123,7 @@
 
 status_t CameraClient::checkPid() const {
     int callingPid = getCallingPid();
-    if (callingPid == mClientPid || callingPid == mServicePid) return NO_ERROR;
+    if (callingPid == mClientPid) return NO_ERROR;
 
     ALOGW("attempt to use a locked camera from a different process"
          " (old pid %d, new pid %d)", mClientPid, callingPid);
@@ -218,7 +217,8 @@
     LOG1("disconnect E (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
-    if (checkPid() != NO_ERROR) {
+    // Allow both client and the media server to disconnect at all times
+    if (callingPid != mClientPid && callingPid != mServicePid) {
         ALOGW("different client - don't disconnect");
         return;
     }
diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp
index 05494d3..3c679da 100644
--- a/services/camera/libcameraservice/camera2/Parameters.cpp
+++ b/services/camera/libcameraservice/camera2/Parameters.cpp
@@ -1739,9 +1739,6 @@
             reqMeteringAreas, reqMeteringAreasSize);
     if (res != OK) return res;
 
-    res = request->update(ANDROID_CONTROL_AWB_REGIONS,
-            reqMeteringAreas, reqMeteringAreasSize);
-    if (res != OK) return res;
     delete[] reqMeteringAreas;
 
     /* don't include jpeg thumbnail size - it's valid for