Bug 774521 - Desktop Web Runtime UI implementation for mozGetUserMedia (Camera API). r=myk

This commit is contained in:
Marco Castelluccio 2013-10-11 11:06:21 -04:00
parent d91e3f7465
commit 5a4a2f1db1
14 changed files with 279 additions and 0 deletions

View File

@ -786,6 +786,7 @@ bin/libfreebl_32int64_3.so
@BINPATH@/webapprt/modules/WebappRT.jsm
@BINPATH@/webapprt/modules/WebappsHandler.jsm
@BINPATH@/webapprt/modules/RemoteDebugger.jsm
@BINPATH@/webapprt/modules/WebRTCHandler.jsm
#endif
#ifdef MOZ_METRO

View File

@ -25,6 +25,7 @@ Cu.import("resource://gre/modules/osfile.jsm");
// Initialize window-independent handling of webapps- notifications.
Cu.import("resource://webapprt/modules/WebappsHandler.jsm");
Cu.import("resource://webapprt/modules/WebappRT.jsm");
Cu.import("resource://webapprt/modules/WebRTCHandler.jsm");
const PROFILE_DIR = OS.Constants.Path.profileDir;

103
webapprt/WebRTCHandler.jsm Normal file
View File

@ -0,0 +1,103 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = [];
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function handleRequest(aSubject, aTopic, aData) {
let { windowID, callID } = aSubject;
let constraints = aSubject.getConstraints();
let contentWindow = Services.wm.getOuterWindowWithId(windowID);
contentWindow.navigator.mozGetUserMediaDevices(
constraints,
function (devices) {
prompt(contentWindow, callID, constraints.audio,
constraints.video || constraints.picture,
devices);
},
function (error) {
denyRequest(callID, error);
});
}
function prompt(aWindow, aCallID, aAudioRequested, aVideoRequested, aDevices) {
let audioDevices = [];
let videoDevices = [];
for (let device of aDevices) {
device = device.QueryInterface(Ci.nsIMediaDevice);
switch (device.type) {
case "audio":
if (aAudioRequested) {
audioDevices.push(device);
}
break;
case "video":
if (aVideoRequested) {
videoDevices.push(device);
}
break;
}
}
if (audioDevices.length == 0 && videoDevices.length == 0) {
denyRequest(aCallID);
return;
}
let params = {
videoDevices: videoDevices,
audioDevices: audioDevices,
out: null
};
aWindow.openDialog("chrome://webapprt/content/getUserMediaDialog.xul", "",
"chrome, dialog, modal", params).focus();
if (!params.out) {
denyRequest(aCallID);
return;
}
let allowedDevices = Cc["@mozilla.org/supports-array;1"].
createInstance(Ci.nsISupportsArray);
let videoIndex = params.out.video;
let audioIndex = params.out.audio;
if (videoIndex != -1) {
allowedDevices.AppendElement(videoDevices[videoIndex]);
}
if (audioIndex != -1) {
allowedDevices.AppendElement(audioDevices[audioIndex]);
}
if (allowedDevices.Count()) {
Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow",
aCallID);
} else {
denyRequest(aCallID);
}
}
function denyRequest(aCallID, aError) {
let msg = null;
if (aError) {
msg = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
msg.data = aError;
}
Services.obs.notifyObservers(msg, "getUserMedia:response:deny", aCallID);
}
Services.obs.addObserver(handleRequest, "getUserMedia:request", false);

View File

@ -0,0 +1,38 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function onOK() {
window.arguments[0].out = {
video: document.getElementById("video").selectedItem.value,
audio: document.getElementById("audio").selectedItem.value
};
return true;
}
function onLoad() {
let videoDevices = window.arguments[0].videoDevices;
if (videoDevices.length) {
let videoMenu = document.getElementById("video");
for (let i = 0; i < videoDevices.length; i++) {
videoMenu.appendItem(videoDevices[i].name, i);
}
videoMenu.selectedIndex = 1;
} else {
document.getElementById("videoGroup").hidden = true;
}
let audioDevices = window.arguments[0].audioDevices;
if (audioDevices.length) {
let audioMenu = document.getElementById("audio");
for (let i = 0; i < audioDevices.length; i++) {
audioMenu.appendItem(audioDevices[i].name, i);
}
audioMenu.selectedIndex = 1;
} else {
document.getElementById("audioGroup").hidden = true;
}
window.sizeToContent();
}

View File

@ -0,0 +1,45 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this file,
- You can obtain one at http://mozilla.org/MPL/2.0/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE dialog [
<!ENTITY % gum-askDTD SYSTEM "chrome://webapprt/locale/getUserMediaDialog.dtd">
%gum-askDTD;
]>
<dialog id="getUserMediaDialog" title="&getUserMediaDialog.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
buttons="accept,cancel"
buttonlabelaccept="&getUserMediaDialog.buttonlabelaccept;"
buttonaccesskeyaccept="&getUserMediaDialog.buttonaccesskeyaccept;"
onload="onLoad()"
ondialogaccept="return onOK()"
buttonlabelcancel="&getUserMediaDialog.buttonlabelcancel;"
buttonaccesskeycancel="&getUserMediaDialog.buttonaccesskeycancel;">
<script type="application/javascript"
src="chrome://webapprt/content/getUserMediaDialog.js"/>
<groupbox id="videoGroup" flex="1">
<caption label="&getUserMediaDialog.video.label;"/>
<menulist id="video">
<menupopup>
<menuitem label="&getUserMediaDialog.video.noVideo;" value="-1"/>
</menupopup>
</menulist>
</groupbox>
<groupbox id="audioGroup" flex="1">
<caption label="&getUserMediaDialog.audio.label;"/>
<menulist id="audio">
<menupopup>
<menuitem label="&getUserMediaDialog.audio.noAudio;" value="-1"/>
</menupopup>
</menulist>
</groupbox>
</dialog>

View File

@ -6,6 +6,8 @@ webapprt.jar:
% content webapprt %content/
* content/webapp.js (content/webapp.js)
* content/webapp.xul (content/webapp.xul)
content/getUserMediaDialog.xul (content/getUserMediaDialog.xul)
content/getUserMediaDialog.js (content/getUserMediaDialog.js)
content/mochitest-shared.js (content/mochitest-shared.js)
content/mochitest.js (content/mochitest.js)
content/mochitest.xul (content/mochitest.xul)

View File

@ -0,0 +1,17 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this file,
- You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- LOCALIZATION NOTE: These are localized strings for the getUserMedia dialog
- to ask permissions in the webapp runtime. -->
<!ENTITY getUserMediaDialog.title "Media Sharing">
<!ENTITY getUserMediaDialog.buttonlabelaccept "Share">
<!ENTITY getUserMediaDialog.buttonaccesskeyaccept "S">
<!ENTITY getUserMediaDialog.buttonlabelcancel "Cancel">
<!ENTITY getUserMediaDialog.buttonaccesskeycancel "n">
<!ENTITY getUserMediaDialog.video.label "Select camera">
<!ENTITY getUserMediaDialog.video.noVideo "No video">
<!ENTITY getUserMediaDialog.audio.label "Select microphone">
<!ENTITY getUserMediaDialog.audio.noAudio "No audio">

View File

@ -7,5 +7,6 @@
% locale webapprt @AB_CD@ %locale/webapprt/
locale/webapprt/webapp.dtd (%webapprt/webapp.dtd)
locale/webapprt/webapp.properties (%webapprt/webapp.properties)
locale/webapprt/getUserMediaDialog.dtd (%webapprt/getUserMediaDialog.dtd)
% locale branding @AB_CD@ resource://webappbranding/

View File

@ -24,6 +24,7 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES += [
'RemoteDebugger.jsm',
'Startup.jsm',
'WebRTCHandler.jsm',
'WebappRT.jsm',
'WebappsHandler.jsm',
]

View File

@ -0,0 +1,38 @@
Cu.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
let openedWindows = 0;
let winObserver = function(win, topic) {
if (topic == "domwindowopened") {
win.addEventListener("load", function onLoadWindow() {
win.removeEventListener("load", onLoadWindow, false);
openedWindows++;
if (openedWindows == 2) {
win.close();
}
}, false);
}
}
Services.ww.registerNotification(winObserver);
let mutObserver = null;
loadWebapp("getUserMedia.webapp", undefined, function onLoad() {
let msg = gAppBrowser.contentDocument.getElementById("msg");
mutObserver = new MutationObserver(function(mutations) {
is(msg.textContent, "PERMISSION_DENIED", "getUserMedia permission denied.");
is(openedWindows, 2, "Prompt shown.");
finish();
});
mutObserver.observe(msg, { childList: true });
});
registerCleanupFunction(function() {
Services.ww.unregisterNotification(winObserver);
mutObserver.disconnect();
});
}

View File

@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<html>
<head>
<title>getUserMedia Test App</title>
<meta charset="utf-8">
</head>
<body>
<span id="msg"></span>
<script>
navigator.mozGetUserMedia({ video: true, audio: true },
function(localMediaStream) {
document.getElementById("msg").textContent = window.URL.createObjectURL(localMediaStream);
},
function(err) {
document.getElementById("msg").textContent = err;
});
</script>
<h1>getUserMedia Test App</h1>
</body>
</html>

View File

@ -0,0 +1,5 @@
{
"name": "getUserMedia Test App",
"description": "an app for testing getUserMedia",
"launch_path": "/webapprtChrome/webapprt/test/chrome/getUserMedia.html"
}

View File

@ -0,0 +1 @@
Content-Type: application/x-web-app-manifest+json

View File

@ -26,6 +26,9 @@ support-files =
mozpay.webapp^headers^
mozpay.html
mozpay-success.html
getUserMedia.webapp
getUserMedia.webapp^headers^
getUserMedia.html
[browser_sample.js]
@ -36,3 +39,5 @@ support-files =
[browser_geolocation-prompt-noperm.js]
[browser_debugger.js]
[browser_mozpay.js]
[browser_getUserMedia.js]
skip-if = true