Bug 1434538 - Allocate per-allocation members in Allocate(). r?jib draft
authorAndreas Pehrson <pehrsons@mozilla.com>
Fri, 09 Feb 2018 11:17:30 +0100
changeset 753091 ac87ee3e5e511658632a50ff7d43b58ad5d1ba76
parent 752986 3e153e241838648dca9c219a3f9b0d780e9c7545
push id98481
push userbmo:apehrson@mozilla.com
push dateFri, 09 Feb 2018 16:37:51 +0000
reviewersjib
bugs1434538
milestone59.0
Bug 1434538 - Allocate per-allocation members in Allocate(). r?jib This removes the assumption that a Start() call always follows an Allocate() call for the same allocation. We still assume that Start() calls come in the same order as Allocate() calls, and that all Allocate() calls eventually get a Start() call. This is fine, as all the paths causing Start() to not happen are related to shutdown. What we have to be careful with now is a call to Deallocate() where Stop() didn't happen (because Start() didn't happen). There is probably no issue in not cleaning up the arrays there, but we do just to stay sane. MozReview-Commit-ID: KmfTbZaT5bA
dom/media/webrtc/MediaEngineCameraVideoSource.h
dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -148,17 +148,16 @@ protected:
 
   int mWidth, mHeight;
   bool mInitDone;
   int mCaptureIndex;
   TrackID mTrackID;
 
   webrtc::CaptureCapability mCapability;
   webrtc::CaptureCapability mTargetCapability;
-  uint64_t mHandleId;
 
   mutable nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities;
 private:
   nsString mDeviceName;
   nsCString mUniqueId;
   nsString mFacingMode;
 };
 
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -87,17 +87,19 @@ MediaEngineRemoteVideoSource::Shutdown()
           MOZ_ASSERT(mPrincipalHandles.IsEmpty());
           MOZ_ASSERT(mTargetCapabilities.IsEmpty());
           MOZ_ASSERT(mHandleIds.IsEmpty());
           MOZ_ASSERT(mImages.IsEmpty());
           break;
         }
         source = mSources[0];
       }
-      Stop(source, kVideoTrack); // XXX change to support multiple tracks
+      if (source) {
+        Stop(source, kVideoTrack); // XXX change to support multiple tracks
+      }
     }
     MOZ_ASSERT(mState == kStopped);
   }
 
   for (auto& registered : mRegisteredHandles) {
     MOZ_ASSERT(mState == kAllocated || mState == kStopped);
     Deallocate(registered.get());
   }
@@ -137,16 +139,30 @@ MediaEngineRemoteVideoSource::Allocate(
       MOZ_ASSERT(mTargetCapabilities.IsEmpty());
       MOZ_ASSERT(mHandleIds.IsEmpty());
       MOZ_ASSERT(mImages.IsEmpty());
       LOG(("Video device %d reallocated", mCaptureIndex));
     } else {
       LOG(("Video device %d allocated shared", mCaptureIndex));
     }
   }
+
+  // Pre-allocate per-allocation members.
+  MonitorAutoLock lock(mMonitor);
+  MOZ_DIAGNOSTIC_ASSERT(*aOutHandle);
+  mSources.AppendElement();
+  mPrincipalHandles.AppendElement(PRINCIPAL_HANDLE_NONE);
+  mTargetCapabilities.AppendElement(mTargetCapability);
+  mHandleIds.AppendElement((*aOutHandle)->mId); // Key
+  mImages.AppendElement();
+
+  MOZ_DIAGNOSTIC_ASSERT(mSources.Length() == mPrincipalHandles.Length());
+  MOZ_DIAGNOSTIC_ASSERT(mSources.Length() == mTargetCapabilities.Length());
+  MOZ_DIAGNOSTIC_ASSERT(mSources.Length() == mHandleIds.Length());
+  MOZ_DIAGNOSTIC_ASSERT(mSources.Length() == mImages.Length());
   return NS_OK;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Deallocate(AllocationHandle* aHandle)
 {
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
@@ -160,16 +176,38 @@ MediaEngineRemoteVideoSource::Deallocate
     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_DIAGNOSTIC_ASSERT(aHandle);
+  size_t i = mHandleIds.IndexOf(aHandle->mId);
+  if (i == mHandleIds.NoIndex) {
+    // Cleaned up by Stop() - this is allowed
+    return NS_OK;
+  }
+
+  MOZ_DIAGNOSTIC_ASSERT(!mSources[i],
+                        "A handle id remaining at Deallocate() must not have "
+                        "gotten the source assigned by Start(). "
+                        "It would have been cleaned up by Stop().");
+  MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
+  MOZ_ASSERT(mSources.Length() == mTargetCapabilities.Length());
+  MOZ_ASSERT(mSources.Length() == mHandleIds.Length());
+  MOZ_ASSERT(mSources.Length() == mImages.Length());
+  mSources.RemoveElementAt(i);
+  mPrincipalHandles.RemoveElementAt(i);
+  mTargetCapabilities.RemoveElementAt(i);
+  mHandleIds.RemoveElementAt(i);
+  mImages.RemoveElementAt(i);
+
   return NS_OK;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Start(SourceMediaStream* aStream, TrackID aID,
                                     const PrincipalHandle& aPrincipalHandle)
 {
   LOG((__PRETTY_FUNCTION__));
@@ -179,23 +217,28 @@ MediaEngineRemoteVideoSource::Start(Sour
     return NS_ERROR_FAILURE;
   }
 
   if (!mImageContainer) {
     mImageContainer =
       layers::LayerManager::CreateImageContainer(layers::ImageContainer::ASYNCHRONOUS);
   }
 
+  // This is an assumption that this Start() belongs to the first source that
+  // has not yet been assigned.
+  size_t index = mSources.IndexOf(nullptr);
+  if (index == mSources.NoIndex) {
+    MOZ_DIAGNOSTIC_ASSERT(false, "No allocation has happened for this source");
+    return NS_ERROR_FAILURE;
+  }
+
   {
     MonitorAutoLock lock(mMonitor);
-    mSources.AppendElement(aStream);
-    mPrincipalHandles.AppendElement(aPrincipalHandle);
-    mTargetCapabilities.AppendElement(mTargetCapability);
-    mHandleIds.AppendElement(mHandleId);
-    mImages.AppendElement(nullptr);
+    mSources[index] = aStream;
+    mPrincipalHandles[index] = aPrincipalHandle;
 
     MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
     MOZ_ASSERT(mSources.Length() == mTargetCapabilities.Length());
     MOZ_ASSERT(mSources.Length() == mHandleIds.Length());
     MOZ_ASSERT(mSources.Length() == mImages.Length());
   }
 
   aStream->AddTrack(aID, 0, new VideoSegment(), SourceMediaStream::ADDTRACK_QUEUED);
@@ -218,16 +261,17 @@ MediaEngineRemoteVideoSource::Start(Sour
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource,
                                    mozilla::TrackID aID)
 {
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
+  MOZ_DIAGNOSTIC_ASSERT(aSource);
   {
     MonitorAutoLock lock(mMonitor);
 
     // Drop any cached image so we don't start with a stale image on next
     // usage.  Also, gfx gets very upset if these are held until this object
     // is gc'd in final-cc during shutdown (bug 1374164)
     mImage = nullptr;
     // we drop mImageContainer only in MediaEngineCaptureVideoSource::Shutdown()
@@ -292,17 +336,16 @@ MediaEngineRemoteVideoSource::UpdateSing
     const NormalizedConstraints& aNewConstraint,
     const MediaEnginePrefs& aPrefs,
     const nsString& aDeviceId,
     const char** aOutBadConstraint)
 {
   switch (mState) {
     case kReleased:
       MOZ_ASSERT(aHandle);
-      mHandleId = aHandle->mId;
       LOG(("ChooseCapability(kFitness) for mTargetCapability and mCapability ++"));
       if (!ChooseCapability(aNetConstraints, aPrefs, aDeviceId, mCapability, kFitness)) {
         *aOutBadConstraint = FindBadConstraint(aNetConstraints, *this, aDeviceId);
         return NS_ERROR_FAILURE;
       }
       LOG(("ChooseCapability(kFitness) for mTargetCapability and mCapability --"));
       mTargetCapability = mCapability;
 
@@ -317,18 +360,17 @@ MediaEngineRemoteVideoSource::UpdateSing
       LOG(("Video device %d allocated", mCaptureIndex));
       break;
 
     case kAllocated:
     case kStarted:
       {
         size_t index = mHandleIds.NoIndex;
         if (aHandle) {
-          mHandleId = aHandle->mId;
-          index = mHandleIds.IndexOf(mHandleId);
+          index = mHandleIds.IndexOf(aHandle->mId);
         }
 
         LOG(("ChooseCapability(kFitness) for mTargetCapability ++"));
         if (!ChooseCapability(aNewConstraint, aPrefs, aDeviceId, mTargetCapability,
                               kFitness)) {
           *aOutBadConstraint = FindBadConstraint(aNewConstraint, *this, aDeviceId);
           return NS_ERROR_FAILURE;
         }