Bug 1213517 - Consider competing constraints in getUserMedia+applyConstraints. draft
authorJan-Ivar Bruaroey <jib@mozilla.com>
Mon, 06 Jun 2016 13:15:50 -0400
changeset 388772 188b810e8d5c40e787dfde2326530780ae948e7e
parent 388771 ef006cf5f14530bc12cda2d59182539607f9cbe1
child 388773 4394fe7cd5eab13510526812f7d6edde014ab33f
push id23232
push userjbruaroey@mozilla.com
push dateSun, 17 Jul 2016 21:00:46 +0000
bugs1213517
milestone50.0a1
Bug 1213517 - Consider competing constraints in getUserMedia+applyConstraints. MozReview-Commit-ID: 9jzjNrJVUMX
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -108,45 +108,61 @@ MediaEngineRemoteVideoSource::Allocate(
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
 
   if (!mInitDone) {
     LOG(("Init not done"));
     return NS_ERROR_FAILURE;
   }
 
+  AutoTArray<const NormalizedConstraints*, 10> allConstraints;
+  for (auto& registered : mRegisteredHandles) {
+    allConstraints.AppendElement(&registered->mConstraints);
+  }
   RefPtr<AllocationHandle> handle = new AllocationHandle(aConstraints);
-  mRegisteredHandles.AppendElement(handle);
+  allConstraints.AppendElement(&handle->mConstraints);
+
+  NormalizedConstraints netConstraints(allConstraints);
+  if (netConstraints.mOverconstrained) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!ChooseCapability(netConstraints, aPrefs, aDeviceId)) {
+    return NS_ERROR_FAILURE;
+  }
 
   if (mState == kReleased) {
-    // Note: if shared, we don't allow a later opener to affect the resolution.
-    // (This may change depending on spec changes for Constraints/settings)
-
-    if (!ChooseCapability(handle->mConstraints, aPrefs, aDeviceId)) {
-      return NS_ERROR_UNEXPECTED;
-    }
-
     if (mozilla::camera::GetChildAndCall(
       &mozilla::camera::CamerasChild::AllocateCaptureDevice,
       mCapEngine, GetUUID().get(), kMaxUniqueIdLength, mCaptureIndex, aOrigin)) {
       return NS_ERROR_FAILURE;
     }
     mState = kAllocated;
     LOG(("Video device %d allocated for %s", mCaptureIndex,
          PromiseFlatCString(aOrigin).get()));
-  } else if (MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
-    MonitorAutoLock lock(mMonitor);
-    if (mSources.IsEmpty()) {
-      MOZ_ASSERT(mPrincipalHandles.IsEmpty());
-      LOG(("Video device %d reallocated", mCaptureIndex));
-    } else {
-      LOG(("Video device %d allocated shared", mCaptureIndex));
+  } else {
+    camera::GetChildAndCall(&camera::CamerasChild::StopCapture, mCapEngine,
+                            mCaptureIndex);
+    if (camera::GetChildAndCall(&camera::CamerasChild::StartCapture, mCapEngine,
+                                mCaptureIndex, mCapability, this)) {
+      LOG(("StartCapture failed"));
+      return NS_ERROR_FAILURE;
+    }
+    if (MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
+      MonitorAutoLock lock(mMonitor);
+      if (mSources.IsEmpty()) {
+        MOZ_ASSERT(mPrincipalHandles.IsEmpty());
+        LOG(("Video device %d reallocated", mCaptureIndex));
+      } else {
+        LOG(("Video device %d allocated shared", mCaptureIndex));
+      }
     }
   }
 
+  mRegisteredHandles.AppendElement(handle);
   ++mNrAllocations;
   handle.forget(aOutHandle);
   return NS_OK;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Deallocate(BaseAllocationHandle* aHandle)
 {
@@ -271,33 +287,50 @@ MediaEngineRemoteVideoSource::Restart(Ba
 {
   AssertIsOnOwningThread();
   if (!mInitDone) {
     LOG(("Init not done"));
     return NS_ERROR_FAILURE;
   }
   MOZ_ASSERT(aHandle);
   auto handle = static_cast<AllocationHandle*>(aHandle);
-  handle->mConstraints = NormalizedConstraints(aConstraints);
-  if (!ChooseCapability(handle->mConstraints, aPrefs, aDeviceId)) {
-    return NS_ERROR_NOT_AVAILABLE;
+  RefPtr<AllocationHandle> temp = new AllocationHandle(aConstraints);
+  temp->mConstraints = NormalizedConstraints(aConstraints);
+
+  AutoTArray<const NormalizedConstraints*, 10> allConstraints;
+  for (auto& registered : mRegisteredHandles) {
+    if (registered.get() == handle) {
+      continue; // Don't count old constraints
+    }
+    allConstraints.AppendElement(&registered->mConstraints);
+  }
+  allConstraints.AppendElement(&temp->mConstraints);
+
+  NormalizedConstraints netConstraints(allConstraints);
+  if (netConstraints.mOverconstrained) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!ChooseCapability(netConstraints, aPrefs, aDeviceId)) {
+    return NS_ERROR_FAILURE;
   }
   if (mState != kStarted) {
     return NS_OK;
   }
 
   mozilla::camera::GetChildAndCall(
     &mozilla::camera::CamerasChild::StopCapture,
     mCapEngine, mCaptureIndex);
   if (mozilla::camera::GetChildAndCall(
     &mozilla::camera::CamerasChild::StartCapture,
     mCapEngine, mCaptureIndex, mCapability, this)) {
     LOG(("StartCapture failed"));
     return NS_ERROR_FAILURE;
   }
+  handle->mConstraints = temp->mConstraints;
   return NS_OK;
 }
 
 void
 MediaEngineRemoteVideoSource::NotifyPull(MediaStreamGraph* aGraph,
                                          SourceMediaStream* aSource,
                                          TrackID aID, StreamTime aDesiredTime,
                                          const PrincipalHandle& aPrincipalHandle)