Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/systemservices/CamerasChild.h
Line
Count
Source (jump to first uncovered line)
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
#ifndef mozilla_CamerasChild_h
8
#define mozilla_CamerasChild_h
9
10
#include "mozilla/Move.h"
11
#include "mozilla/Pair.h"
12
#include "mozilla/dom/ContentChild.h"
13
#include "mozilla/camera/PCamerasChild.h"
14
#include "mozilla/camera/PCamerasParent.h"
15
#include "mozilla/media/DeviceChangeCallback.h"
16
#include "mozilla/Mutex.h"
17
#include "base/singleton.h"
18
#include "nsCOMPtr.h"
19
20
// conflicts with #include of scoped_ptr.h
21
#undef FF
22
#include "webrtc/modules/video_capture/video_capture_defines.h"
23
24
namespace mozilla {
25
26
namespace ipc {
27
class BackgroundChildImpl;
28
class PrincipalInfo;
29
}
30
31
namespace camera {
32
33
class FrameRelay {
34
public:
35
  virtual int DeliverFrame(uint8_t* buffer,
36
    const mozilla::camera::VideoFrameProperties& props) = 0;
37
};
38
39
struct CapturerElement {
40
  CaptureEngine engine;
41
  int id;
42
  FrameRelay* callback;
43
};
44
45
// Forward declaration so we can work with pointers to it.
46
class CamerasChild;
47
// Helper class in impl that we friend.
48
template <class T> class LockAndDispatch;
49
50
// We emulate the sync webrtc.org API with the help of singleton
51
// CamerasSingleton, which manages a pointer to an IPC object, a thread
52
// where IPC operations should run on, and a mutex.
53
// The static function Cameras() will use that Singleton to set up,
54
// if needed, both the thread and the associated IPC objects and return
55
// a pointer to the IPC object. Users can then do IPC calls on that object
56
// after dispatching them to aforementioned thread.
57
58
// 2 Threads are involved in this code:
59
// - the MediaManager thread, which will call the (static, sync API) functions
60
//   through MediaEngineRemoteVideoSource
61
// - the Cameras IPC thread, which will be doing our IPC to the parent process
62
//   via PBackground
63
64
// Our main complication is that we emulate a sync API while (having to do)
65
// async messaging. We dispatch the messages to another thread to send them
66
// async and hold a Monitor to wait for the result to be asynchronously received
67
// again. The requirement for async messaging originates on the parent side:
68
// it's not reasonable to block all PBackground IPC there while waiting for
69
// something like device enumeration to complete.
70
71
class CamerasSingleton {
72
public:
73
  CamerasSingleton();
74
  ~CamerasSingleton();
75
76
0
  static OffTheBooksMutex& Mutex() {
77
0
    return Singleton<mozilla::camera::CamerasSingleton>::get()->mCamerasMutex;
78
0
  }
79
80
0
  static CamerasChild*& Child() {
81
0
    Mutex().AssertCurrentThreadOwns();
82
0
    return Singleton<mozilla::camera::CamerasSingleton>::get()->mCameras;
83
0
  }
84
85
0
  static nsCOMPtr<nsIThread>& Thread() {
86
0
    Mutex().AssertCurrentThreadOwns();
87
0
    return Singleton<mozilla::camera::CamerasSingleton>::get()->mCamerasChildThread;
88
0
  }
89
90
0
  static nsCOMPtr<nsIThread>& FakeDeviceChangeEventThread() {
91
0
    Mutex().AssertCurrentThreadOwns();
92
0
    return Singleton<mozilla::camera::CamerasSingleton>::get()->mFakeDeviceChangeEventThread;
93
0
  }
94
95
0
  static bool InShutdown() {
96
0
    return gTheInstance.get()->mInShutdown;
97
0
  }
98
99
0
  static void StartShutdown() {
100
0
    gTheInstance.get()->mInShutdown = true;
101
0
  }
102
103
private:
104
  static Singleton<CamerasSingleton> gTheInstance;
105
106
  // Reinitializing CamerasChild will change the pointers below.
107
  // We don't want this to happen in the middle of preparing IPC.
108
  // We will be alive on destruction, so this needs to be off the books.
109
  mozilla::OffTheBooksMutex mCamerasMutex;
110
111
  // This is owned by the IPC code, and the same code controls the lifetime.
112
  // It will set and clear this pointer as appropriate in setup/teardown.
113
  // We'd normally make this a WeakPtr but unfortunately the IPC code already
114
  // uses the WeakPtr mixin in a protected base class of CamerasChild, and in
115
  // any case the object becomes unusable as soon as IPC is tearing down, which
116
  // will be before actual destruction.
117
  CamerasChild* mCameras;
118
  nsCOMPtr<nsIThread> mCamerasChildThread;
119
  nsCOMPtr<nsIThread> mFakeDeviceChangeEventThread;
120
  Atomic<bool> mInShutdown;
121
};
122
123
// Get a pointer to a CamerasChild object we can use to do IPC with.
124
// This does everything needed to set up, including starting the IPC
125
// channel with PBackground, blocking until thats done, and starting the
126
// thread to do IPC on. This will fail if we're in shutdown. On success
127
// it will set up the CamerasSingleton.
128
CamerasChild* GetCamerasChild();
129
130
CamerasChild* GetCamerasChildIfExists();
131
132
// Shut down the IPC channel and everything associated, like WebRTC.
133
// This is a static call because the CamerasChild object may not even
134
// be alive when we're called.
135
void Shutdown(void);
136
137
// Obtain the CamerasChild object (if possible, i.e. not shutting down),
138
// and maintain a grip on the object for the duration of the call.
139
template <class MEM_FUN, class... ARGS>
140
int GetChildAndCall(MEM_FUN&& f, ARGS&&... args)
141
{
142
  OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex());
143
  CamerasChild* child = GetCamerasChild();
144
  if (child) {
145
    return (child->*f)(std::forward<ARGS>(args)...);
146
  } else {
147
    return -1;
148
  }
149
}
150
151
class CamerasChild final : public PCamerasChild
152
                          ,public DeviceChangeCallback
153
{
154
  friend class mozilla::ipc::BackgroundChildImpl;
155
  template <class T> friend class mozilla::camera::LockAndDispatch;
156
157
public:
158
  // We are owned by the PBackground thread only. CamerasSingleton
159
  // takes a non-owning reference.
160
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CamerasChild)
161
162
  // IPC messages recevied, received on the PBackground thread
163
  // these are the actual callbacks with data
164
  mozilla::ipc::IPCResult RecvDeliverFrame(const CaptureEngine&, const int&,
165
                                           mozilla::ipc::Shmem&&,
166
                                           const VideoFrameProperties & prop) override;
167
168
  mozilla::ipc::IPCResult RecvDeviceChange() override;
169
  int AddDeviceChangeCallback(DeviceChangeCallback* aCallback) override;
170
  int SetFakeDeviceChangeEvents();
171
172
  // these are response messages to our outgoing requests
173
  mozilla::ipc::IPCResult RecvReplyNumberOfCaptureDevices(const int&) override;
174
  mozilla::ipc::IPCResult RecvReplyNumberOfCapabilities(const int&) override;
175
  mozilla::ipc::IPCResult RecvReplyAllocateCaptureDevice(const int&) override;
176
  mozilla::ipc::IPCResult RecvReplyGetCaptureCapability(const VideoCaptureCapability& capability) override;
177
  mozilla::ipc::IPCResult RecvReplyGetCaptureDevice(const nsCString& device_name,
178
                                                            const nsCString& device_id,
179
                                                            const bool& scary) override;
180
  mozilla::ipc::IPCResult RecvReplyFailure(void) override;
181
  mozilla::ipc::IPCResult RecvReplySuccess(void) override;
182
  void ActorDestroy(ActorDestroyReason aWhy) override;
183
184
  // the webrtc.org ViECapture calls are mirrored here, but with access
185
  // to a specific PCameras instance to communicate over. These also
186
  // run on the MediaManager thread
187
  int NumberOfCaptureDevices(CaptureEngine aCapEngine);
188
  int NumberOfCapabilities(CaptureEngine aCapEngine,
189
                           const char* deviceUniqueIdUTF8);
190
  int ReleaseCaptureDevice(CaptureEngine aCapEngine,
191
                           const int capture_id);
192
  int StartCapture(CaptureEngine aCapEngine,
193
                   const int capture_id, webrtc::VideoCaptureCapability& capability,
194
                   FrameRelay* func);
195
  int FocusOnSelectedSource(CaptureEngine aCapEngine, const int capture_id);
196
  int StopCapture(CaptureEngine aCapEngine, const int capture_id);
197
  int AllocateCaptureDevice(CaptureEngine aCapEngine,
198
                            const char* unique_idUTF8,
199
                            const unsigned int unique_idUTF8Length,
200
                            int& capture_id,
201
                            const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
202
  int GetCaptureCapability(CaptureEngine aCapEngine,
203
                           const char* unique_idUTF8,
204
                           const unsigned int capability_number,
205
                           webrtc::VideoCaptureCapability& capability);
206
  int GetCaptureDevice(CaptureEngine aCapEngine,
207
                       unsigned int list_number, char* device_nameUTF8,
208
                       const unsigned int device_nameUTF8Length,
209
                       char* unique_idUTF8,
210
                       const unsigned int unique_idUTF8Length,
211
                       bool* scary = nullptr);
212
  void ShutdownAll();
213
  int EnsureInitialized(CaptureEngine aCapEngine);
214
215
  FrameRelay* Callback(CaptureEngine aCapEngine, int capture_id);
216
217
private:
218
  CamerasChild();
219
  ~CamerasChild();
220
  // Dispatch a Runnable to the PCamerasParent, by executing it on the
221
  // decidecated Cameras IPC/PBackground thread.
222
  bool DispatchToParent(nsIRunnable* aRunnable,
223
                        MonitorAutoLock& aMonitor);
224
  void AddCallback(const CaptureEngine aCapEngine, const int capture_id,
225
                   FrameRelay* render);
226
  void RemoveCallback(const CaptureEngine aCapEngine, const int capture_id);
227
  void ShutdownParent();
228
  void ShutdownChild();
229
230
  nsTArray<CapturerElement> mCallbacks;
231
  // Protects the callback arrays
232
  Mutex mCallbackMutex;
233
234
  bool mIPCIsAlive;
235
236
  // Hold to prevent multiple outstanding requests. We don't use
237
  // request IDs so we only support one at a time. Don't want try
238
  // to use the webrtc.org API from multiple threads simultanously.
239
  // The monitor below isn't sufficient for this, as it will drop
240
  // the lock when Wait-ing for a response, allowing us to send a new
241
  // request. The Notify on receiving the response will then unblock
242
  // both waiters and one will be guaranteed to get the wrong result.
243
  // Take this one before taking mReplyMonitor.
244
  Mutex mRequestMutex;
245
  // Hold to wait for an async response to our calls
246
  Monitor mReplyMonitor;
247
  // Async response valid?
248
  bool mReceivedReply;
249
  // Async responses data contents;
250
  bool mReplySuccess;
251
  const int mZero;
252
  int mReplyInteger;
253
  webrtc::VideoCaptureCapability mReplyCapability;
254
  nsCString mReplyDeviceName;
255
  nsCString mReplyDeviceID;
256
  bool mReplyScary;
257
};
258
259
} // namespace camera
260
} // namespace mozilla
261
262
#endif  // mozilla_CamerasChild_h