|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "MediaManager.h" |
|
6 #include "MediaPermissionGonk.h" |
|
7 |
|
8 #include "nsCOMPtr.h" |
|
9 #include "nsCxPusher.h" |
|
10 #include "nsIContentPermissionPrompt.h" |
|
11 #include "nsIDocument.h" |
|
12 #include "nsIDOMNavigatorUserMedia.h" |
|
13 #include "nsIStringEnumerator.h" |
|
14 #include "nsISupportsArray.h" |
|
15 #include "nsJSUtils.h" |
|
16 #include "nsPIDOMWindow.h" |
|
17 #include "nsTArray.h" |
|
18 #include "GetUserMediaRequest.h" |
|
19 #include "PCOMContentPermissionRequestChild.h" |
|
20 #include "mozilla/dom/PBrowserChild.h" |
|
21 #include "mozilla/dom/TabChild.h" |
|
22 #include "mozilla/dom/MediaStreamTrackBinding.h" |
|
23 #include "nsISupportsPrimitives.h" |
|
24 #include "nsServiceManagerUtils.h" |
|
25 #include "nsArrayUtils.h" |
|
26 #include "nsContentPermissionHelper.h" |
|
27 #include "mozilla/dom/PermissionMessageUtils.h" |
|
28 |
|
29 #define AUDIO_PERMISSION_NAME "audio-capture" |
|
30 #define VIDEO_PERMISSION_NAME "video-capture" |
|
31 |
|
32 using namespace mozilla::dom; |
|
33 |
|
34 namespace mozilla { |
|
35 |
|
36 static MediaPermissionManager *gMediaPermMgr = nullptr; |
|
37 |
|
38 static uint32_t |
|
39 ConvertArrayToPermissionRequest(nsIArray* aSrcArray, |
|
40 nsTArray<PermissionRequest>& aDesArray) |
|
41 { |
|
42 uint32_t len = 0; |
|
43 aSrcArray->GetLength(&len); |
|
44 for (uint32_t i = 0; i < len; i++) { |
|
45 nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i); |
|
46 nsAutoCString type; |
|
47 nsAutoCString access; |
|
48 cpt->GetType(type); |
|
49 cpt->GetAccess(access); |
|
50 |
|
51 nsCOMPtr<nsIArray> optionArray; |
|
52 cpt->GetOptions(getter_AddRefs(optionArray)); |
|
53 uint32_t optionsLength = 0; |
|
54 optionArray->GetLength(&optionsLength); |
|
55 nsTArray<nsString> options; |
|
56 for (uint32_t j = 0; j < optionsLength; ++j) { |
|
57 nsCOMPtr<nsISupportsString> isupportsString = do_QueryElementAt(optionArray, j); |
|
58 if (isupportsString) { |
|
59 nsString option; |
|
60 isupportsString->GetData(option); |
|
61 options.AppendElement(option); |
|
62 } |
|
63 } |
|
64 |
|
65 aDesArray.AppendElement(PermissionRequest(type, access, options)); |
|
66 } |
|
67 return len; |
|
68 } |
|
69 |
|
70 static void |
|
71 CreateDeviceNameList(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices, |
|
72 nsTArray<nsString> &aDeviceNameList) |
|
73 { |
|
74 for (uint32_t i = 0; i < aDevices.Length(); ++i) { |
|
75 nsString name; |
|
76 nsresult rv = aDevices[i]->GetName(name); |
|
77 NS_ENSURE_SUCCESS_VOID(rv); |
|
78 aDeviceNameList.AppendElement(name); |
|
79 } |
|
80 } |
|
81 |
|
82 static already_AddRefed<nsIMediaDevice> |
|
83 FindDeviceByName(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices, |
|
84 const nsAString &aDeviceName) |
|
85 { |
|
86 for (uint32_t i = 0; i < aDevices.Length(); ++i) { |
|
87 nsCOMPtr<nsIMediaDevice> device = aDevices[i]; |
|
88 nsString deviceName; |
|
89 device->GetName(deviceName); |
|
90 if (deviceName.Equals(aDeviceName)) { |
|
91 return device.forget(); |
|
92 } |
|
93 } |
|
94 |
|
95 return nullptr; |
|
96 } |
|
97 |
|
98 // Helper function for notifying permission granted |
|
99 static nsresult |
|
100 NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices) |
|
101 { |
|
102 nsresult rv; |
|
103 nsCOMPtr<nsISupportsArray> array; |
|
104 rv = NS_NewISupportsArray(getter_AddRefs(array)); |
|
105 NS_ENSURE_SUCCESS(rv, rv); |
|
106 |
|
107 for (uint32_t i = 0; i < aDevices.Length(); ++i) { |
|
108 rv = array->AppendElement(aDevices.ElementAt(i)); |
|
109 NS_ENSURE_SUCCESS(rv, rv); |
|
110 } |
|
111 |
|
112 nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
|
113 NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); |
|
114 |
|
115 return obs->NotifyObservers(array, "getUserMedia:response:allow", |
|
116 aCallID.BeginReading()); |
|
117 } |
|
118 |
|
119 // Helper function for notifying permision denial or error |
|
120 static nsresult |
|
121 NotifyPermissionDeny(const nsAString &aCallID, const nsAString &aErrorMsg) |
|
122 { |
|
123 nsresult rv; |
|
124 nsCOMPtr<nsISupportsString> supportsString = |
|
125 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); |
|
126 NS_ENSURE_SUCCESS(rv, rv); |
|
127 |
|
128 rv = supportsString->SetData(aErrorMsg); |
|
129 NS_ENSURE_SUCCESS(rv, rv); |
|
130 |
|
131 nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
|
132 NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); |
|
133 |
|
134 return obs->NotifyObservers(supportsString, "getUserMedia:response:deny", |
|
135 aCallID.BeginReading()); |
|
136 } |
|
137 |
|
138 namespace { |
|
139 |
|
140 /** |
|
141 * MediaPermissionRequest will send a prompt ipdl request to b2g process according |
|
142 * to its owned type. |
|
143 */ |
|
144 class MediaPermissionRequest : public nsIContentPermissionRequest |
|
145 , public PCOMContentPermissionRequestChild |
|
146 { |
|
147 public: |
|
148 NS_DECL_ISUPPORTS |
|
149 NS_DECL_NSICONTENTPERMISSIONREQUEST |
|
150 |
|
151 MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest> &aRequest, |
|
152 nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices); |
|
153 virtual ~MediaPermissionRequest() {} |
|
154 |
|
155 // It will be called when prompt dismissed. |
|
156 virtual bool Recv__delete__(const bool &allow, |
|
157 const InfallibleTArray<PermissionChoice>& choices) MOZ_OVERRIDE; |
|
158 virtual void IPDLRelease() MOZ_OVERRIDE { Release(); } |
|
159 |
|
160 already_AddRefed<nsPIDOMWindow> GetOwner(); |
|
161 |
|
162 private: |
|
163 nsresult DoAllow(const nsString &audioDevice, const nsString &videoDevice); |
|
164 |
|
165 bool mAudio; // Request for audio permission |
|
166 bool mVideo; // Request for video permission |
|
167 nsRefPtr<dom::GetUserMediaRequest> mRequest; |
|
168 nsTArray<nsCOMPtr<nsIMediaDevice> > mAudioDevices; // candidate audio devices |
|
169 nsTArray<nsCOMPtr<nsIMediaDevice> > mVideoDevices; // candidate video devices |
|
170 }; |
|
171 |
|
172 // MediaPermissionRequest |
|
173 NS_IMPL_ISUPPORTS(MediaPermissionRequest, nsIContentPermissionRequest) |
|
174 |
|
175 MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest> &aRequest, |
|
176 nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices) |
|
177 : mRequest(aRequest) |
|
178 { |
|
179 dom::MediaStreamConstraints constraints; |
|
180 mRequest->GetConstraints(constraints); |
|
181 |
|
182 mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean(); |
|
183 mVideo = !constraints.mVideo.IsBoolean() || constraints.mVideo.GetAsBoolean(); |
|
184 |
|
185 for (uint32_t i = 0; i < aDevices.Length(); ++i) { |
|
186 nsCOMPtr<nsIMediaDevice> device(aDevices[i]); |
|
187 nsAutoString deviceType; |
|
188 device->GetType(deviceType); |
|
189 if (mAudio && deviceType.EqualsLiteral("audio")) { |
|
190 mAudioDevices.AppendElement(device); |
|
191 } |
|
192 if (mVideo && deviceType.EqualsLiteral("video")) { |
|
193 mVideoDevices.AppendElement(device); |
|
194 } |
|
195 } |
|
196 } |
|
197 |
|
198 // nsIContentPermissionRequest methods |
|
199 NS_IMETHODIMP |
|
200 MediaPermissionRequest::GetTypes(nsIArray** aTypes) |
|
201 { |
|
202 nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID); |
|
203 //XXX append device list |
|
204 if (mAudio) { |
|
205 nsTArray<nsString> audioDeviceNames; |
|
206 CreateDeviceNameList(mAudioDevices, audioDeviceNames); |
|
207 nsCOMPtr<nsISupports> AudioType = |
|
208 new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME), |
|
209 NS_LITERAL_CSTRING("unused"), |
|
210 audioDeviceNames); |
|
211 types->AppendElement(AudioType, false); |
|
212 } |
|
213 if (mVideo) { |
|
214 nsTArray<nsString> videoDeviceNames; |
|
215 CreateDeviceNameList(mVideoDevices, videoDeviceNames); |
|
216 nsCOMPtr<nsISupports> VideoType = |
|
217 new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME), |
|
218 NS_LITERAL_CSTRING("unused"), |
|
219 videoDeviceNames); |
|
220 types->AppendElement(VideoType, false); |
|
221 } |
|
222 NS_IF_ADDREF(*aTypes = types); |
|
223 |
|
224 return NS_OK; |
|
225 } |
|
226 |
|
227 NS_IMETHODIMP |
|
228 MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) |
|
229 { |
|
230 NS_ENSURE_ARG_POINTER(aRequestingPrincipal); |
|
231 |
|
232 nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*> |
|
233 (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())); |
|
234 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); |
|
235 |
|
236 nsCOMPtr<nsIDocument> doc = window->GetExtantDoc(); |
|
237 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
|
238 |
|
239 NS_ADDREF(*aRequestingPrincipal = doc->NodePrincipal()); |
|
240 return NS_OK; |
|
241 } |
|
242 |
|
243 NS_IMETHODIMP |
|
244 MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow) |
|
245 { |
|
246 NS_ENSURE_ARG_POINTER(aRequestingWindow); |
|
247 nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*> |
|
248 (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())); |
|
249 window.forget(aRequestingWindow); |
|
250 return NS_OK; |
|
251 } |
|
252 |
|
253 NS_IMETHODIMP |
|
254 MediaPermissionRequest::GetElement(nsIDOMElement** aRequestingElement) |
|
255 { |
|
256 NS_ENSURE_ARG_POINTER(aRequestingElement); |
|
257 *aRequestingElement = nullptr; |
|
258 return NS_OK; |
|
259 } |
|
260 |
|
261 NS_IMETHODIMP |
|
262 MediaPermissionRequest::Cancel() |
|
263 { |
|
264 nsString callID; |
|
265 mRequest->GetCallID(callID); |
|
266 NotifyPermissionDeny(callID, NS_LITERAL_STRING("Permission Denied")); |
|
267 return NS_OK; |
|
268 } |
|
269 |
|
270 NS_IMETHODIMP |
|
271 MediaPermissionRequest::Allow(JS::HandleValue aChoices) |
|
272 { |
|
273 // check if JS object |
|
274 if (!aChoices.isObject()) { |
|
275 MOZ_ASSERT(false, "Not a correct format of PermissionChoice"); |
|
276 return NS_ERROR_INVALID_ARG; |
|
277 } |
|
278 // iterate through audio-capture and video-capture |
|
279 AutoSafeJSContext cx; |
|
280 JS::Rooted<JSObject*> obj(cx, &aChoices.toObject()); |
|
281 JSAutoCompartment ac(cx, obj); |
|
282 JS::Rooted<JS::Value> v(cx); |
|
283 |
|
284 // get selected audio device name |
|
285 nsString audioDevice; |
|
286 if (mAudio) { |
|
287 if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) { |
|
288 return NS_ERROR_FAILURE; |
|
289 } |
|
290 nsDependentJSString deviceName; |
|
291 if (!deviceName.init(cx, v)) { |
|
292 MOZ_ASSERT(false, "Couldn't initialize string from aChoices"); |
|
293 return NS_ERROR_FAILURE; |
|
294 } |
|
295 audioDevice = deviceName; |
|
296 } |
|
297 |
|
298 // get selected video device name |
|
299 nsString videoDevice; |
|
300 if (mVideo) { |
|
301 if (!JS_GetProperty(cx, obj, VIDEO_PERMISSION_NAME, &v) || !v.isString()) { |
|
302 return NS_ERROR_FAILURE; |
|
303 } |
|
304 nsDependentJSString deviceName; |
|
305 if (!deviceName.init(cx, v)) { |
|
306 MOZ_ASSERT(false, "Couldn't initialize string from aChoices"); |
|
307 return NS_ERROR_FAILURE; |
|
308 } |
|
309 videoDevice = deviceName; |
|
310 } |
|
311 |
|
312 return DoAllow(audioDevice, videoDevice); |
|
313 } |
|
314 |
|
315 nsresult |
|
316 MediaPermissionRequest::DoAllow(const nsString &audioDevice, |
|
317 const nsString &videoDevice) |
|
318 { |
|
319 nsTArray<nsCOMPtr<nsIMediaDevice> > selectedDevices; |
|
320 if (mAudio) { |
|
321 nsCOMPtr<nsIMediaDevice> device = |
|
322 FindDeviceByName(mAudioDevices, audioDevice); |
|
323 if (device) { |
|
324 selectedDevices.AppendElement(device); |
|
325 } |
|
326 } |
|
327 |
|
328 if (mVideo) { |
|
329 nsCOMPtr<nsIMediaDevice> device = |
|
330 FindDeviceByName(mVideoDevices, videoDevice); |
|
331 if (device) { |
|
332 selectedDevices.AppendElement(device); |
|
333 } |
|
334 } |
|
335 |
|
336 nsString callID; |
|
337 mRequest->GetCallID(callID); |
|
338 return NotifyPermissionAllow(callID, selectedDevices); |
|
339 } |
|
340 |
|
341 already_AddRefed<nsPIDOMWindow> |
|
342 MediaPermissionRequest::GetOwner() |
|
343 { |
|
344 nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*> |
|
345 (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())); |
|
346 return window.forget(); |
|
347 } |
|
348 |
|
349 //PCOMContentPermissionRequestChild |
|
350 bool |
|
351 MediaPermissionRequest::Recv__delete__(const bool& allow, |
|
352 const InfallibleTArray<PermissionChoice>& choices) |
|
353 { |
|
354 if (allow) { |
|
355 // get selected device name for audio and video |
|
356 nsString audioDevice, videoDevice; |
|
357 for (uint32_t i = 0; i < choices.Length(); ++i) { |
|
358 const nsString &choice = choices[i].choice(); |
|
359 if (choices[i].type().EqualsLiteral(AUDIO_PERMISSION_NAME)) { |
|
360 audioDevice = choice; |
|
361 } else if (choices[i].type().EqualsLiteral(VIDEO_PERMISSION_NAME)) { |
|
362 videoDevice = choice; |
|
363 } |
|
364 } |
|
365 (void) DoAllow(audioDevice, videoDevice); |
|
366 } else { |
|
367 (void) Cancel(); |
|
368 } |
|
369 return true; |
|
370 } |
|
371 |
|
372 // Success callback for MediaManager::GetUserMediaDevices(). |
|
373 class MediaDeviceSuccessCallback: public nsIGetUserMediaDevicesSuccessCallback |
|
374 { |
|
375 public: |
|
376 NS_DECL_ISUPPORTS |
|
377 NS_DECL_NSIGETUSERMEDIADEVICESSUCCESSCALLBACK |
|
378 |
|
379 MediaDeviceSuccessCallback(nsRefPtr<dom::GetUserMediaRequest> &aRequest) |
|
380 : mRequest(aRequest) {} |
|
381 virtual ~MediaDeviceSuccessCallback() {} |
|
382 |
|
383 private: |
|
384 nsresult DoPrompt(nsRefPtr<MediaPermissionRequest> &req); |
|
385 nsRefPtr<dom::GetUserMediaRequest> mRequest; |
|
386 }; |
|
387 |
|
388 NS_IMPL_ISUPPORTS(MediaDeviceSuccessCallback, nsIGetUserMediaDevicesSuccessCallback) |
|
389 |
|
390 // nsIGetUserMediaDevicesSuccessCallback method |
|
391 NS_IMETHODIMP |
|
392 MediaDeviceSuccessCallback::OnSuccess(nsIVariant* aDevices) |
|
393 { |
|
394 nsIID elementIID; |
|
395 uint16_t elementType; |
|
396 void* rawArray; |
|
397 uint32_t arrayLen; |
|
398 |
|
399 nsresult rv; |
|
400 rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray); |
|
401 NS_ENSURE_SUCCESS(rv, rv); |
|
402 |
|
403 if (elementType != nsIDataType::VTYPE_INTERFACE) { |
|
404 NS_Free(rawArray); |
|
405 return NS_ERROR_FAILURE; |
|
406 } |
|
407 |
|
408 // Create array for nsIMediaDevice |
|
409 nsTArray<nsCOMPtr<nsIMediaDevice> > devices; |
|
410 |
|
411 nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray); |
|
412 for (uint32_t i = 0; i < arrayLen; ++i) { |
|
413 nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i])); |
|
414 devices.AppendElement(device); |
|
415 NS_IF_RELEASE(supportsArray[i]); // explicitly decrease reference count for raw pointer |
|
416 } |
|
417 NS_Free(rawArray); // explicitly free for the memory from nsIVariant::GetAsArray |
|
418 |
|
419 // Send MediaPermissionRequest |
|
420 nsRefPtr<MediaPermissionRequest> req = new MediaPermissionRequest(mRequest, devices); |
|
421 rv = DoPrompt(req); |
|
422 |
|
423 NS_ENSURE_SUCCESS(rv, rv); |
|
424 return NS_OK; |
|
425 } |
|
426 |
|
427 // Trigger permission prompt UI |
|
428 nsresult |
|
429 MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req) |
|
430 { |
|
431 // for content process |
|
432 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
433 MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread. |
|
434 |
|
435 nsresult rv; |
|
436 |
|
437 nsCOMPtr<nsPIDOMWindow> window(req->GetOwner()); |
|
438 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); |
|
439 |
|
440 dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell()); |
|
441 NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); |
|
442 |
|
443 nsCOMPtr<nsIArray> typeArray; |
|
444 rv = req->GetTypes(getter_AddRefs(typeArray)); |
|
445 NS_ENSURE_SUCCESS(rv, rv); |
|
446 |
|
447 nsTArray<PermissionRequest> permArray; |
|
448 ConvertArrayToPermissionRequest(typeArray, permArray); |
|
449 |
|
450 nsCOMPtr<nsIPrincipal> principal; |
|
451 rv = req->GetPrincipal(getter_AddRefs(principal)); |
|
452 NS_ENSURE_SUCCESS(rv, rv); |
|
453 |
|
454 req->AddRef(); |
|
455 child->SendPContentPermissionRequestConstructor(req, |
|
456 permArray, |
|
457 IPC::Principal(principal)); |
|
458 |
|
459 req->Sendprompt(); |
|
460 return NS_OK; |
|
461 } |
|
462 |
|
463 // for chrome process |
|
464 nsCOMPtr<nsIContentPermissionPrompt> prompt = |
|
465 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); |
|
466 if (prompt) { |
|
467 prompt->Prompt(req); |
|
468 } |
|
469 return NS_OK; |
|
470 } |
|
471 |
|
472 // Error callback for MediaManager::GetUserMediaDevices() |
|
473 class MediaDeviceErrorCallback: public nsIDOMGetUserMediaErrorCallback |
|
474 { |
|
475 public: |
|
476 NS_DECL_ISUPPORTS |
|
477 NS_DECL_NSIDOMGETUSERMEDIAERRORCALLBACK |
|
478 |
|
479 MediaDeviceErrorCallback(const nsAString &aCallID) |
|
480 : mCallID(aCallID) {} |
|
481 |
|
482 virtual ~MediaDeviceErrorCallback() {} |
|
483 |
|
484 private: |
|
485 const nsString mCallID; |
|
486 }; |
|
487 |
|
488 NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback) |
|
489 |
|
490 // nsIDOMGetUserMediaErrorCallback method |
|
491 NS_IMETHODIMP |
|
492 MediaDeviceErrorCallback::OnError(const nsAString &aError) |
|
493 { |
|
494 return NotifyPermissionDeny(mCallID, aError); |
|
495 } |
|
496 |
|
497 } // namespace anonymous |
|
498 |
|
499 // MediaPermissionManager |
|
500 NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver) |
|
501 |
|
502 MediaPermissionManager* |
|
503 MediaPermissionManager::GetInstance() |
|
504 { |
|
505 if (!gMediaPermMgr) { |
|
506 gMediaPermMgr = new MediaPermissionManager(); |
|
507 } |
|
508 |
|
509 return gMediaPermMgr; |
|
510 } |
|
511 |
|
512 MediaPermissionManager::MediaPermissionManager() |
|
513 { |
|
514 nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
|
515 if (obs) { |
|
516 obs->AddObserver(this, "getUserMedia:request", false); |
|
517 obs->AddObserver(this, "xpcom-shutdown", false); |
|
518 } |
|
519 } |
|
520 |
|
521 MediaPermissionManager::~MediaPermissionManager() |
|
522 { |
|
523 this->Deinit(); |
|
524 } |
|
525 |
|
526 nsresult |
|
527 MediaPermissionManager::Deinit() |
|
528 { |
|
529 nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
|
530 if (obs) { |
|
531 obs->RemoveObserver(this, "getUserMedia:request"); |
|
532 obs->RemoveObserver(this, "xpcom-shutdown"); |
|
533 } |
|
534 return NS_OK; |
|
535 } |
|
536 |
|
537 // nsIObserver method |
|
538 NS_IMETHODIMP |
|
539 MediaPermissionManager::Observe(nsISupports* aSubject, const char* aTopic, |
|
540 const char16_t* aData) |
|
541 { |
|
542 nsresult rv; |
|
543 if (!strcmp(aTopic, "getUserMedia:request")) { |
|
544 nsRefPtr<dom::GetUserMediaRequest> req = |
|
545 static_cast<dom::GetUserMediaRequest*>(aSubject); |
|
546 rv = HandleRequest(req); |
|
547 |
|
548 if (NS_FAILED(rv)) { |
|
549 nsString callID; |
|
550 req->GetCallID(callID); |
|
551 NotifyPermissionDeny(callID, NS_LITERAL_STRING("unable to enumerate media device")); |
|
552 } |
|
553 } else if (!strcmp(aTopic, "xpcom-shutdown")) { |
|
554 rv = this->Deinit(); |
|
555 } else { |
|
556 // not reachable |
|
557 rv = NS_ERROR_FAILURE; |
|
558 } |
|
559 return rv; |
|
560 } |
|
561 |
|
562 // Handle GetUserMediaRequest, query available media device first. |
|
563 nsresult |
|
564 MediaPermissionManager::HandleRequest(nsRefPtr<dom::GetUserMediaRequest> &req) |
|
565 { |
|
566 nsString callID; |
|
567 req->GetCallID(callID); |
|
568 |
|
569 nsCOMPtr<nsPIDOMWindow> innerWindow = static_cast<nsPIDOMWindow*> |
|
570 (nsGlobalWindow::GetInnerWindowWithId(req->InnerWindowID())); |
|
571 if (!innerWindow) { |
|
572 MOZ_ASSERT(false, "No inner window"); |
|
573 return NS_ERROR_FAILURE; |
|
574 } |
|
575 |
|
576 nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess = |
|
577 new MediaDeviceSuccessCallback(req); |
|
578 nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError = |
|
579 new MediaDeviceErrorCallback(callID); |
|
580 |
|
581 dom::MediaStreamConstraints constraints; |
|
582 req->GetConstraints(constraints); |
|
583 |
|
584 nsRefPtr<MediaManager> MediaMgr = MediaManager::GetInstance(); |
|
585 nsresult rv = MediaMgr->GetUserMediaDevices(innerWindow, constraints, onSuccess, onError); |
|
586 NS_ENSURE_SUCCESS(rv, rv); |
|
587 |
|
588 return NS_OK; |
|
589 } |
|
590 |
|
591 } // namespace mozilla |