Bug 1399413 - Make VideoEngine & VideoCaptureModule singletons. r?jib draft
authorMunro Mengjue Chiang <mchiang@mozilla.com>
Thu, 02 Nov 2017 11:25:14 +0800
changeset 698104 01ccc04507d31e524ceb38c60dbd42a4e66f6951
parent 697453 e1d7427787f7a26983c92ea1a1ac99eb863edd6c
child 698105 b0de6e49fd62239fb5cb03d3db30d3e62dc808a7
push id89206
push userbmo:mchiang@mozilla.com
push dateWed, 15 Nov 2017 09:26:10 +0000
reviewersjib
bugs1399413
milestone59.0a1
Bug 1399413 - Make VideoEngine & VideoCaptureModule singletons. r?jib MozReview-Commit-ID: Czm0IYYpOpN
dom/media/systemservices/CamerasParent.cpp
dom/media/systemservices/CamerasParent.h
dom/media/systemservices/VideoEngine.cpp
dom/media/systemservices/VideoEngine.h
media/webrtc/trunk/webrtc/base/platform_thread.cc
media/webrtc/trunk/webrtc/base/platform_thread.h
media/webrtc/trunk/webrtc/modules/video_capture/video_capture.h
media/webrtc/trunk/webrtc/modules/video_capture/video_capture_impl.cc
media/webrtc/trunk/webrtc/modules/video_capture/video_capture_impl.h
media/webrtc/trunk/webrtc/test/vcm_capturer.cc
media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -34,16 +34,23 @@
 mozilla::LazyLogModule gCamerasParentLog("CamerasParent");
 #define LOG(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Debug, args)
 #define LOG_VERBOSE(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Verbose, args)
 #define LOG_ENABLED() MOZ_LOG_TEST(gCamerasParentLog, mozilla::LogLevel::Debug)
 
 namespace mozilla {
 namespace camera {
 
+RefPtr<VideoEngine> CamerasParent::sEngines[CaptureEngine::MaxEngine];
+int32_t CamerasParent::sNumOfOpenCamerasParentEngines = 0;
+int32_t CamerasParent::sNumOfCamerasParents = 0;
+base::Thread* CamerasParent::sVideoCaptureThread = nullptr;
+Monitor* CamerasParent::sThreadMonitor = nullptr;
+StaticMutex CamerasParent::sMutex;
+
 // 3 threads are involved in this code:
 // - the main thread for some setups, and occassionally for video capture setup
 //   calls that don't work correctly elsewhere.
 // - the IPC thread on which PBackground is running and which receives and
 //   sends messages
 // - a thread which will execute the actual (possibly slow) camera access
 //   called "VideoCapture". On Windows this is a thread with an event loop
 //   suitable for UI access.
@@ -147,68 +154,68 @@ CamerasParent::Observe(nsISupports *aSub
   StopVideoCapture();
   return NS_OK;
 }
 
 nsresult
 CamerasParent::DispatchToVideoCaptureThread(Runnable* event)
 {
   // Don't try to dispatch if we're already on the right thread.
-  // There's a potential deadlock because the mThreadMonitor is likely
+  // There's a potential deadlock because the sThreadMonitor is likely
   // to be taken already.
-  MOZ_ASSERT(!mVideoCaptureThread ||
-             mVideoCaptureThread->thread_id() != PlatformThread::CurrentId());
+  MOZ_ASSERT(!sVideoCaptureThread ||
+             sVideoCaptureThread->thread_id() != PlatformThread::CurrentId());
 
-  MonitorAutoLock lock(mThreadMonitor);
+  MonitorAutoLock lock(*sThreadMonitor);
 
   while(mChildIsAlive && mWebRTCAlive &&
-        (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning())) {
-    mThreadMonitor.Wait();
+        (!sVideoCaptureThread || !sVideoCaptureThread->IsRunning())) {
+    sThreadMonitor->Wait();
   }
-  if (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning()) {
+  if (!sVideoCaptureThread || !sVideoCaptureThread->IsRunning()) {
     return NS_ERROR_FAILURE;
   }
   RefPtr<Runnable> addrefedEvent = event;
-  mVideoCaptureThread->message_loop()->PostTask(addrefedEvent.forget());
+  sVideoCaptureThread->message_loop()->PostTask(addrefedEvent.forget());
   return NS_OK;
 }
 
 void
 CamerasParent::StopVideoCapture()
 {
   LOG((__PRETTY_FUNCTION__));
   // We are called from the main thread (xpcom-shutdown) or
   // from PBackground (when the Actor shuts down).
   // Shut down the WebRTC stack (on the capture thread)
   RefPtr<CamerasParent> self(this);
   RefPtr<Runnable> webrtc_runnable =
     media::NewRunnableFrom([self]() -> nsresult {
-      MonitorAutoLock lock(self->mThreadMonitor);
+      MonitorAutoLock lock(*(self->sThreadMonitor));
       self->CloseEngines();
-      self->mThreadMonitor.NotifyAll();
+      self->sThreadMonitor->NotifyAll();
       return NS_OK;
     });
   DebugOnly<nsresult> rv = DispatchToVideoCaptureThread(webrtc_runnable);
 #ifdef DEBUG
   // It's ok for the dispatch to fail if the cleanup it has to do
   // has been done already.
   MOZ_ASSERT(NS_SUCCEEDED(rv) || !mWebRTCAlive);
 #endif
   // Hold here until the WebRTC thread is gone. We need to dispatch
   // the thread deletion *now*, or there will be no more possibility
   // to get to the main thread.
-  MonitorAutoLock lock(mThreadMonitor);
+  MonitorAutoLock lock(*sThreadMonitor);
   while (mWebRTCAlive) {
-    mThreadMonitor.Wait();
+    sThreadMonitor->Wait();
   }
   // After closing the WebRTC stack, clean up the
   // VideoCapture thread.
-  if (self->mVideoCaptureThread) {
-    base::Thread *thread = self->mVideoCaptureThread;
-    self->mVideoCaptureThread = nullptr;
+  if (sNumOfOpenCamerasParentEngines == 0 && self->sVideoCaptureThread) {
+    base::Thread *thread = self->sVideoCaptureThread;
+    self->sVideoCaptureThread = nullptr;
     RefPtr<Runnable> threadShutdown =
       media::NewRunnableFrom([thread]() -> nsresult {
         if (thread->IsRunning()) {
           thread->Stop();
         }
         delete thread;
         return NS_OK;
       });
@@ -302,109 +309,110 @@ CamerasParent::RecvReleaseFrame(mozilla:
   mShmemPool.Put(ShmemBuffer(s));
   return IPC_OK();
 }
 
 bool
 CamerasParent::SetupEngine(CaptureEngine aCapEngine)
 {
   LOG((__PRETTY_FUNCTION__));
-  MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
-  RefPtr<mozilla::camera::VideoEngine>* engine = &mEngines[aCapEngine];
+  MOZ_ASSERT(sVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
+  RefPtr<mozilla::camera::VideoEngine>* engine = &sEngines[aCapEngine];
+
+  if (!engine->get()) {
+    webrtc::CaptureDeviceInfo *captureDeviceInfo = nullptr;
+    UniquePtr<webrtc::Config> config(new webrtc::Config);
 
-  // Already initialized
-  if (engine->get()) {
-    return true;
+    switch (aCapEngine) {
+    case ScreenEngine:
+      captureDeviceInfo =
+        new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Screen);
+      break;
+    case BrowserEngine:
+      captureDeviceInfo =
+        new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Browser);
+      break;
+    case WinEngine:
+      captureDeviceInfo =
+        new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Window);
+      break;
+    case AppEngine:
+      captureDeviceInfo =
+        new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Application);
+      break;
+    case CameraEngine:
+      captureDeviceInfo =
+        new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Camera);
+      break;
+    default:
+      LOG(("Invalid webrtc Video engine"));
+      MOZ_CRASH();
+      break;
+    }
+
+    config->Set<webrtc::CaptureDeviceInfo>(captureDeviceInfo);
+    *engine = mozilla::camera::VideoEngine::Create(UniquePtr<const webrtc::Config>(config.release()));
+
+    if (!engine->get()) {
+      LOG(("VideoEngine::Create failed"));
+      return false;
+    }
   }
 
-  webrtc::CaptureDeviceInfo *captureDeviceInfo = nullptr;
-  UniquePtr<webrtc::Config> config(new webrtc::Config);
-
-  switch (aCapEngine) {
-  case ScreenEngine:
-    captureDeviceInfo =
-      new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Screen);
-    break;
-  case BrowserEngine:
-    captureDeviceInfo =
-      new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Browser);
-    break;
-  case WinEngine:
-    captureDeviceInfo =
-      new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Window);
-    break;
-  case AppEngine:
-    captureDeviceInfo =
-      new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Application);
-    break;
-  case CameraEngine:
-    captureDeviceInfo =
-      new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Camera);
-    break;
-  default:
-    LOG(("Invalid webrtc Video engine"));
-    MOZ_CRASH();
-    break;
-  }
-
-  config->Set<webrtc::CaptureDeviceInfo>(captureDeviceInfo);
-  *engine = mozilla::camera::VideoEngine::Create(UniquePtr<const webrtc::Config>(config.release()));
-
-  if (!engine->get()) {
-    LOG(("VideoEngine::Create failed"));
-    return false;
-  }
-
-  RefPtr<InputObserver>* observer = mObservers.AppendElement(new InputObserver(this));
-  auto device_info = engine->get()->GetOrCreateVideoCaptureDeviceInfo();
-  MOZ_ASSERT(device_info);
-  if (device_info) {
-    device_info->RegisterVideoInputFeedBack(*(observer->get()));
+  if (aCapEngine == CameraEngine && !mCameraObserver) {
+    mCameraObserver = new InputObserver(this);
+    auto device_info = engine->get()->GetOrCreateVideoCaptureDeviceInfo();
+    MOZ_ASSERT(device_info);
+    if (device_info) {
+      device_info->RegisterVideoInputFeedBack(mCameraObserver.get());
+    }
   }
 
   return true;
 }
 
 void
 CamerasParent::CloseEngines()
 {
   LOG((__PRETTY_FUNCTION__));
   if (!mWebRTCAlive) {
     return;
   }
-  MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
+  MOZ_ASSERT(sVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
 
   // Stop the callers
   while (mCallbacks.Length()) {
     auto capEngine = mCallbacks[0]->mCapEngine;
     auto streamNum = mCallbacks[0]->mStreamId;
     LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, streamNum));
     StopCapture(capEngine, streamNum);
     Unused << ReleaseCaptureDevice(capEngine, streamNum);
   }
 
-  for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
-    if (auto engine = mEngines[i].get() ){
-      if (engine->IsRunning()) {
-        LOG(("Being closed down while engine %d is running!", i));
-      }
+  auto engine = sEngines[CameraEngine].get();
+  if (engine && mCameraObserver) {
+    auto device_info = engine->GetOrCreateVideoCaptureDeviceInfo();
+    MOZ_ASSERT(device_info);
+    if (device_info) {
+      device_info->DeRegisterVideoInputFeedBack(mCameraObserver.get());
+    }
+    mCameraObserver = nullptr;
+  }
 
-      auto device_info = engine->GetOrCreateVideoCaptureDeviceInfo();
-      MOZ_ASSERT(device_info);
-      if (device_info) {
-        device_info->DeRegisterVideoInputFeedBack();
+  // CloseEngines() is protected by sThreadMonitor
+  sNumOfOpenCamerasParentEngines--;
+  if (sNumOfOpenCamerasParentEngines == 0) {
+    for (auto& engine : sEngines) {
+      if (engine.get()) {
+        mozilla::camera::VideoEngine::Delete(engine.get());
+        engine = nullptr;
       }
-      mozilla::camera::VideoEngine::Delete(engine);
-      mEngines[i] = nullptr;
     }
   }
 
-  // the observers hold references to us
-  mObservers.Clear();
-
   mWebRTCAlive = false;
 }
 
 VideoEngine *
 CamerasParent::EnsureInitialized(int aEngine)
 {
   LOG_VERBOSE((__PRETTY_FUNCTION__));
   // We're shutting down, don't try to do new WebRTC ops.
@@ -412,17 +420,17 @@ CamerasParent::EnsureInitialized(int aEn
     return nullptr;
   }
   CaptureEngine capEngine = static_cast<CaptureEngine>(aEngine);
   if (!SetupEngine(capEngine)) {
     LOG(("CamerasParent failed to initialize engine"));
     return nullptr;
   }
 
-  return mEngines[aEngine];
+  return sEngines[aEngine];
 }
 
 // Dispatch the runnable to do the camera operation on the
 // specific Cameras thread, preventing us from blocking, and
 // chain a runnable to send back the result on the IPC thread.
 // It would be nice to get rid of the code duplication here,
 // perhaps via Promises.
 mozilla::ipc::IPCResult
@@ -707,17 +715,17 @@ CamerasParent::RecvAllocateCaptureDevice
       // After retrieving the permission (or not) on the main thread,
       // bounce to the WebRTC thread to allocate the device (or not),
       // then bounce back to the IPC thread for the reply to content.
       RefPtr<Runnable> webrtc_runnable =
       media::NewRunnableFrom([self, allowed, aCapEngine, unique_id]() -> nsresult {
         int numdev = -1;
         int error = -1;
         if (allowed && self->EnsureInitialized(aCapEngine)) {
-          auto engine = self->mEngines[aCapEngine].get();
+          auto engine = self->sEngines[aCapEngine].get();
           engine->CreateVideoCapture(numdev, unique_id.get());
           engine->WithEntry(numdev, [&error](VideoEngine::CaptureEntry& cap) {
             if (cap.VideoCapture()) {
               error = 0;
             }
           });
         }
         RefPtr<nsIRunnable> ipc_runnable =
@@ -802,33 +810,32 @@ CamerasParent::RecvStartCapture(const Ca
       LOG((__PRETTY_FUNCTION__));
       CallbackHelper** cbh;
       VideoEngine* engine = nullptr;
       int error = -1;
       if (self->EnsureInitialized(aCapEngine)) {
         cbh = self->mCallbacks.AppendElement(
           new CallbackHelper(static_cast<CaptureEngine>(aCapEngine), capnum, self));
 
-        engine = self->mEngines[aCapEngine];
-        engine->WithEntry(capnum, [&engine, &error, &ipcCaps, &cbh](VideoEngine::CaptureEntry& cap) {
+        engine = self->sEngines[aCapEngine];
+        engine->WithEntry(capnum, [&error, &ipcCaps, &cbh](VideoEngine::CaptureEntry& cap) {
           error = 0;
           webrtc::VideoCaptureCapability capability;
           capability.width = ipcCaps.width();
           capability.height = ipcCaps.height();
           capability.maxFPS = ipcCaps.maxFPS();
           capability.expectedCaptureDelay = ipcCaps.expectedCaptureDelay();
           capability.rawType = static_cast<webrtc::RawVideoType>(ipcCaps.rawType());
           capability.codecType = static_cast<webrtc::VideoCodecType>(ipcCaps.codecType());
           capability.interlaced = ipcCaps.interlaced();
 
           if (!error) {
             error = cap.VideoCapture()->StartCapture(capability);
           }
           if (!error) {
-            engine->Startup();
             cap.VideoCapture()->RegisterCaptureDataCallback(static_cast<rtc::VideoSinkInterface<webrtc::VideoFrame>*>(*cbh));
           }
         });
       }
       RefPtr<nsIRunnable> ipc_runnable =
         media::NewRunnableFrom([self, error]() -> nsresult {
           if (self->IsShuttingDown()) {
             return NS_ERROR_FAILURE;
@@ -848,32 +855,35 @@ CamerasParent::RecvStartCapture(const Ca
   return IPC_OK();
 }
 
 void
 CamerasParent::StopCapture(const CaptureEngine& aCapEngine,
                            const int& capnum)
 {
   if (auto engine = EnsureInitialized(aCapEngine)) {
-    engine->WithEntry(capnum,[](VideoEngine::CaptureEntry& cap){
-      if (cap.VideoCapture()) {
-        cap.VideoCapture()->StopCapture();
-        cap.VideoCapture()->DeRegisterCaptureDataCallback();
-      }
-    });
     // we're removing elements, iterate backwards
     for (size_t i = mCallbacks.Length(); i > 0; i--) {
       if (mCallbacks[i - 1]->mCapEngine == aCapEngine &&
           mCallbacks[i - 1]->mStreamId == (uint32_t)capnum) {
+
+        CallbackHelper* cbh = mCallbacks[i-1];
+        engine->WithEntry(capnum,[cbh](VideoEngine::CaptureEntry& cap) {
+          if (cap.VideoCapture()) {
+            cap.VideoCapture()->DeRegisterCaptureDataCallback(
+              static_cast<rtc::VideoSinkInterface<webrtc::VideoFrame>*>(cbh));
+            cap.VideoCapture()->StopCaptureIfAllClientsClose();
+          }
+        });
+
         delete mCallbacks[i - 1];
         mCallbacks.RemoveElementAt(i - 1);
         break;
       }
     }
-    engine->Shutdown();
   }
 }
 
 mozilla::ipc::IPCResult
 CamerasParent::RecvStopCapture(const CaptureEngine& aCapEngine,
                                const int& capnum)
 {
   LOG((__PRETTY_FUNCTION__));
@@ -936,23 +946,26 @@ CamerasParent::ActorDestroy(ActorDestroy
   StopIPC();
   // Shut down WebRTC (if we're not in full shutdown, else this
   // will already have happened)
   StopVideoCapture();
 }
 
 CamerasParent::CamerasParent()
   : mShmemPool(CaptureEngine::MaxEngine),
-    mThreadMonitor("CamerasParent::mThreadMonitor"),
-    mVideoCaptureThread(nullptr),
     mChildIsAlive(true),
     mDestroyed(false),
     mWebRTCAlive(true)
 {
   LOG(("CamerasParent: %p", this));
+  StaticMutexAutoLock slock(sMutex);
+
+  if (sNumOfCamerasParents++ == 0) {
+    sThreadMonitor = new Monitor("CamerasParent::sThreadMonitor");
+  }
 
   mPBackgroundEventTarget = GetCurrentThreadSerialEventTarget();
   MOZ_ASSERT(mPBackgroundEventTarget != nullptr,
              "GetCurrentThreadEventTarget failed");
 
   LOG(("Spinning up WebRTC Cameras Thread"));
 
   RefPtr<CamerasParent> self(this);
@@ -964,47 +977,45 @@ CamerasParent::CamerasParent()
         return NS_ERROR_FAILURE;
       }
       nsresult rv =
         obs->AddObserver(self, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       // Start the thread
-      MonitorAutoLock lock(self->mThreadMonitor);
-      self->mVideoCaptureThread = new base::Thread("VideoCapture");
-      base::Thread::Options options;
+      MonitorAutoLock lock(*(self->sThreadMonitor));
+      if (self->sVideoCaptureThread == nullptr) {
+        MOZ_ASSERT(sNumOfOpenCamerasParentEngines == 0);
+        self->sVideoCaptureThread = new base::Thread("VideoCapture");
+        base::Thread::Options options;
 #if defined(_WIN32)
-      options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
+        options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
 #else
-
-      options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
+        options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
 #endif
-      if (!self->mVideoCaptureThread->StartWithOptions(options)) {
-        MOZ_CRASH();
+        if (!self->sVideoCaptureThread->StartWithOptions(options)) {
+          MOZ_CRASH();
+        }
       }
-      self->mThreadMonitor.NotifyAll();
+      sNumOfOpenCamerasParentEngines++;
+      self->sThreadMonitor->NotifyAll();
       return NS_OK;
     });
   NS_DispatchToMainThread(threadStart);
 }
 
 CamerasParent::~CamerasParent()
 {
   LOG(("~CamerasParent: %p", this));
-
-#ifdef DEBUG
-  // Verify we have shut down the webrtc engines, this is
-  // supposed to happen in ActorDestroy.
-  // That runnable takes a ref to us, so it must have finished
-  // by the time we get here.
-  for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
-    MOZ_ASSERT(!mEngines[i]);
+  StaticMutexAutoLock slock(sMutex);
+  if (--sNumOfCamerasParents == 0) {
+    delete sThreadMonitor;
+    sThreadMonitor = nullptr;
   }
-#endif
 }
 
 already_AddRefed<CamerasParent>
 CamerasParent::Create() {
   mozilla::ipc::AssertIsOnBackgroundThread();
   RefPtr<CamerasParent> camerasParent = new CamerasParent();
   return camerasParent.forget();
 }
--- a/dom/media/systemservices/CamerasParent.h
+++ b/dom/media/systemservices/CamerasParent.h
@@ -130,38 +130,45 @@ protected:
   bool SetupEngine(CaptureEngine aCapEngine);
   VideoEngine* EnsureInitialized(int aEngine);
   void CloseEngines();
   void StopIPC();
   void StopVideoCapture();
   // Can't take already_AddRefed because it can fail in stupid ways.
   nsresult DispatchToVideoCaptureThread(Runnable* event);
 
-  RefPtr<VideoEngine> mEngines[CaptureEngine::MaxEngine];
+  // sEngines will be accessed by VideoCapture thread only
+  // sNumOfCamerasParent, sNumOfOpenCamerasParentEngines, and sVideoCaptureThread will
+  // be accessed by main thread / PBackground thread / VideoCapture thread
+  // all variables are protected by sThreadMonitor while sThreadMonitor
+  // creation and deletion is protected by sMutex
+  static RefPtr<VideoEngine> sEngines[CaptureEngine::MaxEngine];
+  static int32_t sNumOfOpenCamerasParentEngines;
+  static int32_t sNumOfCamerasParents;
   nsTArray<CallbackHelper*> mCallbacks;
 
   // image buffers
   mozilla::ShmemPool mShmemPool;
 
   // PBackground parent thread
   nsCOMPtr<nsISerialEventTarget> mPBackgroundEventTarget;
 
-  // Monitors creation of the thread below
-  Monitor mThreadMonitor;
+  static StaticMutex sMutex;
+  static Monitor* sThreadMonitor;
 
   // video processing thread - where webrtc.org capturer code runs
-  base::Thread* mVideoCaptureThread;
+  static base::Thread* sVideoCaptureThread;
 
   // Shutdown handling
   bool mChildIsAlive;
   bool mDestroyed;
   // Above 2 are PBackground only, but this is potentially
   // read cross-thread.
   mozilla::Atomic<bool> mWebRTCAlive;
-  nsTArray<RefPtr<InputObserver>> mObservers;
+  RefPtr<InputObserver> mCameraObserver;
 };
 
 PCamerasParent* CreateCamerasParent();
 
 } // namespace camera
 } // namespace mozilla
 
 #endif  // mozilla_CameraParent_h
--- a/dom/media/systemservices/VideoEngine.cpp
+++ b/dom/media/systemservices/VideoEngine.cpp
@@ -38,42 +38,78 @@ int VideoEngine::SetAndroidObjects(JavaV
 #endif
   return 0;
 }
 #endif
 
 void
 VideoEngine::CreateVideoCapture(int32_t& id, const char* deviceUniqueIdUTF8) {
   LOG((__PRETTY_FUNCTION__));
+
   id = GenerateId();
   LOG(("CaptureDeviceInfo.type=%s id=%d",mCaptureDevInfo.TypeName(),id));
+
+  for (auto &it : mCaps) {
+    if (strcmp(it.second.VideoCapture()->CurrentDeviceName(), deviceUniqueIdUTF8) == 0) {
+      mIdMap.emplace(id, it.first);
+      return;
+    }
+  }
+
   CaptureEntry entry = {-1, nullptr};
 
   if (mCaptureDevInfo.type == webrtc::CaptureDeviceType::Camera) {
     entry = CaptureEntry(id,
 		         webrtc::VideoCaptureFactory::Create(deviceUniqueIdUTF8));
   } else {
 #ifndef WEBRTC_ANDROID
     entry = CaptureEntry(
 	      id,
 	      webrtc::DesktopCaptureImpl::Create(id, deviceUniqueIdUTF8, mCaptureDevInfo.type));
 #else
     MOZ_ASSERT("CreateVideoCapture NO DESKTOP CAPTURE IMPL ON ANDROID" == nullptr);
 #endif
   }
   mCaps.emplace(id, std::move(entry));
+  mIdMap.emplace(id, id);
 }
 
 int
 VideoEngine::ReleaseVideoCapture(const int32_t id) {
   bool found = false;
-  WithEntry(id, [&found](CaptureEntry& cap) {
-         cap.mVideoCaptureModule = nullptr;
-        found = true;
-   });
+
+#ifdef DEBUG
+  {
+    auto it = mIdMap.find(id);
+    MOZ_ASSERT(it != mIdMap.end());
+    Unused << it;
+  }
+#endif
+
+  for (auto &it : mIdMap) {
+    if (it.first != id && it.second == mIdMap[id]) {
+      // There are other tracks still using this hardware.
+      found = true;
+    }
+  }
+
+  if (!found) {
+    WithEntry(id, [&found](CaptureEntry& cap) {
+      cap.mVideoCaptureModule = nullptr;
+      found = true;
+    });
+    MOZ_ASSERT(found);
+    if (found) {
+      auto it = mCaps.find(mIdMap[id]);
+      MOZ_ASSERT(it != mCaps.end());
+      mCaps.erase(it);
+    }
+  }
+
+  mIdMap.erase(id);
   return found ? 0 : (-1);
 }
 
 std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo>
 VideoEngine::GetOrCreateVideoCaptureDeviceInfo() {
   LOG((__PRETTY_FUNCTION__));
   int64_t currentTime = 0;
 
@@ -160,17 +196,26 @@ VideoEngine::CaptureEntry::VideoCapture(
 
 int32_t
 VideoEngine::CaptureEntry::Capnum() const {
   return mCapnum;
 }
 
 bool VideoEngine::WithEntry(const int32_t entryCapnum,
 			    const std::function<void(CaptureEntry &entry)>&& fn) {
-  auto it = mCaps.find(entryCapnum);
+#ifdef DEBUG
+  {
+    auto it = mIdMap.find(entryCapnum);
+    MOZ_ASSERT(it != mIdMap.end());
+    Unused << it;
+  }
+#endif
+
+  auto it = mCaps.find(mIdMap[entryCapnum]);
+  MOZ_ASSERT(it != mCaps.end());
   if (it == mCaps.end()) {
     return false;
   }
   fn(it->second);
   return true;
 }
 
 int32_t
--- a/dom/media/systemservices/VideoEngine.h
+++ b/dom/media/systemservices/VideoEngine.h
@@ -54,28 +54,16 @@ public:
   *   @return on failure the shared_ptr will be null, otherwise it will contain
   *   a DeviceInfo.
   *   @see bug 1305212 https://bugzilla.mozilla.org/show_bug.cgi?id=1305212
   */
   std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo> GetOrCreateVideoCaptureDeviceInfo();
 
   const UniquePtr<const webrtc::Config>& GetConfiguration();
 
-  void Startup() {
-    mIsRunning = true;
-  }
-
-  void Shutdown() {
-    mIsRunning = false;
-  }
-
-  bool IsRunning() const {
-    return mIsRunning;
-  }
-
   class CaptureEntry {
   public:
     CaptureEntry(int32_t aCapnum,
                  rtc::scoped_refptr<webrtc::VideoCaptureModule> aCapture);
     int32_t Capnum() const;
     rtc::scoped_refptr<webrtc::VideoCaptureModule> VideoCapture();
   private:
     int32_t mCapnum;
@@ -83,22 +71,22 @@ public:
     friend class VideoEngine;
   };
 
   // Returns true iff an entry for capnum exists
   bool WithEntry(const int32_t entryCapnum, const std::function<void(CaptureEntry &entry)>&& fn);
 
 private:
   explicit VideoEngine(UniquePtr<const webrtc::Config>&& aConfig);
-  bool mIsRunning;
   int32_t mId;
   webrtc::CaptureDeviceInfo mCaptureDevInfo;
   std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo> mDeviceInfo;
   UniquePtr<const webrtc::Config> mConfig;
   std::map<int32_t, CaptureEntry> mCaps;
+  std::map<int32_t, int32_t> mIdMap;
   // The validity period for non-camera capture device infos`
   int64_t mExpiryTimeInMs = 0;
   int32_t GenerateId();
   static int32_t sId;
 };
 }
 }
 #endif
--- a/media/webrtc/trunk/webrtc/base/platform_thread.cc
+++ b/media/webrtc/trunk/webrtc/base/platform_thread.cc
@@ -139,16 +139,17 @@ PlatformThread::~PlatformThread() {
   RTC_DCHECK(!thread_id_);
 #endif  // defined(WEBRTC_WIN)
 }
 
 #if defined(WEBRTC_WIN)
 bool PlatformUIThread::InternalInit() {
   // Create an event window for use in generating callbacks to capture
   // objects.
+  CritScope scoped_lock(&cs_);
   if (hwnd_ == NULL) {
     WNDCLASSW wc;
     HMODULE hModule = GetModuleHandle(NULL);
     if (!GetClassInfoW(hModule, kThreadWindow, &wc)) {
       ZeroMemory(&wc, sizeof(WNDCLASSW));
       wc.hInstance = hModule;
       wc.lpfnWndProc = EventWindowProc;
       wc.lpszClassName = kThreadWindow;
@@ -170,18 +171,23 @@ bool PlatformUIThread::InternalInit() {
 
 void PlatformUIThread::RequestCallback() {
   RTC_DCHECK(hwnd_);
   RTC_DCHECK(static_reg_windows_msg);
   PostMessage(hwnd_, static_reg_windows_msg, 0, 0);
 }
 
 bool PlatformUIThread::RequestCallbackTimer(unsigned int milliseconds) {
+  CritScope scoped_lock(&cs_);
   if (!hwnd_) {
-    RTC_DCHECK(!thread_);
+    // There is a condition that thread_ (PlatformUIThread) has been
+    // created but PlatformUIThread::Run() hasn't been run yet (hwnd_ is
+    // null while thread_ is not). If we do RTC_DCHECK(!thread_) here,
+    // it would lead to crash in this condition.
+
     // set timer once thread starts
   } else {
     if (timerid_) {
       KillTimer(hwnd_, timerid_);
     }
     timerid_ = SetTimer(hwnd_, kTimerId, milliseconds, NULL);
   }
   timeout_ = milliseconds;
--- a/media/webrtc/trunk/webrtc/base/platform_thread.h
+++ b/media/webrtc/trunk/webrtc/base/platform_thread.h
@@ -91,16 +91,17 @@ class PlatformThread {
   const std::string name_;
   rtc::ThreadChecker thread_checker_;
 #if defined(WEBRTC_WIN)
   static DWORD WINAPI StartThread(void* param);
 
   bool stop_;
   HANDLE thread_;
   DWORD thread_id_;
+  CriticalSection cs_;
 #else
   static void* StartThread(void* param);
 
   rtc::Event stop_event_;
 
   pthread_t thread_;
 #endif  // defined(WEBRTC_WIN)
   RTC_DISALLOW_COPY_AND_ASSIGN(PlatformThread);
--- a/media/webrtc/trunk/webrtc/modules/video_capture/video_capture.h
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/video_capture.h
@@ -11,16 +11,17 @@
 #ifndef WEBRTC_MODULES_VIDEO_CAPTURE_VIDEO_CAPTURE_H_
 #define WEBRTC_MODULES_VIDEO_CAPTURE_VIDEO_CAPTURE_H_
 
 #include "webrtc/modules/audio_processing/include/config.h"
 #include "webrtc/api/video/video_rotation.h"
 #include "webrtc/media/base/videosinkinterface.h"
 #include "webrtc/modules/include/module.h"
 #include "webrtc/modules/video_capture/video_capture_defines.h"
+#include <set>
 
 #if defined(ANDROID)
 #include <jni.h>
 #endif
 
 namespace webrtc {
 
 // Mozilla addition
@@ -79,24 +80,29 @@ protected:
 class VideoCaptureModule: public rtc::RefCountInterface {
  public:
   // Interface for receiving information about available camera devices.
   class DeviceInfo {
    public:
     virtual uint32_t NumberOfDevices() = 0;
     virtual int32_t Refresh() = 0;
     virtual void DeviceChange() {
-     if (_inputCallBack)
-      _inputCallBack->OnDeviceChange();
+      for (auto inputCallBack : _inputCallBacks) {
+        inputCallBack->OnDeviceChange();
+      }
+    }
+    virtual void RegisterVideoInputFeedBack(VideoInputFeedBack* callBack) {
+      _inputCallBacks.insert(callBack);
     }
-    virtual void RegisterVideoInputFeedBack(VideoInputFeedBack& callBack) {
-     _inputCallBack = &callBack;
-    }
-    virtual void DeRegisterVideoInputFeedBack() {
-     _inputCallBack = NULL;
+
+    virtual void DeRegisterVideoInputFeedBack(VideoInputFeedBack* callBack) {
+      auto it = _inputCallBacks.find(callBack);
+      if (it != _inputCallBacks.end()) {
+        _inputCallBacks.erase(it);
+      }
     }
 
     // Returns the available capture devices.
     // deviceNumber   - Index of capture device.
     // deviceNameUTF8 - Friendly name of the capture device.
     // deviceUniqueIdUTF8 - Unique name of the capture device if it exist.
     //                      Otherwise same as deviceNameUTF8.
     // productUniqueIdUTF8 - Unique product id if it exist.
@@ -140,30 +146,33 @@ class VideoCaptureModule: public rtc::Re
         const char* deviceUniqueIdUTF8,
         const char* dialogTitleUTF8,
         void* parentWindow,
         uint32_t positionX,
         uint32_t positionY) = 0;
 
     virtual ~DeviceInfo() {}
    private:
-    VideoInputFeedBack* _inputCallBack = NULL;
+    std::set<VideoInputFeedBack*> _inputCallBacks;
   };
 
   //   Register capture data callback
   virtual void RegisterCaptureDataCallback(
       rtc::VideoSinkInterface<VideoFrame> *dataCallback) = 0;
 
   //  Remove capture data callback
-  virtual void DeRegisterCaptureDataCallback() = 0;
+  virtual void DeRegisterCaptureDataCallback(
+      rtc::VideoSinkInterface<VideoFrame> *dataCallback) = 0;
 
   // Start capture device
   virtual int32_t StartCapture(
       const VideoCaptureCapability& capability) = 0;
 
+  virtual int32_t StopCaptureIfAllClientsClose() = 0;
+
   virtual int32_t StopCapture() = 0;
 
   // Returns the name of the device used by this module.
   virtual const char* CurrentDeviceName() const = 0;
 
   // Returns true if the capture device is running
   virtual bool CaptureStarted() = 0;
 
--- a/media/webrtc/trunk/webrtc/modules/video_capture/video_capture_impl.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/video_capture_impl.cc
@@ -81,52 +81,64 @@ int32_t VideoCaptureImpl::RotationInDegr
 
 VideoCaptureImpl::VideoCaptureImpl()
     : _deviceUniqueId(NULL),
       _apiCs(*CriticalSectionWrapper::CreateCriticalSection()),
       _captureDelay(0),
       _requestedCapability(),
       _lastProcessTimeNanos(rtc::TimeNanos()),
       _lastFrameRateCallbackTimeNanos(rtc::TimeNanos()),
-      _dataCallBack(NULL),
       _lastProcessFrameTimeNanos(rtc::TimeNanos()),
       _rotateFrame(kVideoRotation_0),
       apply_rotation_(true) {
     _requestedCapability.width = kDefaultWidth;
     _requestedCapability.height = kDefaultHeight;
     _requestedCapability.maxFPS = 30;
     _requestedCapability.rawType = kVideoI420;
     _requestedCapability.codecType = kVideoCodecUnknown;
     memset(_incomingFrameTimesNanos, 0, sizeof(_incomingFrameTimesNanos));
 }
 
 VideoCaptureImpl::~VideoCaptureImpl()
 {
-    DeRegisterCaptureDataCallback();
     delete &_apiCs;
 
     if (_deviceUniqueId)
         delete[] _deviceUniqueId;
 }
 
 void VideoCaptureImpl::RegisterCaptureDataCallback(
-    rtc::VideoSinkInterface<VideoFrame>* dataCallBack) {
-    CriticalSectionScoped cs(&_apiCs);
-    _dataCallBack = dataCallBack;
+  rtc::VideoSinkInterface<VideoFrame>* dataCallBack) {
+  CriticalSectionScoped cs(&_apiCs);
+  _dataCallBacks.insert(dataCallBack);
 }
 
-void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
-    CriticalSectionScoped cs(&_apiCs);
-    _dataCallBack = NULL;
+void VideoCaptureImpl::DeRegisterCaptureDataCallback(
+  rtc::VideoSinkInterface<VideoFrame>* dataCallBack) {
+  CriticalSectionScoped cs(&_apiCs);
+
+  auto it = _dataCallBacks.find(dataCallBack);
+  if (it != _dataCallBacks.end()) {
+    _dataCallBacks.erase(it);
+  }
 }
+
+int32_t VideoCaptureImpl::StopCaptureIfAllClientsClose() {
+  if (_dataCallBacks.empty()) {
+    return StopCapture();
+  } else {
+    return 0;
+  }
+}
+
 int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) {
   UpdateFrameCount();  // frame count used for local frame rate callback.
 
-  if (_dataCallBack) {
-    _dataCallBack->OnFrame(captureFrame);
+  for (auto dataCallBack : _dataCallBacks) {
+    dataCallBack->OnFrame(captureFrame);
   }
 
   return 0;
 }
 
 int32_t VideoCaptureImpl::IncomingFrame(
     uint8_t* videoFrame,
     size_t videoFrameLength,
--- a/media/webrtc/trunk/webrtc/modules/video_capture/video_capture_impl.h
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/video_capture_impl.h
@@ -15,16 +15,17 @@
  * video_capture_impl.h
  */
 
 #include "webrtc/api/video/video_frame.h"
 #include "webrtc/base/scoped_ref_ptr.h"
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
 #include "webrtc/modules/video_capture/video_capture.h"
 #include "webrtc/modules/video_capture/video_capture_config.h"
+#include <set>
 
 namespace webrtc
 {
 class CriticalSectionWrapper;
 
 namespace videocapturemodule {
 // Class definitions
 class VideoCaptureImpl: public VideoCaptureModule, public VideoCaptureExternal
@@ -54,18 +55,20 @@ public:
     // Helpers for converting between (integral) degrees and
     // VideoRotation values.  Return 0 on success.
     static int32_t RotationFromDegrees(int degrees, VideoRotation* rotation);
     static int32_t RotationInDegrees(VideoRotation rotation, int* degrees);
 
     //Call backs
     void RegisterCaptureDataCallback(
         rtc::VideoSinkInterface<VideoFrame>* dataCallback) override;
-    void DeRegisterCaptureDataCallback() override;
+    void DeRegisterCaptureDataCallback(
+        rtc::VideoSinkInterface<VideoFrame>* dataCallback) override;
 
+    int32_t StopCaptureIfAllClientsClose() override;
     int32_t SetCaptureRotation(VideoRotation rotation) override;
     bool SetApplyRotation(bool enable) override;
     bool GetApplyRotation() override {
       return apply_rotation_;
     }
 
     const char* CurrentDeviceName() const override;
 
@@ -100,17 +103,17 @@ private:
     void UpdateFrameCount();
     uint32_t CalculateFrameRate(int64_t now_ns);
 
     // last time the module process function was called.
     int64_t _lastProcessTimeNanos;
     // last time the frame rate callback function was called.
     int64_t _lastFrameRateCallbackTimeNanos;
 
-    rtc::VideoSinkInterface<VideoFrame>* _dataCallBack;
+    std::set<rtc::VideoSinkInterface<VideoFrame>*> _dataCallBacks;
 
     int64_t _lastProcessFrameTimeNanos;
     // timestamp for local captured frames
     int64_t _incomingFrameTimesNanos[kFrameRateCountHistorySize];
     VideoRotation _rotateFrame;  // Set if the frame should be rotated by the
                                  // capture module.
 
     // Indicate whether rotation should be applied before delivered externally.
--- a/media/webrtc/trunk/webrtc/test/vcm_capturer.cc
+++ b/media/webrtc/trunk/webrtc/test/vcm_capturer.cc
@@ -88,17 +88,17 @@ void VcmCapturer::RemoveSink(rtc::VideoS
   sink_ = nullptr;
 }
 
 void VcmCapturer::Destroy() {
   if (!vcm_)
     return;
 
   vcm_->StopCapture();
-  vcm_->DeRegisterCaptureDataCallback();
+  vcm_->DeRegisterCaptureDataCallback(this);
   // Release reference to VCM.
   vcm_ = nullptr;
 }
 
 VcmCapturer::~VcmCapturer() { Destroy(); }
 
 void VcmCapturer::OnFrame(const VideoFrame& frame) {
   rtc::CritScope lock(&crit_);
--- a/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
@@ -433,17 +433,16 @@ int32_t DesktopCaptureImpl::Init(const c
 }
 
 DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id)
   : _id(id),
     _deviceUniqueId(""),
     _apiCs(*CriticalSectionWrapper::CreateCriticalSection()),
     _requestedCapability(),
     _callBackCs(*CriticalSectionWrapper::CreateCriticalSection()),
-    _dataCallBack(NULL),
     _rotateFrame(kVideoRotation_0),
     last_capture_time_(rtc::TimeNanos()/rtc::kNumNanosecsPerMillisec),
     // XXX Note that this won't capture drift!
     delta_ntp_internal_ms_(Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() -
                            last_capture_time_),
     time_event_(EventWrapper::Create()),
     mRefCount(0),
 #if defined(_WIN32)
@@ -461,33 +460,44 @@ DesktopCaptureImpl::DesktopCaptureImpl(c
   _requestedCapability.codecType = kVideoCodecUnknown;
   memset(_incomingFrameTimesNanos, 0, sizeof(_incomingFrameTimesNanos));
 }
 
 DesktopCaptureImpl::~DesktopCaptureImpl() {
   time_event_->Set();
   capturer_thread_->Stop();
 
-  DeRegisterCaptureDataCallback();
   delete &_callBackCs;
   delete &_apiCs;
 }
 
 void DesktopCaptureImpl::RegisterCaptureDataCallback(rtc::VideoSinkInterface<VideoFrame> *dataCallback)
 {
   CriticalSectionScoped cs(&_apiCs);
   CriticalSectionScoped cs2(&_callBackCs);
-  _dataCallBack = dataCallback;
+  _dataCallBacks.insert(dataCallback);
 }
 
-void DesktopCaptureImpl::DeRegisterCaptureDataCallback()
+void DesktopCaptureImpl::DeRegisterCaptureDataCallback(
+  rtc::VideoSinkInterface<VideoFrame> *dataCallback)
 {
   CriticalSectionScoped cs(&_apiCs);
   CriticalSectionScoped cs2(&_callBackCs);
-  _dataCallBack = nullptr;
+  auto it = _dataCallBacks.find(dataCallback);
+  if (it != _dataCallBacks.end()) {
+    _dataCallBacks.erase(it);
+  }
+}
+
+int32_t DesktopCaptureImpl::StopCaptureIfAllClientsClose() {
+  if (_dataCallBacks.empty()) {
+    return StopCapture();
+  } else {
+    return 0;
+  }
 }
 
 int32_t DesktopCaptureImpl::DeliverCapturedFrame(webrtc::VideoFrame& captureFrame,
                                                  int64_t capture_time) {
   UpdateFrameCount();  // frame count used for local frame rate callback.
 
   // Set the capture time
   if (capture_time != 0) {
@@ -497,18 +507,18 @@ int32_t DesktopCaptureImpl::DeliverCaptu
   }
 
   if (captureFrame.render_time_ms() == last_capture_time_) {
     // We don't allow the same capture time for two frames, drop this one.
     return -1;
   }
   last_capture_time_ = captureFrame.render_time_ms();
 
-  if (_dataCallBack) {
-    _dataCallBack->OnFrame(captureFrame);
+  for (auto dataCallBack : _dataCallBacks) {
+    dataCallBack->OnFrame(captureFrame);
   }
 
   return 0;
 }
 
 // Copied from VideoCaptureImpl::IncomingFrame. See Bug 1038324
 int32_t DesktopCaptureImpl::IncomingFrame(uint8_t* videoFrame,
                                           size_t videoFrameLength,
@@ -684,16 +694,20 @@ uint32_t DesktopCaptureImpl::CalculateFr
 
 int32_t DesktopCaptureImpl::StartCapture(const VideoCaptureCapability& capability) {
   _requestedCapability = capability;
 #if defined(_WIN32)
   uint32_t maxFPSNeeded = 1000/_requestedCapability.maxFPS;
   capturer_thread_->RequestCallbackTimer(maxFPSNeeded);
 #endif
 
+  if (started_) {
+    return 0;
+  }
+
   desktop_capturer_cursor_composer_->Start(this);
   capturer_thread_->Start();
   started_ = true;
 
   return 0;
 }
 
 int32_t DesktopCaptureImpl::StopCapture() {
--- a/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
+++ b/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
@@ -22,16 +22,17 @@
 #include "webrtc/base/scoped_ref_ptr.h"
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
 #include "webrtc/modules/video_capture/video_capture_config.h"
 #include "webrtc/modules/desktop_capture/shared_memory.h"
 #include "webrtc/base/platform_thread.h"
 #include "webrtc/system_wrappers/include/event_wrapper.h"
 #include "webrtc/modules/desktop_capture/desktop_device_info.h"
 #include "webrtc/modules/desktop_capture/desktop_and_cursor_composer.h"
+#include <set>
 
 using namespace webrtc::videocapturemodule;
 
 namespace webrtc {
 
 class CriticalSectionWrapper;
 class VideoCaptureEncodeInterface;
 
@@ -168,17 +169,18 @@ public:
   static VideoCaptureModule::DeviceInfo* CreateDeviceInfo(const int32_t id, const CaptureDeviceType type);
 
   int32_t Init(const char* uniqueId, const CaptureDeviceType type);
   //RefCounting for RefCountedModule
   virtual int32_t AddRef() const override;
   virtual int32_t Release() const override;
   //Call backs
   virtual void RegisterCaptureDataCallback(rtc::VideoSinkInterface<VideoFrame> *dataCallback) override;
-  virtual void DeRegisterCaptureDataCallback() override;
+  virtual void DeRegisterCaptureDataCallback(rtc::VideoSinkInterface<VideoFrame> *dataCallback) override;
+  virtual int32_t StopCaptureIfAllClientsClose() override;
 
   virtual int32_t SetCaptureRotation(VideoRotation rotation) override;
   virtual bool SetApplyRotation(bool enable) override;
   virtual bool GetApplyRotation() override { return true; }
 
   virtual const char* CurrentDeviceName() const override;
 
   // Implement VideoCaptureExternal
@@ -208,17 +210,17 @@ protected:
   VideoCaptureCapability _requestedCapability; // Should be set by platform dependent code in StartCapture.
 
 private:
   void UpdateFrameCount();
   uint32_t CalculateFrameRate(int64_t now_ns);
 
   CriticalSectionWrapper& _callBackCs;
 
-  rtc::VideoSinkInterface<VideoFrame>* _dataCallBack;
+  std::set<rtc::VideoSinkInterface<VideoFrame>*> _dataCallBacks;
 
   int64_t _incomingFrameTimesNanos[kFrameRateCountHistorySize];// timestamp for local captured frames
   VideoRotation _rotateFrame; //Set if the frame should be rotated by the capture module.
 
   // Used to make sure incoming timestamp is increasing for every frame.
   int64_t last_capture_time_;
 
   // Delta used for translating between NTP and internal timestamps.