Bug 1213517 - Let cam access in competing tabs get closer to their ideals when a tab closes. draft
authorJan-Ivar Bruaroey <jib@mozilla.com>
Sat, 18 Jun 2016 19:09:39 -0400
changeset 388780 4634d50dff3a843d148ae6e5e17b60c1b45bde94
parent 388779 6ee7e68738a84ac7335183188f4014148f2dbfee
child 388781 c85859b71a965bfdca8cf0f1de6853a8ba3ce03d
push id23232
push userjbruaroey@mozilla.com
push dateSun, 17 Jul 2016 21:00:46 +0000
bugs1213517
milestone50.0a1
Bug 1213517 - Let cam access in competing tabs get closer to their ideals when a tab closes. MozReview-Commit-ID: htWkYMm18U
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
dom/media/webrtc/MediaEngineRemoteVideoSource.h
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -27,17 +27,18 @@ using dom::ConstrainLongRange;
 
 NS_IMPL_ISUPPORTS0(MediaEngineRemoteVideoSource)
 
 MediaEngineRemoteVideoSource::MediaEngineRemoteVideoSource(
   int aIndex, mozilla::camera::CaptureEngine aCapEngine,
   dom::MediaSourceEnum aMediaSource, const char* aMonitorName)
   : MediaEngineCameraVideoSource(aIndex, aMonitorName),
     mMediaSource(aMediaSource),
-    mCapEngine(aCapEngine)
+    mCapEngine(aCapEngine),
+    mInShutdown(false)
 {
   MOZ_ASSERT(aMediaSource != dom::MediaSourceEnum::Other);
   Init();
 }
 
 void
 MediaEngineRemoteVideoSource::Init()
 {
@@ -63,16 +64,17 @@ MediaEngineRemoteVideoSource::Init()
 
 void
 MediaEngineRemoteVideoSource::Shutdown()
 {
   LOG((__PRETTY_FUNCTION__));
   if (!mInitDone) {
     return;
   }
+  mInShutdown = true;
   if (mState == kStarted) {
     SourceMediaStream *source;
     bool empty;
 
     while (1) {
       {
         MonitorAutoLock lock(mMonitor);
         empty = mSources.IsEmpty();
@@ -109,17 +111,18 @@ MediaEngineRemoteVideoSource::Allocate(
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
 
   if (!mInitDone) {
     LOG(("Init not done"));
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<AllocationHandle> handle = new AllocationHandle(aConstraints, aOrigin);
+  RefPtr<AllocationHandle> handle = new AllocationHandle(aConstraints, aOrigin,
+                                                         aPrefs, aDeviceId);
 
   nsresult rv = UpdateNew(handle, aPrefs, aDeviceId, aOutBadConstraint);
   if (NS_FAILED(rv)) {
     return rv;
   }
   if (mState == kStarted &&
       MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
     MonitorAutoLock lock(mMonitor);
@@ -153,26 +156,34 @@ MediaEngineRemoteVideoSource::Deallocate
   };
   MOZ_ASSERT(mRegisteredHandles.Contains(handle, Comparator()));
   mRegisteredHandles.RemoveElementAt(mRegisteredHandles.IndexOf(handle, 0,
                                                                 Comparator()));
   --mNrAllocations;
   MOZ_ASSERT(mNrAllocations >= 0, "Double-deallocations are prohibited");
 
   if (mNrAllocations == 0) {
+    MOZ_ASSERT(!mRegisteredHandles.Length());
     if (mState != kStopped && mState != kAllocated) {
       return NS_ERROR_FAILURE;
     }
     mozilla::camera::GetChildAndCall(
       &mozilla::camera::CamerasChild::ReleaseCaptureDevice,
       mCapEngine, mCaptureIndex);
     mState = kReleased;
     LOG(("Video device %d deallocated", mCaptureIndex));
   } else {
     LOG(("Video device %d deallocated but still in use", mCaptureIndex));
+    MOZ_ASSERT(mRegisteredHandles.Length());
+    if (!mInShutdown) {
+      // Whenever constraints are removed, other parties may get closer to ideal.
+      auto& first = mRegisteredHandles[0];
+      const char* badConstraint = nullptr;
+      return UpdateRemove(first->mPrefs, first->mDeviceId, &badConstraint);
+    }
   }
   return NS_OK;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Start(SourceMediaStream* aStream, TrackID aID,
                                     const PrincipalHandle& aPrincipalHandle)
 {
@@ -330,20 +341,20 @@ MediaEngineRemoteVideoSource::UpdateExis
                                     this)) {
           LOG(("StartCapture failed"));
           return NS_ERROR_FAILURE;
         }
         mLastCapability = mCapability;
       }
       break;
 
-      default:
-        LOG(("Video device %d %s in ignored state %d", mCaptureIndex,
+    default:
+      LOG(("Video device %d %s in ignored state %d", mCaptureIndex,
              (aHandle? aHandle->mOrigin.get() : ""), mState));
-        break;
+      break;
   }
   if (aHandle && aNewConstraints) {
     aHandle->mConstraints = *aNewConstraints;
   }
   return NS_OK;
 }
 
 void
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -70,23 +70,30 @@ public:
   MediaEngineRemoteVideoSource(int aIndex, mozilla::camera::CaptureEngine aCapEngine,
                                dom::MediaSourceEnum aMediaSource,
                                const char* aMonitorName = "RemoteVideo.Monitor");
 
   class AllocationHandle : public BaseAllocationHandle
   {
   public:
     AllocationHandle(const dom::MediaTrackConstraints& aConstraints,
-                     const nsACString& aOrigin)
-      : mConstraints(aConstraints), mOrigin(aOrigin) {}
+                     const nsACString& aOrigin,
+                     const MediaEnginePrefs& aPrefs,
+                     const nsString& aDeviceId)
+    : mConstraints(aConstraints),
+      mOrigin(aOrigin),
+      mPrefs(aPrefs),
+      mDeviceId(aDeviceId) {}
   private:
     ~AllocationHandle() override {}
   public:
     NormalizedConstraints mConstraints;
     nsCString mOrigin;
+    MediaEnginePrefs mPrefs;
+    nsString mDeviceId;
   };
 
   nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
                     const MediaEnginePrefs& aPrefs,
                     const nsString& aDeviceId,
                     const nsACString& aOrigin,
                     BaseAllocationHandle** aOutHandle,
                     const char** aOutBadConstraint) override;
@@ -144,20 +151,28 @@ private:
   nsresult
   UpdateNew(AllocationHandle* aHandle,
             const MediaEnginePrefs& aPrefs,
             const nsString& aDeviceId,
             const char** aOutBadConstraint) {
     return UpdateExisting(aHandle, nullptr, aPrefs, aDeviceId, aOutBadConstraint);
   }
 
+  nsresult
+  UpdateRemove(const MediaEnginePrefs& aPrefs,
+               const nsString& aDeviceId,
+               const char** aOutBadConstraint) {
+    return UpdateExisting(nullptr, nullptr, aPrefs, aDeviceId, aOutBadConstraint);
+  }
+
   dom::MediaSourceEnum mMediaSource; // source of media (camera | application | screen)
   mozilla::camera::CaptureEngine mCapEngine;
 
   nsTArray<RefPtr<AllocationHandle>> mRegisteredHandles;
 
   // To only restart camera when needed, we keep track previous settings.
   webrtc::CaptureCapability mLastCapability;
+  bool mInShutdown;
 };
 
 }
 
 #endif /* MEDIAENGINE_REMOTE_VIDEO_SOURCE_H_ */