/work/obj-fuzz/dist/include/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 | | static OffTheBooksMutex& Mutex() { |
77 | | return Singleton<mozilla::camera::CamerasSingleton>::get()->mCamerasMutex; |
78 | | } |
79 | | |
80 | | static CamerasChild*& Child() { |
81 | | Mutex().AssertCurrentThreadOwns(); |
82 | | return Singleton<mozilla::camera::CamerasSingleton>::get()->mCameras; |
83 | | } |
84 | | |
85 | | static nsCOMPtr<nsIThread>& Thread() { |
86 | | Mutex().AssertCurrentThreadOwns(); |
87 | | return Singleton<mozilla::camera::CamerasSingleton>::get()->mCamerasChildThread; |
88 | | } |
89 | | |
90 | | static nsCOMPtr<nsIThread>& FakeDeviceChangeEventThread() { |
91 | | Mutex().AssertCurrentThreadOwns(); |
92 | | return Singleton<mozilla::camera::CamerasSingleton>::get()->mFakeDeviceChangeEventThread; |
93 | | } |
94 | | |
95 | | static bool InShutdown() { |
96 | | return gTheInstance.get()->mInShutdown; |
97 | | } |
98 | | |
99 | | static void StartShutdown() { |
100 | | gTheInstance.get()->mInShutdown = true; |
101 | | } |
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 | 0 | { |
142 | 0 | OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex()); |
143 | 0 | CamerasChild* child = GetCamerasChild(); |
144 | 0 | if (child) { |
145 | 0 | return (child->*f)(std::forward<ARGS>(args)...); |
146 | 0 | } else { |
147 | 0 | return -1; |
148 | 0 | } |
149 | 0 | } Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::DeviceChangeCallback*), mozilla::MediaEngineWebRTC*>(int (mozilla::camera::CamerasChild::*&&)(mozilla::DeviceChangeCallback*), mozilla::MediaEngineWebRTC*&&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)()>(int (mozilla::camera::CamerasChild::*&&)()) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine), mozilla::camera::CaptureEngine&>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine), mozilla::camera::CaptureEngine&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, unsigned int, char*, unsigned int, char*, unsigned int, bool*), mozilla::camera::CaptureEngine&, int&, char (&) [128], unsigned long, char (&) [256], unsigned long, bool*>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, unsigned int, char*, unsigned int, char*, unsigned int, bool*), mozilla::camera::CaptureEngine&, int&, char (&) [128], unsigned long&&, char (&) [256], unsigned long&&, bool*&&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::DeviceChangeCallback::*)(mozilla::DeviceChangeCallback*), mozilla::MediaEngineWebRTC*>(int (mozilla::DeviceChangeCallback::*&&)(mozilla::DeviceChangeCallback*), mozilla::MediaEngineWebRTC*&&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, unsigned int, char*, unsigned int, char*, unsigned int, bool*), mozilla::camera::CaptureEngine const&, int&, char (&) [128], unsigned int const&, char (&) [256], unsigned int const&, decltype(nullptr)>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, unsigned int, char*, unsigned int, char*, unsigned int, bool*), mozilla::camera::CaptureEngine const&, int&, char (&) [128], unsigned int const&, char (&) [256], unsigned int const&, decltype(nullptr)&&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, char const*, unsigned int, int&, mozilla::ipc::PrincipalInfo const&), mozilla::camera::CaptureEngine const&, char const*, unsigned int const&, int&, mozilla::ipc::PrincipalInfo const&>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, char const*, unsigned int, int&, mozilla::ipc::PrincipalInfo const&), mozilla::camera::CaptureEngine const&, char const*&&, unsigned int const&, int&, mozilla::ipc::PrincipalInfo const&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, int), mozilla::camera::CaptureEngine const&, int&>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, int), mozilla::camera::CaptureEngine const&, int&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, int, webrtc::VideoCaptureCapability&, mozilla::camera::FrameRelay*), mozilla::camera::CaptureEngine const&, int&, webrtc::VideoCaptureCapability&, mozilla::MediaEngineRemoteVideoSource*>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, int, webrtc::VideoCaptureCapability&, mozilla::camera::FrameRelay*), mozilla::camera::CaptureEngine const&, int&, webrtc::VideoCaptureCapability&, mozilla::MediaEngineRemoteVideoSource*&&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, char const*), mozilla::camera::CaptureEngine const&, char const*>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, char const*), mozilla::camera::CaptureEngine const&, char const*&&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, char const*, unsigned int, webrtc::VideoCaptureCapability&), mozilla::camera::CaptureEngine const&, char const*, unsigned long&, webrtc::VideoCaptureCapability&>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, char const*, unsigned int, webrtc::VideoCaptureCapability&), mozilla::camera::CaptureEngine const&, char const*&&, unsigned long&, webrtc::VideoCaptureCapability&) Unexecuted instantiation: int mozilla::camera::GetChildAndCall<int (mozilla::camera::CamerasChild::*)(mozilla::camera::CaptureEngine, unsigned int, char*, unsigned int, char*, unsigned int, bool*), mozilla::camera::CaptureEngine const&, int&, char (&) [128], unsigned long, char (&) [256], unsigned long, decltype(nullptr)>(int (mozilla::camera::CamerasChild::*&&)(mozilla::camera::CaptureEngine, unsigned int, char*, unsigned int, char*, unsigned int, bool*), mozilla::camera::CaptureEngine const&, int&, char (&) [128], unsigned long&&, char (&) [256], unsigned long&&, decltype(nullptr)&&) |
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 |