1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/media/MediaPermissionGonk.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,591 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "MediaManager.h" 1.9 +#include "MediaPermissionGonk.h" 1.10 + 1.11 +#include "nsCOMPtr.h" 1.12 +#include "nsCxPusher.h" 1.13 +#include "nsIContentPermissionPrompt.h" 1.14 +#include "nsIDocument.h" 1.15 +#include "nsIDOMNavigatorUserMedia.h" 1.16 +#include "nsIStringEnumerator.h" 1.17 +#include "nsISupportsArray.h" 1.18 +#include "nsJSUtils.h" 1.19 +#include "nsPIDOMWindow.h" 1.20 +#include "nsTArray.h" 1.21 +#include "GetUserMediaRequest.h" 1.22 +#include "PCOMContentPermissionRequestChild.h" 1.23 +#include "mozilla/dom/PBrowserChild.h" 1.24 +#include "mozilla/dom/TabChild.h" 1.25 +#include "mozilla/dom/MediaStreamTrackBinding.h" 1.26 +#include "nsISupportsPrimitives.h" 1.27 +#include "nsServiceManagerUtils.h" 1.28 +#include "nsArrayUtils.h" 1.29 +#include "nsContentPermissionHelper.h" 1.30 +#include "mozilla/dom/PermissionMessageUtils.h" 1.31 + 1.32 +#define AUDIO_PERMISSION_NAME "audio-capture" 1.33 +#define VIDEO_PERMISSION_NAME "video-capture" 1.34 + 1.35 +using namespace mozilla::dom; 1.36 + 1.37 +namespace mozilla { 1.38 + 1.39 +static MediaPermissionManager *gMediaPermMgr = nullptr; 1.40 + 1.41 +static uint32_t 1.42 +ConvertArrayToPermissionRequest(nsIArray* aSrcArray, 1.43 + nsTArray<PermissionRequest>& aDesArray) 1.44 +{ 1.45 + uint32_t len = 0; 1.46 + aSrcArray->GetLength(&len); 1.47 + for (uint32_t i = 0; i < len; i++) { 1.48 + nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i); 1.49 + nsAutoCString type; 1.50 + nsAutoCString access; 1.51 + cpt->GetType(type); 1.52 + cpt->GetAccess(access); 1.53 + 1.54 + nsCOMPtr<nsIArray> optionArray; 1.55 + cpt->GetOptions(getter_AddRefs(optionArray)); 1.56 + uint32_t optionsLength = 0; 1.57 + optionArray->GetLength(&optionsLength); 1.58 + nsTArray<nsString> options; 1.59 + for (uint32_t j = 0; j < optionsLength; ++j) { 1.60 + nsCOMPtr<nsISupportsString> isupportsString = do_QueryElementAt(optionArray, j); 1.61 + if (isupportsString) { 1.62 + nsString option; 1.63 + isupportsString->GetData(option); 1.64 + options.AppendElement(option); 1.65 + } 1.66 + } 1.67 + 1.68 + aDesArray.AppendElement(PermissionRequest(type, access, options)); 1.69 + } 1.70 + return len; 1.71 +} 1.72 + 1.73 +static void 1.74 +CreateDeviceNameList(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices, 1.75 + nsTArray<nsString> &aDeviceNameList) 1.76 +{ 1.77 + for (uint32_t i = 0; i < aDevices.Length(); ++i) { 1.78 + nsString name; 1.79 + nsresult rv = aDevices[i]->GetName(name); 1.80 + NS_ENSURE_SUCCESS_VOID(rv); 1.81 + aDeviceNameList.AppendElement(name); 1.82 + } 1.83 +} 1.84 + 1.85 +static already_AddRefed<nsIMediaDevice> 1.86 +FindDeviceByName(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices, 1.87 + const nsAString &aDeviceName) 1.88 +{ 1.89 + for (uint32_t i = 0; i < aDevices.Length(); ++i) { 1.90 + nsCOMPtr<nsIMediaDevice> device = aDevices[i]; 1.91 + nsString deviceName; 1.92 + device->GetName(deviceName); 1.93 + if (deviceName.Equals(aDeviceName)) { 1.94 + return device.forget(); 1.95 + } 1.96 + } 1.97 + 1.98 + return nullptr; 1.99 +} 1.100 + 1.101 +// Helper function for notifying permission granted 1.102 +static nsresult 1.103 +NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices) 1.104 +{ 1.105 + nsresult rv; 1.106 + nsCOMPtr<nsISupportsArray> array; 1.107 + rv = NS_NewISupportsArray(getter_AddRefs(array)); 1.108 + NS_ENSURE_SUCCESS(rv, rv); 1.109 + 1.110 + for (uint32_t i = 0; i < aDevices.Length(); ++i) { 1.111 + rv = array->AppendElement(aDevices.ElementAt(i)); 1.112 + NS_ENSURE_SUCCESS(rv, rv); 1.113 + } 1.114 + 1.115 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.116 + NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); 1.117 + 1.118 + return obs->NotifyObservers(array, "getUserMedia:response:allow", 1.119 + aCallID.BeginReading()); 1.120 +} 1.121 + 1.122 +// Helper function for notifying permision denial or error 1.123 +static nsresult 1.124 +NotifyPermissionDeny(const nsAString &aCallID, const nsAString &aErrorMsg) 1.125 +{ 1.126 + nsresult rv; 1.127 + nsCOMPtr<nsISupportsString> supportsString = 1.128 + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); 1.129 + NS_ENSURE_SUCCESS(rv, rv); 1.130 + 1.131 + rv = supportsString->SetData(aErrorMsg); 1.132 + NS_ENSURE_SUCCESS(rv, rv); 1.133 + 1.134 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.135 + NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); 1.136 + 1.137 + return obs->NotifyObservers(supportsString, "getUserMedia:response:deny", 1.138 + aCallID.BeginReading()); 1.139 +} 1.140 + 1.141 +namespace { 1.142 + 1.143 +/** 1.144 + * MediaPermissionRequest will send a prompt ipdl request to b2g process according 1.145 + * to its owned type. 1.146 + */ 1.147 +class MediaPermissionRequest : public nsIContentPermissionRequest 1.148 + , public PCOMContentPermissionRequestChild 1.149 +{ 1.150 +public: 1.151 + NS_DECL_ISUPPORTS 1.152 + NS_DECL_NSICONTENTPERMISSIONREQUEST 1.153 + 1.154 + MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest> &aRequest, 1.155 + nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices); 1.156 + virtual ~MediaPermissionRequest() {} 1.157 + 1.158 + // It will be called when prompt dismissed. 1.159 + virtual bool Recv__delete__(const bool &allow, 1.160 + const InfallibleTArray<PermissionChoice>& choices) MOZ_OVERRIDE; 1.161 + virtual void IPDLRelease() MOZ_OVERRIDE { Release(); } 1.162 + 1.163 + already_AddRefed<nsPIDOMWindow> GetOwner(); 1.164 + 1.165 +private: 1.166 + nsresult DoAllow(const nsString &audioDevice, const nsString &videoDevice); 1.167 + 1.168 + bool mAudio; // Request for audio permission 1.169 + bool mVideo; // Request for video permission 1.170 + nsRefPtr<dom::GetUserMediaRequest> mRequest; 1.171 + nsTArray<nsCOMPtr<nsIMediaDevice> > mAudioDevices; // candidate audio devices 1.172 + nsTArray<nsCOMPtr<nsIMediaDevice> > mVideoDevices; // candidate video devices 1.173 +}; 1.174 + 1.175 +// MediaPermissionRequest 1.176 +NS_IMPL_ISUPPORTS(MediaPermissionRequest, nsIContentPermissionRequest) 1.177 + 1.178 +MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest> &aRequest, 1.179 + nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices) 1.180 + : mRequest(aRequest) 1.181 +{ 1.182 + dom::MediaStreamConstraints constraints; 1.183 + mRequest->GetConstraints(constraints); 1.184 + 1.185 + mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean(); 1.186 + mVideo = !constraints.mVideo.IsBoolean() || constraints.mVideo.GetAsBoolean(); 1.187 + 1.188 + for (uint32_t i = 0; i < aDevices.Length(); ++i) { 1.189 + nsCOMPtr<nsIMediaDevice> device(aDevices[i]); 1.190 + nsAutoString deviceType; 1.191 + device->GetType(deviceType); 1.192 + if (mAudio && deviceType.EqualsLiteral("audio")) { 1.193 + mAudioDevices.AppendElement(device); 1.194 + } 1.195 + if (mVideo && deviceType.EqualsLiteral("video")) { 1.196 + mVideoDevices.AppendElement(device); 1.197 + } 1.198 + } 1.199 +} 1.200 + 1.201 +// nsIContentPermissionRequest methods 1.202 +NS_IMETHODIMP 1.203 +MediaPermissionRequest::GetTypes(nsIArray** aTypes) 1.204 +{ 1.205 + nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID); 1.206 + //XXX append device list 1.207 + if (mAudio) { 1.208 + nsTArray<nsString> audioDeviceNames; 1.209 + CreateDeviceNameList(mAudioDevices, audioDeviceNames); 1.210 + nsCOMPtr<nsISupports> AudioType = 1.211 + new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME), 1.212 + NS_LITERAL_CSTRING("unused"), 1.213 + audioDeviceNames); 1.214 + types->AppendElement(AudioType, false); 1.215 + } 1.216 + if (mVideo) { 1.217 + nsTArray<nsString> videoDeviceNames; 1.218 + CreateDeviceNameList(mVideoDevices, videoDeviceNames); 1.219 + nsCOMPtr<nsISupports> VideoType = 1.220 + new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME), 1.221 + NS_LITERAL_CSTRING("unused"), 1.222 + videoDeviceNames); 1.223 + types->AppendElement(VideoType, false); 1.224 + } 1.225 + NS_IF_ADDREF(*aTypes = types); 1.226 + 1.227 + return NS_OK; 1.228 +} 1.229 + 1.230 +NS_IMETHODIMP 1.231 +MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) 1.232 +{ 1.233 + NS_ENSURE_ARG_POINTER(aRequestingPrincipal); 1.234 + 1.235 + nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*> 1.236 + (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())); 1.237 + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 1.238 + 1.239 + nsCOMPtr<nsIDocument> doc = window->GetExtantDoc(); 1.240 + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); 1.241 + 1.242 + NS_ADDREF(*aRequestingPrincipal = doc->NodePrincipal()); 1.243 + return NS_OK; 1.244 +} 1.245 + 1.246 +NS_IMETHODIMP 1.247 +MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow) 1.248 +{ 1.249 + NS_ENSURE_ARG_POINTER(aRequestingWindow); 1.250 + nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*> 1.251 + (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())); 1.252 + window.forget(aRequestingWindow); 1.253 + return NS_OK; 1.254 +} 1.255 + 1.256 +NS_IMETHODIMP 1.257 +MediaPermissionRequest::GetElement(nsIDOMElement** aRequestingElement) 1.258 +{ 1.259 + NS_ENSURE_ARG_POINTER(aRequestingElement); 1.260 + *aRequestingElement = nullptr; 1.261 + return NS_OK; 1.262 +} 1.263 + 1.264 +NS_IMETHODIMP 1.265 +MediaPermissionRequest::Cancel() 1.266 +{ 1.267 + nsString callID; 1.268 + mRequest->GetCallID(callID); 1.269 + NotifyPermissionDeny(callID, NS_LITERAL_STRING("Permission Denied")); 1.270 + return NS_OK; 1.271 +} 1.272 + 1.273 +NS_IMETHODIMP 1.274 +MediaPermissionRequest::Allow(JS::HandleValue aChoices) 1.275 +{ 1.276 + // check if JS object 1.277 + if (!aChoices.isObject()) { 1.278 + MOZ_ASSERT(false, "Not a correct format of PermissionChoice"); 1.279 + return NS_ERROR_INVALID_ARG; 1.280 + } 1.281 + // iterate through audio-capture and video-capture 1.282 + AutoSafeJSContext cx; 1.283 + JS::Rooted<JSObject*> obj(cx, &aChoices.toObject()); 1.284 + JSAutoCompartment ac(cx, obj); 1.285 + JS::Rooted<JS::Value> v(cx); 1.286 + 1.287 + // get selected audio device name 1.288 + nsString audioDevice; 1.289 + if (mAudio) { 1.290 + if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) { 1.291 + return NS_ERROR_FAILURE; 1.292 + } 1.293 + nsDependentJSString deviceName; 1.294 + if (!deviceName.init(cx, v)) { 1.295 + MOZ_ASSERT(false, "Couldn't initialize string from aChoices"); 1.296 + return NS_ERROR_FAILURE; 1.297 + } 1.298 + audioDevice = deviceName; 1.299 + } 1.300 + 1.301 + // get selected video device name 1.302 + nsString videoDevice; 1.303 + if (mVideo) { 1.304 + if (!JS_GetProperty(cx, obj, VIDEO_PERMISSION_NAME, &v) || !v.isString()) { 1.305 + return NS_ERROR_FAILURE; 1.306 + } 1.307 + nsDependentJSString deviceName; 1.308 + if (!deviceName.init(cx, v)) { 1.309 + MOZ_ASSERT(false, "Couldn't initialize string from aChoices"); 1.310 + return NS_ERROR_FAILURE; 1.311 + } 1.312 + videoDevice = deviceName; 1.313 + } 1.314 + 1.315 + return DoAllow(audioDevice, videoDevice); 1.316 +} 1.317 + 1.318 +nsresult 1.319 +MediaPermissionRequest::DoAllow(const nsString &audioDevice, 1.320 + const nsString &videoDevice) 1.321 +{ 1.322 + nsTArray<nsCOMPtr<nsIMediaDevice> > selectedDevices; 1.323 + if (mAudio) { 1.324 + nsCOMPtr<nsIMediaDevice> device = 1.325 + FindDeviceByName(mAudioDevices, audioDevice); 1.326 + if (device) { 1.327 + selectedDevices.AppendElement(device); 1.328 + } 1.329 + } 1.330 + 1.331 + if (mVideo) { 1.332 + nsCOMPtr<nsIMediaDevice> device = 1.333 + FindDeviceByName(mVideoDevices, videoDevice); 1.334 + if (device) { 1.335 + selectedDevices.AppendElement(device); 1.336 + } 1.337 + } 1.338 + 1.339 + nsString callID; 1.340 + mRequest->GetCallID(callID); 1.341 + return NotifyPermissionAllow(callID, selectedDevices); 1.342 +} 1.343 + 1.344 +already_AddRefed<nsPIDOMWindow> 1.345 +MediaPermissionRequest::GetOwner() 1.346 +{ 1.347 + nsCOMPtr<nsPIDOMWindow> window = static_cast<nsPIDOMWindow*> 1.348 + (nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())); 1.349 + return window.forget(); 1.350 +} 1.351 + 1.352 +//PCOMContentPermissionRequestChild 1.353 +bool 1.354 +MediaPermissionRequest::Recv__delete__(const bool& allow, 1.355 + const InfallibleTArray<PermissionChoice>& choices) 1.356 +{ 1.357 + if (allow) { 1.358 + // get selected device name for audio and video 1.359 + nsString audioDevice, videoDevice; 1.360 + for (uint32_t i = 0; i < choices.Length(); ++i) { 1.361 + const nsString &choice = choices[i].choice(); 1.362 + if (choices[i].type().EqualsLiteral(AUDIO_PERMISSION_NAME)) { 1.363 + audioDevice = choice; 1.364 + } else if (choices[i].type().EqualsLiteral(VIDEO_PERMISSION_NAME)) { 1.365 + videoDevice = choice; 1.366 + } 1.367 + } 1.368 + (void) DoAllow(audioDevice, videoDevice); 1.369 + } else { 1.370 + (void) Cancel(); 1.371 + } 1.372 + return true; 1.373 +} 1.374 + 1.375 +// Success callback for MediaManager::GetUserMediaDevices(). 1.376 +class MediaDeviceSuccessCallback: public nsIGetUserMediaDevicesSuccessCallback 1.377 +{ 1.378 +public: 1.379 + NS_DECL_ISUPPORTS 1.380 + NS_DECL_NSIGETUSERMEDIADEVICESSUCCESSCALLBACK 1.381 + 1.382 + MediaDeviceSuccessCallback(nsRefPtr<dom::GetUserMediaRequest> &aRequest) 1.383 + : mRequest(aRequest) {} 1.384 + virtual ~MediaDeviceSuccessCallback() {} 1.385 + 1.386 +private: 1.387 + nsresult DoPrompt(nsRefPtr<MediaPermissionRequest> &req); 1.388 + nsRefPtr<dom::GetUserMediaRequest> mRequest; 1.389 +}; 1.390 + 1.391 +NS_IMPL_ISUPPORTS(MediaDeviceSuccessCallback, nsIGetUserMediaDevicesSuccessCallback) 1.392 + 1.393 +// nsIGetUserMediaDevicesSuccessCallback method 1.394 +NS_IMETHODIMP 1.395 +MediaDeviceSuccessCallback::OnSuccess(nsIVariant* aDevices) 1.396 +{ 1.397 + nsIID elementIID; 1.398 + uint16_t elementType; 1.399 + void* rawArray; 1.400 + uint32_t arrayLen; 1.401 + 1.402 + nsresult rv; 1.403 + rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray); 1.404 + NS_ENSURE_SUCCESS(rv, rv); 1.405 + 1.406 + if (elementType != nsIDataType::VTYPE_INTERFACE) { 1.407 + NS_Free(rawArray); 1.408 + return NS_ERROR_FAILURE; 1.409 + } 1.410 + 1.411 + // Create array for nsIMediaDevice 1.412 + nsTArray<nsCOMPtr<nsIMediaDevice> > devices; 1.413 + 1.414 + nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray); 1.415 + for (uint32_t i = 0; i < arrayLen; ++i) { 1.416 + nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i])); 1.417 + devices.AppendElement(device); 1.418 + NS_IF_RELEASE(supportsArray[i]); // explicitly decrease reference count for raw pointer 1.419 + } 1.420 + NS_Free(rawArray); // explicitly free for the memory from nsIVariant::GetAsArray 1.421 + 1.422 + // Send MediaPermissionRequest 1.423 + nsRefPtr<MediaPermissionRequest> req = new MediaPermissionRequest(mRequest, devices); 1.424 + rv = DoPrompt(req); 1.425 + 1.426 + NS_ENSURE_SUCCESS(rv, rv); 1.427 + return NS_OK; 1.428 +} 1.429 + 1.430 +// Trigger permission prompt UI 1.431 +nsresult 1.432 +MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req) 1.433 +{ 1.434 + // for content process 1.435 + if (XRE_GetProcessType() == GeckoProcessType_Content) { 1.436 + MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread. 1.437 + 1.438 + nsresult rv; 1.439 + 1.440 + nsCOMPtr<nsPIDOMWindow> window(req->GetOwner()); 1.441 + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 1.442 + 1.443 + dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell()); 1.444 + NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); 1.445 + 1.446 + nsCOMPtr<nsIArray> typeArray; 1.447 + rv = req->GetTypes(getter_AddRefs(typeArray)); 1.448 + NS_ENSURE_SUCCESS(rv, rv); 1.449 + 1.450 + nsTArray<PermissionRequest> permArray; 1.451 + ConvertArrayToPermissionRequest(typeArray, permArray); 1.452 + 1.453 + nsCOMPtr<nsIPrincipal> principal; 1.454 + rv = req->GetPrincipal(getter_AddRefs(principal)); 1.455 + NS_ENSURE_SUCCESS(rv, rv); 1.456 + 1.457 + req->AddRef(); 1.458 + child->SendPContentPermissionRequestConstructor(req, 1.459 + permArray, 1.460 + IPC::Principal(principal)); 1.461 + 1.462 + req->Sendprompt(); 1.463 + return NS_OK; 1.464 + } 1.465 + 1.466 + // for chrome process 1.467 + nsCOMPtr<nsIContentPermissionPrompt> prompt = 1.468 + do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); 1.469 + if (prompt) { 1.470 + prompt->Prompt(req); 1.471 + } 1.472 + return NS_OK; 1.473 +} 1.474 + 1.475 +// Error callback for MediaManager::GetUserMediaDevices() 1.476 +class MediaDeviceErrorCallback: public nsIDOMGetUserMediaErrorCallback 1.477 +{ 1.478 +public: 1.479 + NS_DECL_ISUPPORTS 1.480 + NS_DECL_NSIDOMGETUSERMEDIAERRORCALLBACK 1.481 + 1.482 + MediaDeviceErrorCallback(const nsAString &aCallID) 1.483 + : mCallID(aCallID) {} 1.484 + 1.485 + virtual ~MediaDeviceErrorCallback() {} 1.486 + 1.487 +private: 1.488 + const nsString mCallID; 1.489 +}; 1.490 + 1.491 +NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback) 1.492 + 1.493 +// nsIDOMGetUserMediaErrorCallback method 1.494 +NS_IMETHODIMP 1.495 +MediaDeviceErrorCallback::OnError(const nsAString &aError) 1.496 +{ 1.497 + return NotifyPermissionDeny(mCallID, aError); 1.498 +} 1.499 + 1.500 +} // namespace anonymous 1.501 + 1.502 +// MediaPermissionManager 1.503 +NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver) 1.504 + 1.505 +MediaPermissionManager* 1.506 +MediaPermissionManager::GetInstance() 1.507 +{ 1.508 + if (!gMediaPermMgr) { 1.509 + gMediaPermMgr = new MediaPermissionManager(); 1.510 + } 1.511 + 1.512 + return gMediaPermMgr; 1.513 +} 1.514 + 1.515 +MediaPermissionManager::MediaPermissionManager() 1.516 +{ 1.517 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.518 + if (obs) { 1.519 + obs->AddObserver(this, "getUserMedia:request", false); 1.520 + obs->AddObserver(this, "xpcom-shutdown", false); 1.521 + } 1.522 +} 1.523 + 1.524 +MediaPermissionManager::~MediaPermissionManager() 1.525 +{ 1.526 + this->Deinit(); 1.527 +} 1.528 + 1.529 +nsresult 1.530 +MediaPermissionManager::Deinit() 1.531 +{ 1.532 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.533 + if (obs) { 1.534 + obs->RemoveObserver(this, "getUserMedia:request"); 1.535 + obs->RemoveObserver(this, "xpcom-shutdown"); 1.536 + } 1.537 + return NS_OK; 1.538 +} 1.539 + 1.540 +// nsIObserver method 1.541 +NS_IMETHODIMP 1.542 +MediaPermissionManager::Observe(nsISupports* aSubject, const char* aTopic, 1.543 + const char16_t* aData) 1.544 +{ 1.545 + nsresult rv; 1.546 + if (!strcmp(aTopic, "getUserMedia:request")) { 1.547 + nsRefPtr<dom::GetUserMediaRequest> req = 1.548 + static_cast<dom::GetUserMediaRequest*>(aSubject); 1.549 + rv = HandleRequest(req); 1.550 + 1.551 + if (NS_FAILED(rv)) { 1.552 + nsString callID; 1.553 + req->GetCallID(callID); 1.554 + NotifyPermissionDeny(callID, NS_LITERAL_STRING("unable to enumerate media device")); 1.555 + } 1.556 + } else if (!strcmp(aTopic, "xpcom-shutdown")) { 1.557 + rv = this->Deinit(); 1.558 + } else { 1.559 + // not reachable 1.560 + rv = NS_ERROR_FAILURE; 1.561 + } 1.562 + return rv; 1.563 +} 1.564 + 1.565 +// Handle GetUserMediaRequest, query available media device first. 1.566 +nsresult 1.567 +MediaPermissionManager::HandleRequest(nsRefPtr<dom::GetUserMediaRequest> &req) 1.568 +{ 1.569 + nsString callID; 1.570 + req->GetCallID(callID); 1.571 + 1.572 + nsCOMPtr<nsPIDOMWindow> innerWindow = static_cast<nsPIDOMWindow*> 1.573 + (nsGlobalWindow::GetInnerWindowWithId(req->InnerWindowID())); 1.574 + if (!innerWindow) { 1.575 + MOZ_ASSERT(false, "No inner window"); 1.576 + return NS_ERROR_FAILURE; 1.577 + } 1.578 + 1.579 + nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess = 1.580 + new MediaDeviceSuccessCallback(req); 1.581 + nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError = 1.582 + new MediaDeviceErrorCallback(callID); 1.583 + 1.584 + dom::MediaStreamConstraints constraints; 1.585 + req->GetConstraints(constraints); 1.586 + 1.587 + nsRefPtr<MediaManager> MediaMgr = MediaManager::GetInstance(); 1.588 + nsresult rv = MediaMgr->GetUserMediaDevices(innerWindow, constraints, onSuccess, onError); 1.589 + NS_ENSURE_SUCCESS(rv, rv); 1.590 + 1.591 + return NS_OK; 1.592 +} 1.593 + 1.594 +} // namespace mozilla