LCOV - code coverage report
Current view: top level - dom/media/systemservices - CamerasParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 530 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 105 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set sw=2 ts=8 et ft=cpp : */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "CamerasParent.h"
       8             : #include "MediaEngine.h"
       9             : #include "MediaUtils.h"
      10             : #include "VideoFrameUtils.h"
      11             : 
      12             : #include "mozilla/Assertions.h"
      13             : #include "mozilla/Unused.h"
      14             : #include "mozilla/Services.h"
      15             : #include "mozilla/Logging.h"
      16             : #include "mozilla/ipc/BackgroundParent.h"
      17             : #include "mozilla/ipc/PBackgroundParent.h"
      18             : #include "mozilla/Preferences.h"
      19             : #include "nsIPermissionManager.h"
      20             : #include "nsThreadUtils.h"
      21             : #include "nsXPCOM.h"
      22             : #include "nsNetUtil.h"
      23             : 
      24             : #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
      25             : 
      26             : #if defined(_WIN32)
      27             : #include <process.h>
      28             : #define getpid() _getpid()
      29             : #endif
      30             : 
      31             : #undef LOG
      32             : #undef LOG_VERBOSE
      33             : #undef LOG_ENABLED
      34             : mozilla::LazyLogModule gCamerasParentLog("CamerasParent");
      35             : #define LOG(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Debug, args)
      36             : #define LOG_VERBOSE(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Verbose, args)
      37             : #define LOG_ENABLED() MOZ_LOG_TEST(gCamerasParentLog, mozilla::LogLevel::Debug)
      38             : 
      39             : namespace mozilla {
      40             : namespace camera {
      41             : 
      42             : // 3 threads are involved in this code:
      43             : // - the main thread for some setups, and occassionally for video capture setup
      44             : //   calls that don't work correctly elsewhere.
      45             : // - the IPC thread on which PBackground is running and which receives and
      46             : //   sends messages
      47             : // - a thread which will execute the actual (possibly slow) camera access
      48             : //   called "VideoCapture". On Windows this is a thread with an event loop
      49             : //   suitable for UI access.
      50             : 
      51             : // InputObserver is owned by CamerasParent, and it has a ref to CamerasParent
      52           0 : void InputObserver::OnDeviceChange() {
      53           0 :   LOG((__PRETTY_FUNCTION__));
      54           0 :   MOZ_ASSERT(mParent);
      55             : 
      56           0 :   RefPtr<InputObserver> self(this);
      57             :   RefPtr<nsIRunnable> ipc_runnable =
      58           0 :     media::NewRunnableFrom([self]() -> nsresult {
      59           0 :       if (self->mParent->IsShuttingDown()) {
      60           0 :         return NS_ERROR_FAILURE;
      61             :       }
      62           0 :       Unused << self->mParent->SendDeviceChange();
      63           0 :       return NS_OK;
      64           0 :     });
      65             : 
      66           0 :   nsIEventTarget* target = mParent->GetBackgroundEventTarget();
      67           0 :   MOZ_ASSERT(target != nullptr);
      68           0 :   target->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
      69           0 : };
      70             : 
      71           0 : class DeliverFrameRunnable : public ::mozilla::Runnable {
      72             : public:
      73           0 :   DeliverFrameRunnable(CamerasParent* aParent,
      74             :                        CaptureEngine aEngine,
      75             :                        uint32_t aStreamId,
      76             :                        const webrtc::VideoFrame& aFrame,
      77             :                        const VideoFrameProperties& aProperties)
      78           0 :     : Runnable("camera::DeliverFrameRunnable")
      79             :     , mParent(aParent)
      80             :     , mCapEngine(aEngine)
      81             :     , mStreamId(aStreamId)
      82           0 :     , mProperties(aProperties)
      83             :   {
      84             :     // No ShmemBuffer (of the right size) was available, so make an
      85             :     // extra buffer here.  We have no idea when we are going to run and
      86             :     // it will be potentially long after the webrtc frame callback has
      87             :     // returned, so the copy needs to be no later than here.
      88             :     // We will need to copy this back into a Shmem later on so we prefer
      89             :     // using ShmemBuffers to avoid the extra copy.
      90           0 :     mAlternateBuffer.reset(new unsigned char[aProperties.bufferSize()]);
      91           0 :     VideoFrameUtils::CopyVideoFrameBuffers(mAlternateBuffer.get(),
      92           0 :                                            aProperties.bufferSize(), aFrame);
      93           0 :   }
      94             : 
      95           0 :   DeliverFrameRunnable(CamerasParent* aParent,
      96             :                        CaptureEngine aEngine,
      97             :                        uint32_t aStreamId,
      98             :                        ShmemBuffer aBuffer,
      99             :                        VideoFrameProperties& aProperties)
     100           0 :     : Runnable("camera::DeliverFrameRunnable")
     101             :     , mParent(aParent)
     102             :     , mCapEngine(aEngine)
     103             :     , mStreamId(aStreamId)
     104           0 :     , mBuffer(Move(aBuffer))
     105           0 :     , mProperties(aProperties){};
     106             : 
     107           0 :   NS_IMETHOD Run() override {
     108           0 :     if (mParent->IsShuttingDown()) {
     109             :       // Communication channel is being torn down
     110           0 :       mResult = 0;
     111           0 :       return NS_OK;
     112             :     }
     113           0 :     if (!mParent->DeliverFrameOverIPC(mCapEngine, mStreamId, Move(mBuffer),
     114             :                                       mAlternateBuffer.get(), mProperties)) {
     115           0 :       mResult = -1;
     116             :     } else {
     117           0 :       mResult = 0;
     118             :     }
     119           0 :     return NS_OK;
     120             :   }
     121             : 
     122             :   int GetResult() {
     123             :     return mResult;
     124             :   }
     125             : 
     126             : private:
     127             :   RefPtr<CamerasParent> mParent;
     128             :   CaptureEngine mCapEngine;
     129             :   uint32_t mStreamId;
     130             :   ShmemBuffer mBuffer;
     131             :   mozilla::UniquePtr<unsigned char[]> mAlternateBuffer;
     132             :   VideoFrameProperties mProperties;
     133             :   int mResult;
     134             : };
     135             : 
     136           0 : NS_IMPL_ISUPPORTS(CamerasParent, nsIObserver)
     137             : 
     138             : NS_IMETHODIMP
     139           0 : CamerasParent::Observe(nsISupports *aSubject,
     140             :                        const char *aTopic,
     141             :                        const char16_t *aData)
     142             : {
     143           0 :   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID));
     144           0 :   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     145           0 :   MOZ_ASSERT(obs);
     146           0 :   obs->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
     147           0 :   StopVideoCapture();
     148           0 :   return NS_OK;
     149             : }
     150             : 
     151             : nsresult
     152           0 : CamerasParent::DispatchToVideoCaptureThread(Runnable* event)
     153             : {
     154             :   // Don't try to dispatch if we're already on the right thread.
     155             :   // There's a potential deadlock because the mThreadMonitor is likely
     156             :   // to be taken already.
     157           0 :   MOZ_ASSERT(!mVideoCaptureThread ||
     158             :              mVideoCaptureThread->thread_id() != PlatformThread::CurrentId());
     159             : 
     160           0 :   MonitorAutoLock lock(mThreadMonitor);
     161             : 
     162           0 :   while(mChildIsAlive && mWebRTCAlive &&
     163           0 :         (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning())) {
     164           0 :     mThreadMonitor.Wait();
     165             :   }
     166           0 :   if (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning()) {
     167           0 :     return NS_ERROR_FAILURE;
     168             :   }
     169           0 :   RefPtr<Runnable> addrefedEvent = event;
     170           0 :   mVideoCaptureThread->message_loop()->PostTask(addrefedEvent.forget());
     171           0 :   return NS_OK;
     172             : }
     173             : 
     174             : void
     175           0 : CamerasParent::StopVideoCapture()
     176             : {
     177           0 :   LOG((__PRETTY_FUNCTION__));
     178             :   // We are called from the main thread (xpcom-shutdown) or
     179             :   // from PBackground (when the Actor shuts down).
     180             :   // Shut down the WebRTC stack (on the capture thread)
     181           0 :   RefPtr<CamerasParent> self(this);
     182             :   RefPtr<Runnable> webrtc_runnable =
     183           0 :     media::NewRunnableFrom([self]() -> nsresult {
     184           0 :       MonitorAutoLock lock(self->mThreadMonitor);
     185           0 :       self->CloseEngines();
     186           0 :       self->mThreadMonitor.NotifyAll();
     187           0 :       return NS_OK;
     188           0 :     });
     189           0 :   DebugOnly<nsresult> rv = DispatchToVideoCaptureThread(webrtc_runnable);
     190             : #ifdef DEBUG
     191             :   // It's ok for the dispatch to fail if the cleanup it has to do
     192             :   // has been done already.
     193           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv) || !mWebRTCAlive);
     194             : #endif
     195             :   // Hold here until the WebRTC thread is gone. We need to dispatch
     196             :   // the thread deletion *now*, or there will be no more possibility
     197             :   // to get to the main thread.
     198           0 :   MonitorAutoLock lock(mThreadMonitor);
     199           0 :   while (mWebRTCAlive) {
     200           0 :     mThreadMonitor.Wait();
     201             :   }
     202             :   // After closing the WebRTC stack, clean up the
     203             :   // VideoCapture thread.
     204           0 :   if (self->mVideoCaptureThread) {
     205           0 :     base::Thread *thread = self->mVideoCaptureThread;
     206           0 :     self->mVideoCaptureThread = nullptr;
     207             :     RefPtr<Runnable> threadShutdown =
     208           0 :       media::NewRunnableFrom([thread]() -> nsresult {
     209           0 :         if (thread->IsRunning()) {
     210           0 :           thread->Stop();
     211             :         }
     212           0 :         delete thread;
     213           0 :         return NS_OK;
     214           0 :       });
     215           0 :     if (NS_FAILED(NS_DispatchToMainThread(threadShutdown))) {
     216           0 :       LOG(("Could not dispatch VideoCaptureThread destruction"));
     217             :     }
     218             :   }
     219           0 : }
     220             : 
     221             : int
     222           0 : CamerasParent::DeliverFrameOverIPC(CaptureEngine capEng,
     223             :                           uint32_t aStreamId,
     224             :                           ShmemBuffer buffer,
     225             :                           unsigned char* altbuffer,
     226             :                           VideoFrameProperties& aProps)
     227             : {
     228             :   // No ShmemBuffers were available, so construct one now of the right size
     229             :   // and copy into it. That is an extra copy, but we expect this to be
     230             :   // the exceptional case, because we just assured the next call *will* have a
     231             :   // buffer of the right size.
     232           0 :   if (altbuffer != nullptr) {
     233             :     // Get a shared memory buffer from the pool, at least size big
     234           0 :     ShmemBuffer shMemBuff = mShmemPool.Get(this, aProps.bufferSize());
     235             : 
     236           0 :     if (!shMemBuff.Valid()) {
     237           0 :       LOG(("No usable Video shmem in DeliverFrame (out of buffers?)"));
     238             :       // We can skip this frame if we run out of buffers, it's not a real error.
     239           0 :       return 0;
     240             :     }
     241             : 
     242             :     // get() and Size() check for proper alignment of the segment
     243           0 :     memcpy(shMemBuff.GetBytes(), altbuffer, aProps.bufferSize());
     244             : 
     245           0 :     if (!SendDeliverFrame(capEng, aStreamId,
     246           0 :                           shMemBuff.Get(), aProps)) {
     247           0 :       return -1;
     248             :     }
     249             :   } else {
     250           0 :     MOZ_ASSERT(buffer.Valid());
     251             :     // ShmemBuffer was available, we're all good. A single copy happened
     252             :     // in the original webrtc callback.
     253           0 :     if (!SendDeliverFrame(capEng, aStreamId,
     254           0 :                           buffer.Get(), aProps)) {
     255           0 :       return -1;
     256             :     }
     257             :   }
     258             : 
     259           0 :   return 0;
     260             : }
     261             : 
     262             : ShmemBuffer
     263           0 : CamerasParent::GetBuffer(size_t aSize)
     264             : {
     265           0 :   return mShmemPool.GetIfAvailable(aSize);
     266             : }
     267             : 
     268             : void
     269           0 : CallbackHelper::OnFrame(const webrtc::VideoFrame& aVideoFrame)
     270             : {
     271           0 :   LOG_VERBOSE((__PRETTY_FUNCTION__));
     272           0 :   RefPtr<DeliverFrameRunnable> runnable = nullptr;
     273             :   // Get frame properties
     274           0 :   camera::VideoFrameProperties properties;
     275           0 :   VideoFrameUtils::InitFrameBufferProperties(aVideoFrame, properties);
     276             :   // Get a shared memory buffer to copy the frame data into
     277           0 :   ShmemBuffer shMemBuffer = mParent->GetBuffer(properties.bufferSize());
     278           0 :   if (!shMemBuffer.Valid()) {
     279             :     // Either we ran out of buffers or they're not the right size yet
     280           0 :     LOG(("Correctly sized Video shmem not available in DeliverFrame"));
     281             :     // We will do the copy into a(n extra) temporary buffer inside
     282             :     // the DeliverFrameRunnable constructor.
     283             :   } else {
     284             :     // Shared memory buffers of the right size are available, do the copy here.
     285           0 :     VideoFrameUtils::CopyVideoFrameBuffers(shMemBuffer.GetBytes(),
     286           0 :                                            properties.bufferSize(), aVideoFrame);
     287             :     runnable = new DeliverFrameRunnable(mParent, mCapEngine, mStreamId,
     288           0 :                                         Move(shMemBuffer), properties);
     289             :   }
     290           0 :   if (!runnable.get()) {
     291             :     runnable = new DeliverFrameRunnable(mParent, mCapEngine, mStreamId,
     292           0 :                                         aVideoFrame, properties);
     293             :   }
     294           0 :   MOZ_ASSERT(mParent);
     295           0 :   nsIEventTarget* target = mParent->GetBackgroundEventTarget();
     296           0 :   MOZ_ASSERT(target != nullptr);
     297           0 :   target->Dispatch(runnable, NS_DISPATCH_NORMAL);
     298           0 : }
     299             : 
     300             : mozilla::ipc::IPCResult
     301           0 : CamerasParent::RecvReleaseFrame(mozilla::ipc::Shmem&& s) {
     302           0 :   mShmemPool.Put(ShmemBuffer(s));
     303           0 :   return IPC_OK();
     304             : }
     305             : 
     306             : bool
     307           0 : CamerasParent::SetupEngine(CaptureEngine aCapEngine)
     308             : {
     309           0 :   LOG((__PRETTY_FUNCTION__));
     310           0 :   MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
     311           0 :   RefPtr<mozilla::camera::VideoEngine>* engine = &mEngines[aCapEngine];
     312             : 
     313             :   // Already initialized
     314           0 :   if (engine->get()) {
     315           0 :     return true;
     316             :   }
     317             : 
     318           0 :   webrtc::CaptureDeviceInfo *captureDeviceInfo = nullptr;
     319           0 :   UniquePtr<webrtc::Config> config(new webrtc::Config);
     320             : 
     321           0 :   switch (aCapEngine) {
     322             :   case ScreenEngine:
     323           0 :     captureDeviceInfo =
     324           0 :       new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Screen);
     325           0 :     break;
     326             :   case BrowserEngine:
     327           0 :     captureDeviceInfo =
     328           0 :       new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Browser);
     329           0 :     break;
     330             :   case WinEngine:
     331           0 :     captureDeviceInfo =
     332           0 :       new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Window);
     333           0 :     break;
     334             :   case AppEngine:
     335           0 :     captureDeviceInfo =
     336           0 :       new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Application);
     337           0 :     break;
     338             :   case CameraEngine:
     339           0 :     captureDeviceInfo =
     340           0 :       new webrtc::CaptureDeviceInfo(webrtc::CaptureDeviceType::Camera);
     341           0 :     break;
     342             :   default:
     343           0 :     LOG(("Invalid webrtc Video engine"));
     344           0 :     MOZ_CRASH();
     345             :     break;
     346             :   }
     347             : 
     348           0 :   config->Set<webrtc::CaptureDeviceInfo>(captureDeviceInfo);
     349           0 :   *engine = mozilla::camera::VideoEngine::Create(UniquePtr<const webrtc::Config>(config.release()));
     350             : 
     351           0 :   if (!engine->get()) {
     352           0 :     LOG(("VideoEngine::Create failed"));
     353           0 :     return false;
     354             :   }
     355             : 
     356           0 :   RefPtr<InputObserver>* observer = mObservers.AppendElement(new InputObserver(this));
     357           0 :   auto device_info = engine->get()->GetOrCreateVideoCaptureDeviceInfo();
     358           0 :   MOZ_ASSERT(device_info);
     359           0 :   if (device_info) {
     360           0 :     device_info->RegisterVideoInputFeedBack(*(observer->get()));
     361             :   }
     362             : 
     363           0 :   return true;
     364             : }
     365             : 
     366             : void
     367           0 : CamerasParent::CloseEngines()
     368             : {
     369           0 :   LOG((__PRETTY_FUNCTION__));
     370           0 :   if (!mWebRTCAlive) {
     371           0 :     return;
     372             :   }
     373           0 :   MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
     374             : 
     375             :   // Stop the callers
     376           0 :   while (mCallbacks.Length()) {
     377           0 :     auto capEngine = mCallbacks[0]->mCapEngine;
     378           0 :     auto streamNum = mCallbacks[0]->mStreamId;
     379           0 :     LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, streamNum));
     380           0 :     StopCapture(capEngine, streamNum);
     381           0 :     Unused << ReleaseCaptureDevice(capEngine, streamNum);
     382             :   }
     383             : 
     384           0 :   for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
     385           0 :     if (auto engine = mEngines[i].get() ){
     386           0 :       if (engine->IsRunning()) {
     387           0 :         LOG(("Being closed down while engine %d is running!", i));
     388             :       }
     389             : 
     390           0 :       auto device_info = engine->GetOrCreateVideoCaptureDeviceInfo();
     391           0 :       MOZ_ASSERT(device_info);
     392           0 :       if (device_info) {
     393           0 :         device_info->DeRegisterVideoInputFeedBack();
     394             :       }
     395           0 :       mozilla::camera::VideoEngine::Delete(engine);
     396           0 :       mEngines[i] = nullptr;
     397             :     }
     398             :   }
     399             : 
     400             :   // the observers hold references to us
     401           0 :   mObservers.Clear();
     402             : 
     403           0 :   mWebRTCAlive = false;
     404             : }
     405             : 
     406             : VideoEngine *
     407           0 : CamerasParent::EnsureInitialized(int aEngine)
     408             : {
     409           0 :   LOG_VERBOSE((__PRETTY_FUNCTION__));
     410             :   // We're shutting down, don't try to do new WebRTC ops.
     411           0 :   if (!mWebRTCAlive) {
     412           0 :     return nullptr;
     413             :   }
     414           0 :   CaptureEngine capEngine = static_cast<CaptureEngine>(aEngine);
     415           0 :   if (!SetupEngine(capEngine)) {
     416           0 :     LOG(("CamerasParent failed to initialize engine"));
     417           0 :     return nullptr;
     418             :   }
     419             : 
     420           0 :   return mEngines[aEngine];
     421             : }
     422             : 
     423             : // Dispatch the runnable to do the camera operation on the
     424             : // specific Cameras thread, preventing us from blocking, and
     425             : // chain a runnable to send back the result on the IPC thread.
     426             : // It would be nice to get rid of the code duplication here,
     427             : // perhaps via Promises.
     428             : mozilla::ipc::IPCResult
     429           0 : CamerasParent::RecvNumberOfCaptureDevices(const CaptureEngine& aCapEngine)
     430             : {
     431           0 :   LOG((__PRETTY_FUNCTION__));
     432           0 :   LOG(("CaptureEngine=%d", aCapEngine));
     433           0 :   RefPtr<CamerasParent> self(this);
     434             :   RefPtr<Runnable> webrtc_runnable =
     435           0 :     media::NewRunnableFrom([self, aCapEngine]() -> nsresult {
     436           0 :       int num = -1;
     437           0 :       if (auto engine = self->EnsureInitialized(aCapEngine)) {
     438           0 :         if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
     439           0 :           num = devInfo->NumberOfDevices();
     440             :         }
     441             :       }
     442             :       RefPtr<nsIRunnable> ipc_runnable =
     443           0 :         media::NewRunnableFrom([self, num]() -> nsresult {
     444           0 :           if (self->IsShuttingDown()) {
     445           0 :             return NS_ERROR_FAILURE;
     446             :           }
     447           0 :           if (num < 0) {
     448           0 :             LOG(("RecvNumberOfCaptureDevices couldn't find devices"));
     449           0 :             Unused << self->SendReplyFailure();
     450           0 :             return NS_ERROR_FAILURE;
     451             :           } else {
     452           0 :             LOG(("RecvNumberOfCaptureDevices: %d", num));
     453           0 :             Unused << self->SendReplyNumberOfCaptureDevices(num);
     454           0 :             return NS_OK;
     455             :           }
     456           0 :         });
     457           0 :         self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     458           0 :       return NS_OK;
     459           0 :     });
     460           0 :   DispatchToVideoCaptureThread(webrtc_runnable);
     461           0 :   return IPC_OK();
     462             : }
     463             : 
     464             : mozilla::ipc::IPCResult
     465           0 : CamerasParent::RecvEnsureInitialized(const CaptureEngine& aCapEngine)
     466             : {
     467           0 :   LOG((__PRETTY_FUNCTION__));
     468             : 
     469           0 :   RefPtr<CamerasParent> self(this);
     470             :   RefPtr<Runnable> webrtc_runnable =
     471           0 :     media::NewRunnableFrom([self, aCapEngine]() -> nsresult {
     472           0 :       bool result = self->EnsureInitialized(aCapEngine);
     473             : 
     474             :       RefPtr<nsIRunnable> ipc_runnable =
     475           0 :         media::NewRunnableFrom([self, result]() -> nsresult {
     476           0 :           if (self->IsShuttingDown()) {
     477           0 :             return NS_ERROR_FAILURE;
     478             :           }
     479           0 :           if (!result) {
     480           0 :             LOG(("RecvEnsureInitialized failed"));
     481           0 :             Unused << self->SendReplyFailure();
     482           0 :             return NS_ERROR_FAILURE;
     483             :           } else {
     484           0 :             LOG(("RecvEnsureInitialized succeeded"));
     485           0 :             Unused << self->SendReplySuccess();
     486           0 :             return NS_OK;
     487             :           }
     488           0 :         });
     489           0 :         self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     490           0 :       return NS_OK;
     491           0 :     });
     492           0 :   DispatchToVideoCaptureThread(webrtc_runnable);
     493           0 :   return IPC_OK();
     494             : }
     495             : 
     496             : mozilla::ipc::IPCResult
     497           0 : CamerasParent::RecvNumberOfCapabilities(const CaptureEngine& aCapEngine,
     498             :                                         const nsCString& unique_id)
     499             : {
     500           0 :   LOG((__PRETTY_FUNCTION__));
     501           0 :   LOG(("Getting caps for %s", unique_id.get()));
     502             : 
     503           0 :   RefPtr<CamerasParent> self(this);
     504             :   RefPtr<Runnable> webrtc_runnable =
     505           0 :     media::NewRunnableFrom([self, unique_id, aCapEngine]() -> nsresult {
     506           0 :       int num = -1;
     507           0 :       if (auto engine = self->EnsureInitialized(aCapEngine)) {
     508           0 :         if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
     509           0 :           num = devInfo->NumberOfCapabilities(unique_id.get());
     510             :         }
     511             :       }
     512             :       RefPtr<nsIRunnable> ipc_runnable =
     513           0 :         media::NewRunnableFrom([self, num]() -> nsresult {
     514           0 :           if (self->IsShuttingDown()) {
     515           0 :             return NS_ERROR_FAILURE;
     516             :           }
     517           0 :           if (num < 0) {
     518           0 :             LOG(("RecvNumberOfCapabilities couldn't find capabilities"));
     519           0 :             Unused << self->SendReplyFailure();
     520           0 :             return NS_ERROR_FAILURE;
     521             :           } else {
     522           0 :             LOG(("RecvNumberOfCapabilities: %d", num));
     523             :           }
     524           0 :           Unused << self->SendReplyNumberOfCapabilities(num);
     525           0 :           return NS_OK;
     526           0 :         });
     527           0 :       self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     528           0 :       return NS_OK;
     529           0 :     });
     530           0 :   DispatchToVideoCaptureThread(webrtc_runnable);
     531           0 :   return IPC_OK();
     532             : }
     533             : 
     534             : mozilla::ipc::IPCResult
     535           0 : CamerasParent::RecvGetCaptureCapability(const CaptureEngine& aCapEngine,
     536             :                                         const nsCString& unique_id,
     537             :                                         const int& num)
     538             : {
     539           0 :   LOG((__PRETTY_FUNCTION__));
     540           0 :   LOG(("RecvGetCaptureCapability: %s %d", unique_id.get(), num));
     541             : 
     542           0 :   RefPtr<CamerasParent> self(this);
     543             :   RefPtr<Runnable> webrtc_runnable =
     544           0 :     media::NewRunnableFrom([self, unique_id, aCapEngine, num]() -> nsresult {
     545           0 :       webrtc::VideoCaptureCapability webrtcCaps;
     546           0 :       int error = -1;
     547           0 :       if (auto engine = self->EnsureInitialized(aCapEngine)) {
     548           0 :         if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()){
     549           0 :           error = devInfo->GetCapability(unique_id.get(), num, webrtcCaps);
     550             :         }
     551             :       }
     552             :       RefPtr<nsIRunnable> ipc_runnable =
     553           0 :         media::NewRunnableFrom([self, webrtcCaps, error]() -> nsresult {
     554           0 :           if (self->IsShuttingDown()) {
     555           0 :             return NS_ERROR_FAILURE;
     556             :           }
     557             :           VideoCaptureCapability capCap(webrtcCaps.width,
     558             :                                    webrtcCaps.height,
     559             :                                    webrtcCaps.maxFPS,
     560             :                                    webrtcCaps.expectedCaptureDelay,
     561           0 :                                    webrtcCaps.rawType,
     562           0 :                                    webrtcCaps.codecType,
     563           0 :                                    webrtcCaps.interlaced);
     564           0 :           LOG(("Capability: %u %u %u %u %d %d",
     565             :                webrtcCaps.width,
     566             :                webrtcCaps.height,
     567             :                webrtcCaps.maxFPS,
     568             :                webrtcCaps.expectedCaptureDelay,
     569             :                webrtcCaps.rawType,
     570             :                webrtcCaps.codecType));
     571           0 :           if (error) {
     572           0 :             Unused << self->SendReplyFailure();
     573           0 :             return NS_ERROR_FAILURE;
     574             :           }
     575           0 :           Unused << self->SendReplyGetCaptureCapability(capCap);
     576           0 :           return NS_OK;
     577           0 :         });
     578           0 :       self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     579           0 :       return NS_OK;
     580           0 :     });
     581           0 :   DispatchToVideoCaptureThread(webrtc_runnable);
     582           0 :   return IPC_OK();
     583             : }
     584             : 
     585             : mozilla::ipc::IPCResult
     586           0 : CamerasParent::RecvGetCaptureDevice(const CaptureEngine& aCapEngine,
     587             :                                     const int& aListNumber)
     588             : {
     589           0 :   LOG((__PRETTY_FUNCTION__));
     590             : 
     591           0 :   RefPtr<CamerasParent> self(this);
     592             :   RefPtr<Runnable> webrtc_runnable =
     593           0 :     media::NewRunnableFrom([self, aCapEngine, aListNumber]() -> nsresult {
     594             :       char deviceName[MediaEngineSource::kMaxDeviceNameLength];
     595             :       char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength];
     596           0 :       nsCString name;
     597           0 :       nsCString uniqueId;
     598           0 :       pid_t devicePid = 0;
     599           0 :       int error = -1;
     600           0 :       if (auto engine = self->EnsureInitialized(aCapEngine)) {
     601           0 :         if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
     602           0 :           error = devInfo->GetDeviceName(aListNumber, deviceName, sizeof(deviceName),
     603             :                                          deviceUniqueId, sizeof(deviceUniqueId),
     604             :                                          nullptr, 0,
     605           0 :                                          &devicePid);
     606             :         }
     607             :       }
     608           0 :       if (!error) {
     609           0 :         name.Assign(deviceName);
     610           0 :         uniqueId.Assign(deviceUniqueId);
     611             :       }
     612             :       RefPtr<nsIRunnable> ipc_runnable =
     613           0 :         media::NewRunnableFrom([self, error, name, uniqueId, devicePid]() {
     614           0 :           if (self->IsShuttingDown()) {
     615           0 :             return NS_ERROR_FAILURE;
     616             :           }
     617           0 :           if (error) {
     618           0 :             LOG(("GetCaptureDevice failed: %d", error));
     619           0 :             Unused << self->SendReplyFailure();
     620           0 :             return NS_ERROR_FAILURE;
     621             :           }
     622           0 :           bool scary = (devicePid == getpid());
     623             : 
     624           0 :           LOG(("Returning %s name %s id (pid = %d)%s", name.get(),
     625             :                uniqueId.get(), devicePid, (scary? " (scary)" : "")));
     626           0 :           Unused << self->SendReplyGetCaptureDevice(name, uniqueId, scary);
     627           0 :           return NS_OK;
     628           0 :         });
     629           0 :       self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     630           0 :       return NS_OK;
     631           0 :     });
     632           0 :   DispatchToVideoCaptureThread(webrtc_runnable);
     633           0 :   return IPC_OK();
     634             : }
     635             : 
     636             : // Find out whether the given principal has permission to use the
     637             : // camera. If the permission is not persistent, we'll make it
     638             : // a one-shot by removing the (session) permission.
     639             : static bool
     640           0 : HasCameraPermission(const ipc::PrincipalInfo& aPrincipalInfo)
     641             : {
     642           0 :   if (aPrincipalInfo.type() == ipc::PrincipalInfo::TNullPrincipalInfo) {
     643           0 :     return false;
     644             :   }
     645             : 
     646           0 :   if (aPrincipalInfo.type() == ipc::PrincipalInfo::TSystemPrincipalInfo) {
     647           0 :     return true;
     648             :   }
     649             : 
     650           0 :   MOZ_ASSERT(aPrincipalInfo.type() == ipc::PrincipalInfo::TContentPrincipalInfo);
     651             : 
     652             :   nsresult rv;
     653             :   nsCOMPtr<nsIPrincipal> principal =
     654           0 :     PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
     655           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     656           0 :     return false;
     657             :   }
     658             : 
     659             :   // Name used with nsIPermissionManager
     660             :   static const char* cameraPermission = "MediaManagerVideo";
     661             :   nsCOMPtr<nsIPermissionManager> mgr =
     662           0 :     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
     663           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     664           0 :     return false;
     665             :   }
     666             : 
     667           0 :   uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
     668           0 :   rv = mgr->TestExactPermissionFromPrincipal(principal, cameraPermission,
     669           0 :                                              &video);
     670           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     671           0 :     return false;
     672             :   }
     673             : 
     674           0 :   bool allowed = (video == nsIPermissionManager::ALLOW_ACTION);
     675             : 
     676             :   // Session permissions are removed after one use.
     677           0 :   if (allowed) {
     678           0 :     mgr->RemoveFromPrincipal(principal, cameraPermission);
     679             :   }
     680             : 
     681           0 :   return allowed;
     682             : }
     683             : 
     684             : mozilla::ipc::IPCResult
     685           0 : CamerasParent::RecvAllocateCaptureDevice(const CaptureEngine& aCapEngine,
     686             :                                          const nsCString& unique_id,
     687             :                                          const PrincipalInfo& aPrincipalInfo)
     688             : {
     689           0 :   LOG(("%s: Verifying permissions", __PRETTY_FUNCTION__));
     690           0 :   RefPtr<CamerasParent> self(this);
     691             :   RefPtr<Runnable> mainthread_runnable =
     692           0 :     media::NewRunnableFrom([self, aCapEngine, unique_id, aPrincipalInfo]() -> nsresult {
     693             :       // Verify whether the claimed origin has received permission
     694             :       // to use the camera, either persistently or this session (one shot).
     695           0 :       bool allowed = HasCameraPermission(aPrincipalInfo);
     696           0 :       if (!allowed) {
     697             :         // Developer preference for turning off permission check.
     698           0 :         if (Preferences::GetBool("media.navigator.permission.disabled", false)
     699           0 :             || Preferences::GetBool("media.navigator.permission.fake")) {
     700           0 :           allowed = true;
     701           0 :           LOG(("No permission but checks are disabled or fake sources active"));
     702             :         } else {
     703           0 :           LOG(("No camera permission for this origin"));
     704             :         }
     705             :       }
     706             :       // After retrieving the permission (or not) on the main thread,
     707             :       // bounce to the WebRTC thread to allocate the device (or not),
     708             :       // then bounce back to the IPC thread for the reply to content.
     709             :       RefPtr<Runnable> webrtc_runnable =
     710           0 :       media::NewRunnableFrom([self, allowed, aCapEngine, unique_id]() -> nsresult {
     711           0 :         int numdev = -1;
     712           0 :         int error = -1;
     713           0 :         if (allowed && self->EnsureInitialized(aCapEngine)) {
     714           0 :           auto engine = self->mEngines[aCapEngine].get();
     715           0 :           engine->CreateVideoCapture(numdev, unique_id.get());
     716           0 :           engine->WithEntry(numdev, [&error](VideoEngine::CaptureEntry& cap) {
     717           0 :             if (cap.VideoCapture()) {
     718           0 :               error = 0;
     719             :             }
     720           0 :           });
     721             :         }
     722             :         RefPtr<nsIRunnable> ipc_runnable =
     723           0 :           media::NewRunnableFrom([self, numdev, error]() -> nsresult {
     724           0 :             if (self->IsShuttingDown()) {
     725           0 :               return NS_ERROR_FAILURE;
     726             :             }
     727           0 :             if (error) {
     728           0 :               Unused << self->SendReplyFailure();
     729           0 :               return NS_ERROR_FAILURE;
     730             :             } else {
     731           0 :               LOG(("Allocated device nr %d", numdev));
     732           0 :               Unused << self->SendReplyAllocateCaptureDevice(numdev);
     733           0 :               return NS_OK;
     734             :             }
     735           0 :           });
     736           0 :         self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     737           0 :         return NS_OK;
     738           0 :         });
     739           0 :       self->DispatchToVideoCaptureThread(webrtc_runnable);
     740           0 :       return NS_OK;
     741           0 :     });
     742           0 :   NS_DispatchToMainThread(mainthread_runnable);
     743           0 :   return IPC_OK();
     744             : }
     745             : 
     746             : int
     747           0 : CamerasParent::ReleaseCaptureDevice(const CaptureEngine& aCapEngine,
     748             :                                     const int& capnum)
     749             : {
     750           0 :   int error = -1;
     751           0 :   if (auto engine = EnsureInitialized(aCapEngine)) {
     752           0 :     error = engine->ReleaseVideoCapture(capnum);
     753             :   }
     754           0 :   return error;
     755             : }
     756             : 
     757             : mozilla::ipc::IPCResult
     758           0 : CamerasParent::RecvReleaseCaptureDevice(const CaptureEngine& aCapEngine,
     759             :                                         const int& numdev)
     760             : {
     761           0 :   LOG((__PRETTY_FUNCTION__));
     762           0 :   LOG(("RecvReleaseCamera device nr %d", numdev));
     763             : 
     764           0 :   RefPtr<CamerasParent> self(this);
     765             :   RefPtr<Runnable> webrtc_runnable =
     766           0 :     media::NewRunnableFrom([self, aCapEngine, numdev]() -> nsresult {
     767           0 :       int error = self->ReleaseCaptureDevice(aCapEngine, numdev);
     768             :       RefPtr<nsIRunnable> ipc_runnable =
     769           0 :         media::NewRunnableFrom([self, error, numdev]() -> nsresult {
     770           0 :           if (self->IsShuttingDown()) {
     771           0 :             LOG(("In Shutdown, not Releasing"));
     772           0 :             return NS_ERROR_FAILURE;
     773             :           }
     774           0 :           if (error) {
     775           0 :             Unused << self->SendReplyFailure();
     776           0 :             LOG(("Failed to free device nr %d", numdev));
     777           0 :             return NS_ERROR_FAILURE;
     778             :           } else {
     779           0 :             Unused << self->SendReplySuccess();
     780           0 :             LOG(("Freed device nr %d", numdev));
     781           0 :             return NS_OK;
     782             :           }
     783           0 :         });
     784           0 :       self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     785           0 :       return NS_OK;
     786           0 :     });
     787           0 :   DispatchToVideoCaptureThread(webrtc_runnable);
     788           0 :   return IPC_OK();
     789             : }
     790             : 
     791             : mozilla::ipc::IPCResult
     792           0 : CamerasParent::RecvStartCapture(const CaptureEngine& aCapEngine,
     793             :                                 const int& capnum,
     794             :                                 const VideoCaptureCapability& ipcCaps)
     795             : {
     796           0 :   LOG((__PRETTY_FUNCTION__));
     797             : 
     798           0 :   RefPtr<CamerasParent> self(this);
     799             :   RefPtr<Runnable> webrtc_runnable =
     800           0 :     media::NewRunnableFrom([self, aCapEngine, capnum, ipcCaps]() -> nsresult {
     801           0 :       LOG((__PRETTY_FUNCTION__));
     802             :       CallbackHelper** cbh;
     803           0 :       VideoEngine* engine = nullptr;
     804           0 :       int error = -1;
     805           0 :       if (self->EnsureInitialized(aCapEngine)) {
     806           0 :         cbh = self->mCallbacks.AppendElement(
     807           0 :           new CallbackHelper(static_cast<CaptureEngine>(aCapEngine), capnum, self));
     808             : 
     809           0 :         engine = self->mEngines[aCapEngine];
     810           0 :         engine->WithEntry(capnum, [&engine, &error, &ipcCaps, &cbh](VideoEngine::CaptureEntry& cap) {
     811           0 :           error = 0;
     812           0 :           webrtc::VideoCaptureCapability capability;
     813           0 :           capability.width = ipcCaps.width();
     814           0 :           capability.height = ipcCaps.height();
     815           0 :           capability.maxFPS = ipcCaps.maxFPS();
     816           0 :           capability.expectedCaptureDelay = ipcCaps.expectedCaptureDelay();
     817           0 :           capability.rawType = static_cast<webrtc::RawVideoType>(ipcCaps.rawType());
     818           0 :           capability.codecType = static_cast<webrtc::VideoCodecType>(ipcCaps.codecType());
     819           0 :           capability.interlaced = ipcCaps.interlaced();
     820             : 
     821           0 :           if (!error) {
     822           0 :             error = cap.VideoCapture()->StartCapture(capability);
     823             :           }
     824           0 :           if (!error) {
     825           0 :             engine->Startup();
     826           0 :             cap.VideoCapture()->RegisterCaptureDataCallback(static_cast<rtc::VideoSinkInterface<webrtc::VideoFrame>*>(*cbh));
     827             :           }
     828           0 :         });
     829             :       }
     830             :       RefPtr<nsIRunnable> ipc_runnable =
     831           0 :         media::NewRunnableFrom([self, error]() -> nsresult {
     832           0 :           if (self->IsShuttingDown()) {
     833           0 :             return NS_ERROR_FAILURE;
     834             :           }
     835           0 :           if (!error) {
     836           0 :             Unused << self->SendReplySuccess();
     837           0 :             return NS_OK;
     838             :           } else {
     839           0 :             Unused << self->SendReplyFailure();
     840           0 :             return NS_ERROR_FAILURE;
     841             :           }
     842           0 :         });
     843           0 :       self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
     844           0 :       return NS_OK;
     845           0 :     });
     846           0 :   DispatchToVideoCaptureThread(webrtc_runnable);
     847           0 :   return IPC_OK();
     848             : }
     849             : 
     850             : void
     851           0 : CamerasParent::StopCapture(const CaptureEngine& aCapEngine,
     852             :                            const int& capnum)
     853             : {
     854           0 :   if (auto engine = EnsureInitialized(aCapEngine)) {
     855           0 :     engine->WithEntry(capnum,[](VideoEngine::CaptureEntry& cap){
     856           0 :       if (cap.VideoCapture()) {
     857           0 :         cap.VideoCapture()->StopCapture();
     858           0 :         cap.VideoCapture()->DeRegisterCaptureDataCallback();
     859             :       }
     860           0 :     });
     861             :     // we're removing elements, iterate backwards
     862           0 :     for (size_t i = mCallbacks.Length(); i > 0; i--) {
     863           0 :       if (mCallbacks[i-1]->mCapEngine == aCapEngine
     864           0 :           && mCallbacks[i-1]->mStreamId == (uint32_t) capnum) {
     865           0 :         delete mCallbacks[i-1];
     866           0 :         mCallbacks.RemoveElementAt(i-1);
     867           0 :         break;
     868             :       }
     869             :     }
     870           0 :     engine->Shutdown();
     871             :   }
     872           0 : }
     873             : 
     874             : mozilla::ipc::IPCResult
     875           0 : CamerasParent::RecvStopCapture(const CaptureEngine& aCapEngine,
     876             :                                const int& capnum)
     877             : {
     878           0 :   LOG((__PRETTY_FUNCTION__));
     879             : 
     880           0 :   RefPtr<CamerasParent> self(this);
     881             :   RefPtr<Runnable> webrtc_runnable =
     882           0 :     media::NewRunnableFrom([self, aCapEngine, capnum]() -> nsresult {
     883           0 :       self->StopCapture(aCapEngine, capnum);
     884           0 :       return NS_OK;
     885           0 :     });
     886           0 :   nsresult rv = DispatchToVideoCaptureThread(webrtc_runnable);
     887           0 :   if (self->IsShuttingDown()) {
     888           0 :     if (NS_FAILED(rv)) {
     889           0 :       return IPC_FAIL_NO_REASON(this);
     890             :     }
     891             :   } else {
     892           0 :     if (NS_SUCCEEDED(rv)) {
     893           0 :       if (!SendReplySuccess()) {
     894           0 :         return IPC_FAIL_NO_REASON(this);
     895             :       }
     896             :     } else {
     897           0 :       if (!SendReplyFailure()) {
     898           0 :         return IPC_FAIL_NO_REASON(this);
     899             :       }
     900             :     }
     901             :   }
     902           0 :   return IPC_OK();
     903             : }
     904             : 
     905             : void
     906           0 : CamerasParent::StopIPC()
     907             : {
     908           0 :   MOZ_ASSERT(!mDestroyed);
     909             :   // Release shared memory now, it's our last chance
     910           0 :   mShmemPool.Cleanup(this);
     911             :   // We don't want to receive callbacks or anything if we can't
     912             :   // forward them anymore anyway.
     913           0 :   mChildIsAlive = false;
     914           0 :   mDestroyed = true;
     915           0 : }
     916             : 
     917             : mozilla::ipc::IPCResult
     918           0 : CamerasParent::RecvAllDone()
     919             : {
     920           0 :   LOG((__PRETTY_FUNCTION__));
     921             :   // Don't try to send anything to the child now
     922           0 :   mChildIsAlive = false;
     923           0 :   IProtocol* mgr = Manager();
     924           0 :   if (!Send__delete__(this)) {
     925           0 :     return IPC_FAIL_NO_REASON(mgr);
     926             :   }
     927           0 :   return IPC_OK();
     928             : }
     929             : 
     930             : void
     931           0 : CamerasParent::ActorDestroy(ActorDestroyReason aWhy)
     932             : {
     933             :   // No more IPC from here
     934           0 :   LOG((__PRETTY_FUNCTION__));
     935           0 :   StopIPC();
     936             :   // Shut down WebRTC (if we're not in full shutdown, else this
     937             :   // will already have happened)
     938           0 :   StopVideoCapture();
     939           0 : }
     940             : 
     941           0 : CamerasParent::CamerasParent()
     942             :   : mShmemPool(CaptureEngine::MaxEngine),
     943             :     mThreadMonitor("CamerasParent::mThreadMonitor"),
     944             :     mVideoCaptureThread(nullptr),
     945             :     mChildIsAlive(true),
     946             :     mDestroyed(false),
     947           0 :     mWebRTCAlive(true)
     948             : {
     949           0 :   LOG(("CamerasParent: %p", this));
     950             : 
     951           0 :   mPBackgroundEventTarget = GetCurrentThreadSerialEventTarget();
     952           0 :   MOZ_ASSERT(mPBackgroundEventTarget != nullptr,
     953             :              "GetCurrentThreadEventTarget failed");
     954             : 
     955           0 :   LOG(("Spinning up WebRTC Cameras Thread"));
     956             : 
     957           0 :   RefPtr<CamerasParent> self(this);
     958             :   RefPtr<Runnable> threadStart =
     959           0 :     media::NewRunnableFrom([self]() -> nsresult {
     960             :       // Register thread shutdown observer
     961           0 :       nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     962           0 :       if (NS_WARN_IF(!obs)) {
     963           0 :         return NS_ERROR_FAILURE;
     964             :       }
     965             :       nsresult rv =
     966           0 :         obs->AddObserver(self, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
     967           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     968           0 :         return rv;
     969             :       }
     970             :       // Start the thread
     971           0 :       MonitorAutoLock lock(self->mThreadMonitor);
     972           0 :       self->mVideoCaptureThread = new base::Thread("VideoCapture");
     973           0 :       base::Thread::Options options;
     974             : #if defined(_WIN32)
     975             :       options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
     976             : #else
     977             : 
     978           0 :       options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
     979             : #endif
     980           0 :       if (!self->mVideoCaptureThread->StartWithOptions(options)) {
     981           0 :         MOZ_CRASH();
     982             :       }
     983           0 :       self->mThreadMonitor.NotifyAll();
     984           0 :       return NS_OK;
     985           0 :     });
     986           0 :   NS_DispatchToMainThread(threadStart);
     987           0 : }
     988             : 
     989           0 : CamerasParent::~CamerasParent()
     990             : {
     991           0 :   LOG(("~CamerasParent: %p", this));
     992             : 
     993             : #ifdef DEBUG
     994             :   // Verify we have shut down the webrtc engines, this is
     995             :   // supposed to happen in ActorDestroy.
     996             :   // That runnable takes a ref to us, so it must have finished
     997             :   // by the time we get here.
     998           0 :   for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
     999           0 :     MOZ_ASSERT(!mEngines[i]);
    1000             :   }
    1001             : #endif
    1002           0 : }
    1003             : 
    1004             : already_AddRefed<CamerasParent>
    1005           0 : CamerasParent::Create() {
    1006           0 :   mozilla::ipc::AssertIsOnBackgroundThread();
    1007           0 :   RefPtr<CamerasParent> camerasParent = new CamerasParent();
    1008           0 :   return camerasParent.forget();
    1009             : }
    1010             : 
    1011             : }
    1012             : }

Generated by: LCOV version 1.13