LCOV - code coverage report
Current view: top level - dom/media/systemservices - CamerasChild.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 345 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 55 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 "CamerasChild.h"
       8             : 
       9             : #undef FF
      10             : 
      11             : #include "mozilla/Assertions.h"
      12             : #include "mozilla/ipc/BackgroundChild.h"
      13             : #include "mozilla/ipc/PBackgroundChild.h"
      14             : #include "mozilla/Logging.h"
      15             : #include "mozilla/SyncRunnable.h"
      16             : #include "mozilla/WeakPtr.h"
      17             : #include "mozilla/Unused.h"
      18             : #include "MediaUtils.h"
      19             : #include "nsThreadUtils.h"
      20             : 
      21             : #undef LOG
      22             : #undef LOG_ENABLED
      23             : mozilla::LazyLogModule gCamerasChildLog("CamerasChild");
      24             : #define LOG(args) MOZ_LOG(gCamerasChildLog, mozilla::LogLevel::Debug, args)
      25             : #define LOG_ENABLED() MOZ_LOG_TEST(gCamerasChildLog, mozilla::LogLevel::Debug)
      26             : 
      27             : #define FAKE_ONDEVICECHANGE_EVENT_PERIOD_IN_MS 5000
      28             : #define FAKE_ONDEVICECHANGE_EVENT_REPEAT_COUNT 30
      29             : 
      30             : namespace mozilla {
      31             : namespace camera {
      32             : 
      33           0 : CamerasSingleton::CamerasSingleton()
      34             :   : mCamerasMutex("CamerasSingleton::mCamerasMutex"),
      35             :     mCameras(nullptr),
      36             :     mCamerasChildThread(nullptr),
      37           0 :     mFakeDeviceChangeEventThread(nullptr) {
      38           0 :   LOG(("CamerasSingleton: %p", this));
      39           0 : }
      40             : 
      41           0 : CamerasSingleton::~CamerasSingleton() {
      42           0 :   LOG(("~CamerasSingleton: %p", this));
      43           0 : }
      44             : 
      45           0 : class FakeOnDeviceChangeEventRunnable : public Runnable
      46             : {
      47             : public:
      48           0 :   explicit FakeOnDeviceChangeEventRunnable(uint8_t counter)
      49           0 :     : Runnable("camera::FakeOnDeviceChangeEventRunnable")
      50           0 :     , mCounter(counter)
      51             :   {
      52           0 :   }
      53             : 
      54           0 :   NS_IMETHOD Run() override
      55             :   {
      56           0 :     OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex());
      57             : 
      58           0 :     CamerasChild* child = CamerasSingleton::Child();
      59           0 :     if (child) {
      60           0 :       child->OnDeviceChange();
      61             : 
      62           0 :       if (mCounter++ < FAKE_ONDEVICECHANGE_EVENT_REPEAT_COUNT) {
      63           0 :         RefPtr<FakeOnDeviceChangeEventRunnable> evt = new FakeOnDeviceChangeEventRunnable(mCounter);
      64           0 :         CamerasSingleton::FakeDeviceChangeEventThread()->DelayedDispatch(evt.forget(),
      65           0 :           FAKE_ONDEVICECHANGE_EVENT_PERIOD_IN_MS);
      66             :       }
      67             :     }
      68             : 
      69           0 :     return NS_OK;
      70             :   }
      71             : 
      72             : private:
      73             :   uint8_t mCounter;
      74             : };
      75             : 
      76           0 : class InitializeIPCThread : public Runnable
      77             : {
      78             : public:
      79           0 :   InitializeIPCThread()
      80           0 :     : Runnable("camera::InitializeIPCThread")
      81           0 :     , mCamerasChild(nullptr)
      82             :   {
      83           0 :   }
      84             : 
      85           0 :   NS_IMETHOD Run() override {
      86             :     // Try to get the PBackground handle
      87             :     ipc::PBackgroundChild* existingBackgroundChild =
      88           0 :       ipc::BackgroundChild::GetForCurrentThread();
      89             :     // If it's not spun up yet, block until it is, and retry
      90           0 :     if (!existingBackgroundChild) {
      91           0 :       LOG(("No existingBackgroundChild"));
      92             :       existingBackgroundChild =
      93           0 :         ipc::BackgroundChild::SynchronouslyCreateForCurrentThread();
      94           0 :       LOG(("BackgroundChild: %p", existingBackgroundChild));
      95           0 :       if (!existingBackgroundChild) {
      96           0 :         return NS_ERROR_FAILURE;
      97             :       }
      98             :     }
      99             : 
     100             :     // Create CamerasChild
     101             :     // We will be returning the resulting pointer (synchronously) to our caller.
     102           0 :     mCamerasChild =
     103           0 :       static_cast<mozilla::camera::CamerasChild*>(existingBackgroundChild->SendPCamerasConstructor());
     104             : 
     105           0 :     return NS_OK;
     106             :   }
     107             : 
     108           0 :   CamerasChild* GetCamerasChild() {
     109           0 :     return mCamerasChild;
     110             :   }
     111             : 
     112             : private:
     113             :   CamerasChild* mCamerasChild;
     114             : };
     115             : 
     116             : CamerasChild*
     117           0 : GetCamerasChild() {
     118           0 :   CamerasSingleton::Mutex().AssertCurrentThreadOwns();
     119           0 :   if (!CamerasSingleton::Child()) {
     120           0 :     MOZ_ASSERT(!NS_IsMainThread(), "Should not be on the main Thread");
     121           0 :     MOZ_ASSERT(!CamerasSingleton::Thread());
     122           0 :     LOG(("No sCameras, setting up IPC Thread"));
     123           0 :     nsresult rv = NS_NewNamedThread("Cameras IPC",
     124           0 :                                     getter_AddRefs(CamerasSingleton::Thread()));
     125           0 :     if (NS_FAILED(rv)) {
     126           0 :       LOG(("Error launching IPC Thread"));
     127           0 :       return nullptr;
     128             :     }
     129             : 
     130             :     // At this point we are in the MediaManager thread, and the thread we are
     131             :     // dispatching to is the specific Cameras IPC thread that was just made
     132             :     // above, so now we will fire off a runnable to run
     133             :     // BackgroundChild::SynchronouslyCreateForCurrentThread there, while we
     134             :     // block in this thread.
     135             :     // We block until the following happens in the Cameras IPC thread:
     136             :     // 1) Creation of PBackground finishes
     137             :     // 2) Creation of PCameras finishes by sending a message to the parent
     138           0 :     RefPtr<InitializeIPCThread> runnable = new InitializeIPCThread();
     139           0 :     RefPtr<SyncRunnable> sr = new SyncRunnable(runnable);
     140           0 :     sr->DispatchToThread(CamerasSingleton::Thread());
     141           0 :     CamerasSingleton::Child() = runnable->GetCamerasChild();
     142             :   }
     143           0 :   if (!CamerasSingleton::Child()) {
     144           0 :     LOG(("Failed to set up CamerasChild, are we in shutdown?"));
     145             :   }
     146           0 :   return CamerasSingleton::Child();
     147             : }
     148             : 
     149             : CamerasChild*
     150           0 : GetCamerasChildIfExists() {
     151           0 :   OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex());
     152           0 :   return CamerasSingleton::Child();
     153             : }
     154             : 
     155           0 : int CamerasChild::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
     156             : {
     157             :   // According to the spec, if the script sets
     158             :   // navigator.mediaDevices.ondevicechange and the permission state is
     159             :   // "always granted", the User Agent MUST fires a devicechange event when
     160             :   // a new media input device is made available, even the script never
     161             :   // call getusermedia or enumerateDevices.
     162             : 
     163             :   // In order to detect the event, we need to init the camera engine.
     164             :   // Currently EnsureInitialized(aCapEngine) is only called when one of
     165             :   // CamerasaParent api, e.g., RecvNumberOfCaptureDevices(), is called.
     166             : 
     167             :   // So here we setup camera engine via EnsureInitialized(aCapEngine)
     168             : 
     169           0 :   EnsureInitialized(CameraEngine);
     170           0 :   return DeviceChangeCallback::AddDeviceChangeCallback(aCallback);
     171             : }
     172             : 
     173             : mozilla::ipc::IPCResult
     174           0 : CamerasChild::RecvReplyFailure(void)
     175             : {
     176           0 :   LOG((__PRETTY_FUNCTION__));
     177           0 :   MonitorAutoLock monitor(mReplyMonitor);
     178           0 :   mReceivedReply = true;
     179           0 :   mReplySuccess = false;
     180           0 :   monitor.Notify();
     181           0 :   return IPC_OK();
     182             : }
     183             : 
     184             : mozilla::ipc::IPCResult
     185           0 : CamerasChild::RecvReplySuccess(void)
     186             : {
     187           0 :   LOG((__PRETTY_FUNCTION__));
     188           0 :   MonitorAutoLock monitor(mReplyMonitor);
     189           0 :   mReceivedReply = true;
     190           0 :   mReplySuccess = true;
     191           0 :   monitor.Notify();
     192           0 :   return IPC_OK();
     193             : }
     194             : 
     195             : mozilla::ipc::IPCResult
     196           0 : CamerasChild::RecvReplyNumberOfCapabilities(const int& numdev)
     197             : {
     198           0 :   LOG((__PRETTY_FUNCTION__));
     199           0 :   MonitorAutoLock monitor(mReplyMonitor);
     200           0 :   mReceivedReply = true;
     201           0 :   mReplySuccess = true;
     202           0 :   mReplyInteger = numdev;
     203           0 :   monitor.Notify();
     204           0 :   return IPC_OK();
     205             : }
     206             : 
     207             : // Helper function to dispatch calls to the IPC Thread and
     208             : // CamerasChild object. Takes the needed locks and dispatches.
     209             : // Takes a "failed" value and a reference to the output variable
     210             : // as parameters, will return the right one depending on whether
     211             : // dispatching succeeded.
     212             : template <class T = int>
     213           0 : class LockAndDispatch
     214             : {
     215             : public:
     216           0 :   LockAndDispatch(CamerasChild* aCamerasChild,
     217             :                   const char* aRequestingFunc,
     218             :                   nsIRunnable *aRunnable,
     219             :                   const T& aFailureValue = T(-1), const T& aSuccessValue = T(0))
     220             :     : mCamerasChild(aCamerasChild), mRequestingFunc(aRequestingFunc),
     221             :       mRunnable(aRunnable),
     222             :       mReplyLock(aCamerasChild->mReplyMonitor),
     223             :       mRequestLock(aCamerasChild->mRequestMutex),
     224             :       mSuccess(true),
     225           0 :       mFailureValue(aFailureValue), mSuccessValue(aSuccessValue)
     226             :   {
     227           0 :     Dispatch();
     228           0 :   }
     229             : 
     230           0 :   T ReturnValue() const {
     231           0 :     if (mSuccess) {
     232           0 :       return mSuccessValue;
     233             :     } else {
     234           0 :       return mFailureValue;
     235             :     }
     236             :   }
     237             : 
     238           0 :   const bool& Success() const {
     239           0 :     return mSuccess;
     240             :   }
     241             : 
     242             : private:
     243           0 :   void Dispatch() {
     244           0 :     if (!mCamerasChild->DispatchToParent(mRunnable, mReplyLock)) {
     245           0 :       LOG(("Cameras dispatch for IPC failed in %s", mRequestingFunc));
     246           0 :       mSuccess = false;
     247             :     }
     248           0 :   }
     249             : 
     250             :   CamerasChild* mCamerasChild;
     251             :   const char* mRequestingFunc;
     252             :   nsIRunnable* mRunnable;
     253             :   // Prevent concurrent use of the reply variables by holding
     254             :   // the mReplyMonitor. Note that this is unlocked while waiting for
     255             :   // the reply to be filled in, necessitating the additional mRequestLock/Mutex;
     256             :   MonitorAutoLock mReplyLock;
     257             :   MutexAutoLock mRequestLock;
     258             :   bool mSuccess;
     259             :   const T& mFailureValue;
     260             :   const T& mSuccessValue;
     261             : };
     262             : 
     263             : bool
     264           0 : CamerasChild::DispatchToParent(nsIRunnable* aRunnable,
     265             :                                MonitorAutoLock& aMonitor)
     266             : {
     267           0 :   CamerasSingleton::Mutex().AssertCurrentThreadOwns();
     268           0 :   CamerasSingleton::Thread()->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
     269             :   // We can't see if the send worked, so we need to be able to bail
     270             :   // out on shutdown (when it failed and we won't get a reply).
     271           0 :   if (!mIPCIsAlive) {
     272           0 :     return false;
     273             :   }
     274             :   // Guard against spurious wakeups.
     275           0 :   mReceivedReply = false;
     276             :   // Wait for a reply
     277           0 :   do {
     278           0 :     aMonitor.Wait();
     279           0 :   } while (!mReceivedReply && mIPCIsAlive);
     280           0 :   if (!mReplySuccess) {
     281           0 :     return false;
     282             :   }
     283           0 :   return true;
     284             : }
     285             : 
     286             : int
     287           0 : CamerasChild::NumberOfCapabilities(CaptureEngine aCapEngine,
     288             :                                    const char* deviceUniqueIdUTF8)
     289             : {
     290           0 :   LOG((__PRETTY_FUNCTION__));
     291           0 :   LOG(("NumberOfCapabilities for %s", deviceUniqueIdUTF8));
     292           0 :   nsCString unique_id(deviceUniqueIdUTF8);
     293             :   nsCOMPtr<nsIRunnable> runnable =
     294           0 :     mozilla::NewNonOwningRunnableMethod<CaptureEngine, nsCString>(
     295             :       "camera::PCamerasChild::SendNumberOfCapabilities",
     296             :       this,
     297             :       &CamerasChild::SendNumberOfCapabilities,
     298             :       aCapEngine,
     299           0 :       unique_id);
     300           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable, 0, mReplyInteger);
     301           0 :   LOG(("Capture capability count: %d", dispatcher.ReturnValue()));
     302           0 :   return dispatcher.ReturnValue();
     303             : }
     304             : 
     305             : int
     306           0 : CamerasChild::NumberOfCaptureDevices(CaptureEngine aCapEngine)
     307             : {
     308           0 :   LOG((__PRETTY_FUNCTION__));
     309             :   nsCOMPtr<nsIRunnable> runnable =
     310           0 :     mozilla::NewNonOwningRunnableMethod<CaptureEngine>(
     311             :       "camera::PCamerasChild::SendNumberOfCaptureDevices",
     312             :       this,
     313             :       &CamerasChild::SendNumberOfCaptureDevices,
     314           0 :       aCapEngine);
     315           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable, 0, mReplyInteger);
     316           0 :   LOG(("Capture Devices: %d", dispatcher.ReturnValue()));
     317           0 :   return dispatcher.ReturnValue();
     318             : }
     319             : 
     320             : mozilla::ipc::IPCResult
     321           0 : CamerasChild::RecvReplyNumberOfCaptureDevices(const int& numdev)
     322             : {
     323           0 :   LOG((__PRETTY_FUNCTION__));
     324           0 :   MonitorAutoLock monitor(mReplyMonitor);
     325           0 :   mReceivedReply = true;
     326           0 :   mReplySuccess = true;
     327           0 :   mReplyInteger = numdev;
     328           0 :   monitor.Notify();
     329           0 :   return IPC_OK();
     330             : }
     331             : 
     332             : int
     333           0 : CamerasChild::EnsureInitialized(CaptureEngine aCapEngine)
     334             : {
     335           0 :   LOG((__PRETTY_FUNCTION__));
     336             :   nsCOMPtr<nsIRunnable> runnable =
     337           0 :     mozilla::NewNonOwningRunnableMethod<CaptureEngine>(
     338             :       "camera::PCamerasChild::SendEnsureInitialized",
     339             :       this,
     340             :       &CamerasChild::SendEnsureInitialized,
     341           0 :       aCapEngine);
     342           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable, 0, mReplyInteger);
     343           0 :   LOG(("Capture Devices: %d", dispatcher.ReturnValue()));
     344           0 :   return dispatcher.ReturnValue();
     345             : }
     346             : 
     347             : int
     348           0 : CamerasChild::GetCaptureCapability(CaptureEngine aCapEngine,
     349             :                                    const char* unique_idUTF8,
     350             :                                    const unsigned int capability_number,
     351             :                                    webrtc::VideoCaptureCapability& capability)
     352             : {
     353           0 :   LOG(("GetCaptureCapability: %s %d", unique_idUTF8, capability_number));
     354           0 :   nsCString unique_id(unique_idUTF8);
     355             :   nsCOMPtr<nsIRunnable> runnable =
     356           0 :     mozilla::NewNonOwningRunnableMethod<CaptureEngine, nsCString, unsigned int>(
     357             :       "camera::PCamerasChild::SendGetCaptureCapability",
     358             :       this,
     359             :       &CamerasChild::SendGetCaptureCapability,
     360             :       aCapEngine,
     361             :       unique_id,
     362           0 :       capability_number);
     363           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable);
     364           0 :   if (dispatcher.Success()) {
     365           0 :     capability = mReplyCapability;
     366             :   }
     367           0 :   return dispatcher.ReturnValue();
     368             : }
     369             : 
     370             : mozilla::ipc::IPCResult
     371           0 : CamerasChild::RecvReplyGetCaptureCapability(const VideoCaptureCapability& ipcCapability)
     372             : {
     373           0 :   LOG((__PRETTY_FUNCTION__));
     374           0 :   MonitorAutoLock monitor(mReplyMonitor);
     375           0 :   mReceivedReply = true;
     376           0 :   mReplySuccess = true;
     377           0 :   mReplyCapability.width = ipcCapability.width();
     378           0 :   mReplyCapability.height = ipcCapability.height();
     379           0 :   mReplyCapability.maxFPS = ipcCapability.maxFPS();
     380           0 :   mReplyCapability.expectedCaptureDelay = ipcCapability.expectedCaptureDelay();
     381           0 :   mReplyCapability.rawType = static_cast<webrtc::RawVideoType>(ipcCapability.rawType());
     382           0 :   mReplyCapability.codecType = static_cast<webrtc::VideoCodecType>(ipcCapability.codecType());
     383           0 :   mReplyCapability.interlaced = ipcCapability.interlaced();
     384           0 :   monitor.Notify();
     385           0 :   return IPC_OK();
     386             : }
     387             : 
     388             : int
     389           0 : CamerasChild::GetCaptureDevice(CaptureEngine aCapEngine,
     390             :                                unsigned int list_number, char* device_nameUTF8,
     391             :                                const unsigned int device_nameUTF8Length,
     392             :                                char* unique_idUTF8,
     393             :                                const unsigned int unique_idUTF8Length,
     394             :                                bool* scary)
     395             : {
     396           0 :   LOG((__PRETTY_FUNCTION__));
     397             :   nsCOMPtr<nsIRunnable> runnable =
     398           0 :     mozilla::NewNonOwningRunnableMethod<CaptureEngine, unsigned int>(
     399             :       "camera::PCamerasChild::SendGetCaptureDevice",
     400             :       this,
     401             :       &CamerasChild::SendGetCaptureDevice,
     402             :       aCapEngine,
     403           0 :       list_number);
     404           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable);
     405           0 :   if (dispatcher.Success()) {
     406           0 :     base::strlcpy(device_nameUTF8, mReplyDeviceName.get(), device_nameUTF8Length);
     407           0 :     base::strlcpy(unique_idUTF8, mReplyDeviceID.get(), unique_idUTF8Length);
     408           0 :     if (scary) {
     409           0 :       *scary = mReplyScary;
     410             :     }
     411           0 :     LOG(("Got %s name %s id", device_nameUTF8, unique_idUTF8));
     412             :   }
     413           0 :   return dispatcher.ReturnValue();
     414             : }
     415             : 
     416             : mozilla::ipc::IPCResult
     417           0 : CamerasChild::RecvReplyGetCaptureDevice(const nsCString& device_name,
     418             :                                         const nsCString& device_id,
     419             :                                         const bool& scary)
     420             : {
     421           0 :   LOG((__PRETTY_FUNCTION__));
     422           0 :   MonitorAutoLock monitor(mReplyMonitor);
     423           0 :   mReceivedReply = true;
     424           0 :   mReplySuccess = true;
     425           0 :   mReplyDeviceName = device_name;
     426           0 :   mReplyDeviceID = device_id;
     427           0 :   mReplyScary = scary;
     428           0 :   monitor.Notify();
     429           0 :   return IPC_OK();
     430             : }
     431             : 
     432             : int
     433           0 : CamerasChild::AllocateCaptureDevice(CaptureEngine aCapEngine,
     434             :                                     const char* unique_idUTF8,
     435             :                                     const unsigned int unique_idUTF8Length,
     436             :                                     int& aStreamId,
     437             :                                     const mozilla::ipc::PrincipalInfo& aPrincipalInfo)
     438             : {
     439           0 :   LOG((__PRETTY_FUNCTION__));
     440           0 :   nsCString unique_id(unique_idUTF8);
     441             :   nsCOMPtr<nsIRunnable> runnable =
     442             :     mozilla::NewNonOwningRunnableMethod<CaptureEngine,
     443             :                                         nsCString,
     444           0 :                                         const mozilla::ipc::PrincipalInfo&>(
     445             :       "camera::PCamerasChild::SendAllocateCaptureDevice",
     446             :       this,
     447             :       &CamerasChild::SendAllocateCaptureDevice,
     448             :       aCapEngine,
     449             :       unique_id,
     450           0 :       aPrincipalInfo);
     451           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable);
     452           0 :   if (dispatcher.Success()) {
     453           0 :     LOG(("Capture Device allocated: %d", mReplyInteger));
     454           0 :     aStreamId = mReplyInteger;
     455             :   }
     456           0 :   return dispatcher.ReturnValue();
     457             : }
     458             : 
     459             : 
     460             : mozilla::ipc::IPCResult
     461           0 : CamerasChild::RecvReplyAllocateCaptureDevice(const int& numdev)
     462             : {
     463           0 :   LOG((__PRETTY_FUNCTION__));
     464           0 :   MonitorAutoLock monitor(mReplyMonitor);
     465           0 :   mReceivedReply = true;
     466           0 :   mReplySuccess = true;
     467           0 :   mReplyInteger = numdev;
     468           0 :   monitor.Notify();
     469           0 :   return IPC_OK();
     470             : }
     471             : 
     472             : int
     473           0 : CamerasChild::ReleaseCaptureDevice(CaptureEngine aCapEngine,
     474             :                                    const int capture_id)
     475             : {
     476           0 :   LOG((__PRETTY_FUNCTION__));
     477             :   nsCOMPtr<nsIRunnable> runnable =
     478           0 :     mozilla::NewNonOwningRunnableMethod<CaptureEngine, int>(
     479             :       "camera::PCamerasChild::SendReleaseCaptureDevice",
     480             :       this,
     481             :       &CamerasChild::SendReleaseCaptureDevice,
     482             :       aCapEngine,
     483           0 :       capture_id);
     484           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable);
     485           0 :   return dispatcher.ReturnValue();
     486             : }
     487             : 
     488             : void
     489           0 : CamerasChild::AddCallback(const CaptureEngine aCapEngine, const int capture_id,
     490             :                           FrameRelay* render)
     491             : {
     492           0 :   MutexAutoLock lock(mCallbackMutex);
     493             :   CapturerElement ce;
     494           0 :   ce.engine = aCapEngine;
     495           0 :   ce.id = capture_id;
     496           0 :   ce.callback = render;
     497           0 :   mCallbacks.AppendElement(ce);
     498           0 : }
     499             : 
     500             : void
     501           0 : CamerasChild::RemoveCallback(const CaptureEngine aCapEngine, const int capture_id)
     502             : {
     503           0 :   MutexAutoLock lock(mCallbackMutex);
     504           0 :   for (unsigned int i = 0; i < mCallbacks.Length(); i++) {
     505           0 :     CapturerElement ce = mCallbacks[i];
     506           0 :     if (ce.engine == aCapEngine && ce.id == capture_id) {
     507           0 :       mCallbacks.RemoveElementAt(i);
     508           0 :       break;
     509             :     }
     510             :   }
     511           0 : }
     512             : 
     513             : int
     514           0 : CamerasChild::StartCapture(CaptureEngine aCapEngine,
     515             :                            const int capture_id,
     516             :                            webrtc::VideoCaptureCapability& webrtcCaps,
     517             :                            FrameRelay* cb)
     518             : {
     519           0 :   LOG((__PRETTY_FUNCTION__));
     520           0 :   AddCallback(aCapEngine, capture_id, cb);
     521             :   VideoCaptureCapability capCap(webrtcCaps.width,
     522             :                            webrtcCaps.height,
     523             :                            webrtcCaps.maxFPS,
     524             :                            webrtcCaps.expectedCaptureDelay,
     525           0 :                            webrtcCaps.rawType,
     526           0 :                            webrtcCaps.codecType,
     527           0 :                            webrtcCaps.interlaced);
     528             :   nsCOMPtr<nsIRunnable> runnable = mozilla::
     529           0 :     NewNonOwningRunnableMethod<CaptureEngine, int, VideoCaptureCapability>(
     530             :       "camera::PCamerasChild::SendStartCapture",
     531             :       this,
     532             :       &CamerasChild::SendStartCapture,
     533             :       aCapEngine,
     534             :       capture_id,
     535           0 :       capCap);
     536           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable);
     537           0 :   return dispatcher.ReturnValue();
     538             : }
     539             : 
     540             : int
     541           0 : CamerasChild::StopCapture(CaptureEngine aCapEngine, const int capture_id)
     542             : {
     543           0 :   LOG((__PRETTY_FUNCTION__));
     544             :   nsCOMPtr<nsIRunnable> runnable =
     545           0 :     mozilla::NewNonOwningRunnableMethod<CaptureEngine, int>(
     546             :       "camera::PCamerasChild::SendStopCapture",
     547             :       this,
     548             :       &CamerasChild::SendStopCapture,
     549             :       aCapEngine,
     550           0 :       capture_id);
     551           0 :   LockAndDispatch<> dispatcher(this, __func__, runnable);
     552           0 :   if (dispatcher.Success()) {
     553           0 :     RemoveCallback(aCapEngine, capture_id);
     554             :   }
     555           0 :   return dispatcher.ReturnValue();
     556             : }
     557             : 
     558             : void
     559           0 : Shutdown(void)
     560             : {
     561           0 :   OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex());
     562           0 :   CamerasChild* child = CamerasSingleton::Child();
     563           0 :   if (!child) {
     564             :     // We don't want to cause everything to get fired up if we're
     565             :     // really already shut down.
     566           0 :     LOG(("Shutdown when already shut down"));
     567           0 :     return;
     568             :   }
     569           0 :   child->ShutdownAll();
     570             : }
     571             : 
     572           0 : class ShutdownRunnable : public Runnable {
     573             : public:
     574           0 :   explicit ShutdownRunnable(already_AddRefed<Runnable>&& aReplyEvent)
     575           0 :     : Runnable("camera::ShutdownRunnable")
     576           0 :     , mReplyEvent(aReplyEvent){};
     577             : 
     578           0 :   NS_IMETHOD Run() override {
     579           0 :     LOG(("Closing BackgroundChild"));
     580           0 :     ipc::BackgroundChild::CloseForCurrentThread();
     581             : 
     582           0 :     NS_DispatchToMainThread(mReplyEvent.forget());
     583             : 
     584           0 :     return NS_OK;
     585             :   }
     586             : 
     587             : private:
     588             :   RefPtr<Runnable> mReplyEvent;
     589             : };
     590             : 
     591             : void
     592           0 : CamerasChild::ShutdownAll()
     593             : {
     594             :   // Called with CamerasSingleton::Mutex() held
     595           0 :   ShutdownParent();
     596           0 :   ShutdownChild();
     597           0 : }
     598             : 
     599             : void
     600           0 : CamerasChild::ShutdownParent()
     601             : {
     602             :   // Called with CamerasSingleton::Mutex() held
     603             :   {
     604           0 :     MonitorAutoLock monitor(mReplyMonitor);
     605           0 :     mIPCIsAlive = false;
     606           0 :     monitor.NotifyAll();
     607             :   }
     608           0 :   if (CamerasSingleton::Thread()) {
     609           0 :     LOG(("Dispatching actor deletion"));
     610             :     // Delete the parent actor.
     611             :     // CamerasChild (this) will remain alive and is only deleted by the
     612             :     // IPC layer when SendAllDone returns.
     613           0 :     nsCOMPtr<nsIRunnable> deleteRunnable = mozilla::NewNonOwningRunnableMethod(
     614           0 :       "camera::PCamerasChild::SendAllDone", this, &CamerasChild::SendAllDone);
     615           0 :     CamerasSingleton::Thread()->Dispatch(deleteRunnable, NS_DISPATCH_NORMAL);
     616             :   } else {
     617           0 :     LOG(("ShutdownParent called without PBackground thread"));
     618             :   }
     619           0 : }
     620             : 
     621             : void
     622           0 : CamerasChild::ShutdownChild()
     623             : {
     624             :   // Called with CamerasSingleton::Mutex() held
     625           0 :   if (CamerasSingleton::Thread()) {
     626           0 :     LOG(("PBackground thread exists, dispatching close"));
     627             :     // Dispatch closing the IPC thread back to us when the
     628             :     // BackgroundChild is closed.
     629           0 :     RefPtr<ShutdownRunnable> runnable = new ShutdownRunnable(NewRunnableMethod(
     630           0 :       "nsIThread::Shutdown", CamerasSingleton::Thread(), &nsIThread::Shutdown));
     631           0 :     CamerasSingleton::Thread()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
     632             :   } else {
     633           0 :     LOG(("Shutdown called without PBackground thread"));
     634             :   }
     635           0 :   LOG(("Erasing sCameras & thread refs (original thread)"));
     636           0 :   CamerasSingleton::Child() = nullptr;
     637           0 :   CamerasSingleton::Thread() = nullptr;
     638             : 
     639           0 :   if (CamerasSingleton::FakeDeviceChangeEventThread()) {
     640             :     RefPtr<ShutdownRunnable> runnable = new ShutdownRunnable(
     641           0 :       NewRunnableMethod("nsIThread::Shutdown",
     642             :                         CamerasSingleton::FakeDeviceChangeEventThread(),
     643           0 :                         &nsIThread::Shutdown));
     644           0 :     CamerasSingleton::FakeDeviceChangeEventThread()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
     645             :   }
     646           0 :   CamerasSingleton::FakeDeviceChangeEventThread() = nullptr;
     647           0 : }
     648             : 
     649             : mozilla::ipc::IPCResult
     650           0 : CamerasChild::RecvDeliverFrame(const CaptureEngine& capEngine,
     651             :                                const int& capId,
     652             :                                mozilla::ipc::Shmem&& shmem,
     653             :                                const VideoFrameProperties & prop)
     654             : {
     655           0 :   MutexAutoLock lock(mCallbackMutex);
     656           0 :   if (Callback(capEngine, capId)) {
     657           0 :     unsigned char* image = shmem.get<unsigned char>();
     658           0 :     Callback(capEngine, capId)->DeliverFrame(image, prop);
     659             :   } else {
     660           0 :     LOG(("DeliverFrame called with dead callback"));
     661             :   }
     662           0 :   SendReleaseFrame(shmem);
     663           0 :   return IPC_OK();
     664             : }
     665             : 
     666             : mozilla::ipc::IPCResult
     667           0 : CamerasChild::RecvDeviceChange()
     668             : {
     669           0 :   this->OnDeviceChange();
     670           0 :   return IPC_OK();
     671             : }
     672             : 
     673             : int
     674           0 : CamerasChild::SetFakeDeviceChangeEvents()
     675             : {
     676           0 :   CamerasSingleton::Mutex().AssertCurrentThreadOwns();
     677             : 
     678           0 :   if(!CamerasSingleton::FakeDeviceChangeEventThread()) {
     679           0 :     nsresult rv = NS_NewNamedThread("Fake DC Event",
     680           0 :                                     getter_AddRefs(CamerasSingleton::FakeDeviceChangeEventThread()));
     681           0 :     if (NS_FAILED(rv)) {
     682           0 :       LOG(("Error launching Fake OnDeviceChange Event Thread"));
     683           0 :       return -1;
     684             :     }
     685             :   }
     686             : 
     687             :   // To simulate the devicechange event in mochitest,
     688             :   // we fire a fake devicechange event in Camera IPC thread periodically
     689           0 :   RefPtr<FakeOnDeviceChangeEventRunnable> evt = new FakeOnDeviceChangeEventRunnable(0);
     690           0 :   CamerasSingleton::FakeDeviceChangeEventThread()->Dispatch(evt.forget(), NS_DISPATCH_NORMAL);
     691             : 
     692           0 :   return 0;
     693             : }
     694             : 
     695             : mozilla::ipc::IPCResult
     696           0 : CamerasChild::RecvFrameSizeChange(const CaptureEngine& capEngine,
     697             :                                   const int& capId,
     698             :                                   const int& w, const int& h)
     699             : {
     700           0 :   LOG((__PRETTY_FUNCTION__));
     701           0 :   MutexAutoLock lock(mCallbackMutex);
     702           0 :   if (Callback(capEngine, capId)) {
     703           0 :     Callback(capEngine, capId)->FrameSizeChange(w, h);
     704             :   } else {
     705           0 :     LOG(("Frame size change with dead callback"));
     706             :   }
     707           0 :   return IPC_OK();
     708             : }
     709             : 
     710             : void
     711           0 : CamerasChild::ActorDestroy(ActorDestroyReason aWhy)
     712             : {
     713           0 :   MonitorAutoLock monitor(mReplyMonitor);
     714           0 :   mIPCIsAlive = false;
     715             :   // Hopefully prevent us from getting stuck
     716             :   // on replies that'll never come.
     717           0 :   monitor.NotifyAll();
     718           0 : }
     719             : 
     720           0 : CamerasChild::CamerasChild()
     721             :   : mCallbackMutex("mozilla::cameras::CamerasChild::mCallbackMutex"),
     722             :     mIPCIsAlive(true),
     723             :     mRequestMutex("mozilla::cameras::CamerasChild::mRequestMutex"),
     724           0 :     mReplyMonitor("mozilla::cameras::CamerasChild::mReplyMonitor")
     725             : {
     726           0 :   LOG(("CamerasChild: %p", this));
     727             : 
     728           0 :   MOZ_COUNT_CTOR(CamerasChild);
     729           0 : }
     730             : 
     731           0 : CamerasChild::~CamerasChild()
     732             : {
     733           0 :   LOG(("~CamerasChild: %p", this));
     734             : 
     735             :   {
     736           0 :     OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex());
     737             :     // In normal circumstances we've already shut down and the
     738             :     // following does nothing. But on fatal IPC errors we will
     739             :     // get destructed immediately, and should not try to reach
     740             :     // the parent.
     741           0 :     ShutdownChild();
     742             :   }
     743             : 
     744           0 :   MOZ_COUNT_DTOR(CamerasChild);
     745           0 : }
     746             : 
     747           0 : FrameRelay* CamerasChild::Callback(CaptureEngine aCapEngine,
     748             :                                                  int capture_id)
     749             : {
     750           0 :   for (unsigned int i = 0; i < mCallbacks.Length(); i++) {
     751           0 :     CapturerElement ce = mCallbacks[i];
     752           0 :     if (ce.engine == aCapEngine && ce.id == capture_id) {
     753           0 :       return ce.callback;
     754             :     }
     755             :   }
     756             : 
     757           0 :   return nullptr;
     758             : }
     759             : 
     760             : }
     761             : }

Generated by: LCOV version 1.13