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