зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1642465 - Add EncryptedMedia actors to handle EME messages. r=Gijs
This patch also removes the code that is replaced by the new actors. Differential Revision: https://phabricator.services.mozilla.com/D77861
This commit is contained in:
Родитель
897e56554c
Коммит
12c7838399
|
@ -0,0 +1,17 @@
|
|||
/* vim: set ts=2 sw=2 sts=2 et tw=80: */
|
||||
/* 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["EncryptedMediaChild"];
|
||||
|
||||
class EncryptedMediaChild extends JSWindowActorChild {
|
||||
// Expected to observe 'mediakeys-request' as notified from MediaKeySystemAccess.
|
||||
// @param aSubject the nsPIDOMWindowInner associated with the notifying MediaKeySystemAccess.
|
||||
// @param aTopic should be "mediakeys-request".
|
||||
// @param aData json containing a `status` and a `keysystem`.
|
||||
observe(aSubject, aTopic, aData) {
|
||||
this.sendAsyncMessage("EMEVideo:ContentMediaKeysRequest", aData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/* vim: set ts=2 sw=2 sts=2 et tw=80: */
|
||||
/* 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["EncryptedMediaParent"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"BrowserUtils",
|
||||
"resource://gre/modules/BrowserUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
|
||||
return Services.strings.createBundle(
|
||||
"chrome://branding/locale/brand.properties"
|
||||
);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gNavigatorBundle", function() {
|
||||
return Services.strings.createBundle(
|
||||
"chrome://browser/locale/browser.properties"
|
||||
);
|
||||
});
|
||||
|
||||
class EncryptedMediaParent extends JSWindowActorParent {
|
||||
isUiEnabled() {
|
||||
return Services.prefs.getBoolPref("browser.eme.ui.enabled");
|
||||
}
|
||||
|
||||
ensureEMEEnabled(aBrowser, aKeySystem) {
|
||||
Services.prefs.setBoolPref("media.eme.enabled", true);
|
||||
if (
|
||||
aKeySystem &&
|
||||
aKeySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
|
||||
!Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")
|
||||
) {
|
||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
|
||||
}
|
||||
aBrowser.reload();
|
||||
}
|
||||
|
||||
isKeySystemVisible(aKeySystem) {
|
||||
if (!aKeySystem) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
aKeySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.visible")
|
||||
) {
|
||||
return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getEMEDisabledFragment(aBrowser) {
|
||||
let mainMessage = gNavigatorBundle.GetStringFromName(
|
||||
"emeNotifications.drmContentDisabled.message"
|
||||
);
|
||||
let text = gNavigatorBundle.GetStringFromName(
|
||||
"emeNotifications.drmContentDisabled.learnMoreLabel"
|
||||
);
|
||||
let document = aBrowser.ownerDocument;
|
||||
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
let link = document.createXULElement("label", { is: "text-link" });
|
||||
link.setAttribute("href", baseURL + "drm-content");
|
||||
link.textContent = text;
|
||||
return BrowserUtils.getLocalizedFragment(document, mainMessage, link);
|
||||
}
|
||||
|
||||
getMessageWithBrandName(aNotificationId) {
|
||||
let msgId = "emeNotifications." + aNotificationId + ".message";
|
||||
return gNavigatorBundle.formatStringFromName(msgId, [
|
||||
gBrandBundle.GetStringFromName("brandShortName"),
|
||||
]);
|
||||
}
|
||||
|
||||
receiveMessage(aMessage) {
|
||||
// The top level browsing context's embedding element should be a xul browser element.
|
||||
let browser = this.browsingContext.top.embedderElement;
|
||||
|
||||
if (!browser) {
|
||||
// We don't have a browser so bail!
|
||||
return;
|
||||
}
|
||||
|
||||
if (browser.outerBrowser) {
|
||||
// Responsive design mode check
|
||||
browser = browser.outerBrowser;
|
||||
}
|
||||
|
||||
let parsedData;
|
||||
try {
|
||||
parsedData = JSON.parse(aMessage.data);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Malformed EME video message with data: " + aMessage.data);
|
||||
return;
|
||||
}
|
||||
let { status, keySystem } = parsedData;
|
||||
// Don't need to show if disabled or keysystem not visible.
|
||||
if (!this.isUiEnabled() || !this.isKeySystemVisible(keySystem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let notificationId;
|
||||
let buttonCallback;
|
||||
// Notification message can be either a string or a DOM fragment.
|
||||
let notificationMessage;
|
||||
switch (status) {
|
||||
case "available":
|
||||
case "cdm-created":
|
||||
// Only show the chain icon for proprietary CDMs. Clearkey is not one.
|
||||
if (keySystem != "org.w3.clearkey") {
|
||||
this.showPopupNotificationForSuccess(browser, keySystem);
|
||||
}
|
||||
// ... and bail!
|
||||
return;
|
||||
|
||||
case "api-disabled":
|
||||
case "cdm-disabled":
|
||||
notificationId = "drmContentDisabled";
|
||||
buttonCallback = () => {
|
||||
this.ensureEMEEnabled(browser, keySystem);
|
||||
};
|
||||
notificationMessage = this.getEMEDisabledFragment(browser);
|
||||
break;
|
||||
|
||||
case "cdm-not-installed":
|
||||
notificationId = "drmContentCDMInstalling";
|
||||
notificationMessage = this.getMessageWithBrandName(notificationId);
|
||||
break;
|
||||
|
||||
case "cdm-not-supported":
|
||||
// Not to pop up user-level notification because they cannot do anything
|
||||
// about it.
|
||||
return;
|
||||
default:
|
||||
Cu.reportError(
|
||||
new Error(
|
||||
"Unknown message ('" +
|
||||
status +
|
||||
"') dealing with EME key request: " +
|
||||
aMessage.data
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now actually create the notification
|
||||
|
||||
let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
|
||||
if (notificationBox.getNotificationWithValue(notificationId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let buttons = [];
|
||||
if (buttonCallback) {
|
||||
let msgPrefix = "emeNotifications." + notificationId + ".";
|
||||
let btnLabelId = msgPrefix + "button.label";
|
||||
let btnAccessKeyId = msgPrefix + "button.accesskey";
|
||||
buttons.push({
|
||||
label: gNavigatorBundle.GetStringFromName(btnLabelId),
|
||||
accessKey: gNavigatorBundle.GetStringFromName(btnAccessKeyId),
|
||||
callback: buttonCallback,
|
||||
});
|
||||
}
|
||||
|
||||
let iconURL = "chrome://browser/skin/drm-icon.svg";
|
||||
notificationBox.appendNotification(
|
||||
notificationMessage,
|
||||
notificationId,
|
||||
iconURL,
|
||||
notificationBox.PRIORITY_WARNING_MEDIUM,
|
||||
buttons
|
||||
);
|
||||
}
|
||||
|
||||
showPopupNotificationForSuccess(aBrowser) {
|
||||
// We're playing EME content! Remove any "we can't play because..." messages.
|
||||
let notificationBox = aBrowser.getTabBrowser().getNotificationBox(aBrowser);
|
||||
["drmContentDisabled", "drmContentCDMInstalling"].forEach(function(value) {
|
||||
let notification = notificationBox.getNotificationWithValue(value);
|
||||
if (notification) {
|
||||
notificationBox.removeNotification(notification);
|
||||
}
|
||||
});
|
||||
|
||||
// Don't bother creating it if it's already there:
|
||||
if (
|
||||
aBrowser.ownerGlobal.PopupNotifications.getNotification(
|
||||
"drmContentPlaying",
|
||||
aBrowser
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msgPrefix = "emeNotifications.drmContentPlaying.";
|
||||
let msgId = msgPrefix + "message2";
|
||||
let btnLabelId = msgPrefix + "button.label";
|
||||
let btnAccessKeyId = msgPrefix + "button.accesskey";
|
||||
|
||||
let message = gNavigatorBundle.formatStringFromName(msgId, [
|
||||
gBrandBundle.GetStringFromName("brandShortName"),
|
||||
]);
|
||||
let anchorId = "eme-notification-icon";
|
||||
let firstPlayPref = "browser.eme.ui.firstContentShown";
|
||||
let document = aBrowser.ownerDocument;
|
||||
if (
|
||||
!Services.prefs.getPrefType(firstPlayPref) ||
|
||||
!Services.prefs.getBoolPref(firstPlayPref)
|
||||
) {
|
||||
document.getElementById(anchorId).setAttribute("firstplay", "true");
|
||||
Services.prefs.setBoolPref(firstPlayPref, true);
|
||||
} else {
|
||||
document.getElementById(anchorId).removeAttribute("firstplay");
|
||||
}
|
||||
|
||||
let mainAction = {
|
||||
label: gNavigatorBundle.GetStringFromName(btnLabelId),
|
||||
accessKey: gNavigatorBundle.GetStringFromName(btnAccessKeyId),
|
||||
callback() {
|
||||
aBrowser.ownerGlobal.openPreferences("general-drm");
|
||||
},
|
||||
dismiss: true,
|
||||
};
|
||||
let options = {
|
||||
dismissed: true,
|
||||
eventCallback: aTopic => aTopic == "swapping",
|
||||
learnMoreURL:
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"drm-content",
|
||||
};
|
||||
aBrowser.ownerGlobal.PopupNotifications.show(
|
||||
aBrowser,
|
||||
"drmContentPlaying",
|
||||
message,
|
||||
anchorId,
|
||||
mainAction,
|
||||
null,
|
||||
options
|
||||
);
|
||||
}
|
||||
}
|
|
@ -56,6 +56,8 @@ FINAL_TARGET_FILES.actors += [
|
|||
'ContextMenuParent.jsm',
|
||||
'DOMFullscreenChild.jsm',
|
||||
'DOMFullscreenParent.jsm',
|
||||
'EncryptedMediaChild.jsm',
|
||||
'EncryptedMediaParent.jsm',
|
||||
'FormValidationChild.jsm',
|
||||
'FormValidationParent.jsm',
|
||||
'LightweightThemeChild.jsm',
|
||||
|
|
|
@ -5,211 +5,6 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var gEMEHandler = {
|
||||
get uiEnabled() {
|
||||
let emeUIEnabled = Services.prefs.getBoolPref("browser.eme.ui.enabled");
|
||||
// Force-disable on WinXP:
|
||||
if (navigator.platform.toLowerCase().startsWith("win")) {
|
||||
emeUIEnabled =
|
||||
emeUIEnabled && parseFloat(Services.sysinfo.get("version")) >= 6;
|
||||
}
|
||||
return emeUIEnabled;
|
||||
},
|
||||
ensureEMEEnabled(browser, keySystem) {
|
||||
Services.prefs.setBoolPref("media.eme.enabled", true);
|
||||
if (
|
||||
keySystem &&
|
||||
keySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
|
||||
!Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")
|
||||
) {
|
||||
Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
|
||||
}
|
||||
browser.reload();
|
||||
},
|
||||
isKeySystemVisible(keySystem) {
|
||||
if (!keySystem) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
keySystem == "com.widevine.alpha" &&
|
||||
Services.prefs.getPrefType("media.gmp-widevinecdm.visible")
|
||||
) {
|
||||
return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
|
||||
}
|
||||
return true;
|
||||
},
|
||||
getEMEDisabledFragment(msgId) {
|
||||
let mainMessage = gNavigatorBundle.getString(
|
||||
"emeNotifications.drmContentDisabled.message"
|
||||
);
|
||||
let text = gNavigatorBundle.getString(
|
||||
"emeNotifications.drmContentDisabled.learnMoreLabel"
|
||||
);
|
||||
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
let link = document.createXULElement("label", { is: "text-link" });
|
||||
link.setAttribute("href", baseURL + "drm-content");
|
||||
link.textContent = text;
|
||||
return BrowserUtils.getLocalizedFragment(document, mainMessage, link);
|
||||
},
|
||||
getMessageWithBrandName(notificationId) {
|
||||
let msgId = "emeNotifications." + notificationId + ".message";
|
||||
return gNavigatorBundle.getFormattedString(msgId, [this._brandShortName]);
|
||||
},
|
||||
receiveMessage({ target: browser, data: data }) {
|
||||
let parsedData;
|
||||
try {
|
||||
parsedData = JSON.parse(data);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Malformed EME video message with data: " + data);
|
||||
return;
|
||||
}
|
||||
let { status: status, keySystem: keySystem } = parsedData;
|
||||
// Don't need to show if disabled or keysystem not visible.
|
||||
if (!this.uiEnabled || !this.isKeySystemVisible(keySystem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let notificationId;
|
||||
let buttonCallback;
|
||||
// Notification message can be either a string or a DOM fragment.
|
||||
let notificationMessage;
|
||||
switch (status) {
|
||||
case "available":
|
||||
case "cdm-created":
|
||||
// Only show the chain icon for proprietary CDMs. Clearkey is not one.
|
||||
if (keySystem != "org.w3.clearkey") {
|
||||
this.showPopupNotificationForSuccess(browser, keySystem);
|
||||
}
|
||||
// ... and bail!
|
||||
return;
|
||||
|
||||
case "api-disabled":
|
||||
case "cdm-disabled":
|
||||
notificationId = "drmContentDisabled";
|
||||
buttonCallback = gEMEHandler.ensureEMEEnabled.bind(
|
||||
gEMEHandler,
|
||||
browser,
|
||||
keySystem
|
||||
);
|
||||
notificationMessage = this.getEMEDisabledFragment();
|
||||
break;
|
||||
|
||||
case "cdm-not-installed":
|
||||
notificationId = "drmContentCDMInstalling";
|
||||
notificationMessage = this.getMessageWithBrandName(notificationId);
|
||||
break;
|
||||
|
||||
case "cdm-not-supported":
|
||||
// Not to pop up user-level notification because they cannot do anything
|
||||
// about it.
|
||||
return;
|
||||
default:
|
||||
Cu.reportError(
|
||||
new Error(
|
||||
"Unknown message ('" +
|
||||
status +
|
||||
"') dealing with EME key request: " +
|
||||
data
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now actually create the notification
|
||||
|
||||
let box = gBrowser.getNotificationBox(browser);
|
||||
if (box.getNotificationWithValue(notificationId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let buttons = [];
|
||||
if (buttonCallback) {
|
||||
let msgPrefix = "emeNotifications." + notificationId + ".";
|
||||
let btnLabelId = msgPrefix + "button.label";
|
||||
let btnAccessKeyId = msgPrefix + "button.accesskey";
|
||||
buttons.push({
|
||||
label: gNavigatorBundle.getString(btnLabelId),
|
||||
accessKey: gNavigatorBundle.getString(btnAccessKeyId),
|
||||
callback: buttonCallback,
|
||||
});
|
||||
}
|
||||
|
||||
let iconURL = "chrome://browser/skin/drm-icon.svg";
|
||||
box.appendNotification(
|
||||
notificationMessage,
|
||||
notificationId,
|
||||
iconURL,
|
||||
box.PRIORITY_WARNING_MEDIUM,
|
||||
buttons
|
||||
);
|
||||
},
|
||||
showPopupNotificationForSuccess(browser, keySystem) {
|
||||
// We're playing EME content! Remove any "we can't play because..." messages.
|
||||
var box = gBrowser.getNotificationBox(browser);
|
||||
["drmContentDisabled", "drmContentCDMInstalling"].forEach(function(value) {
|
||||
var notification = box.getNotificationWithValue(value);
|
||||
if (notification) {
|
||||
box.removeNotification(notification);
|
||||
}
|
||||
});
|
||||
|
||||
// Don't bother creating it if it's already there:
|
||||
if (PopupNotifications.getNotification("drmContentPlaying", browser)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msgPrefix = "emeNotifications.drmContentPlaying.";
|
||||
let msgId = msgPrefix + "message2";
|
||||
let btnLabelId = msgPrefix + "button.label";
|
||||
let btnAccessKeyId = msgPrefix + "button.accesskey";
|
||||
|
||||
let message = gNavigatorBundle.getFormattedString(msgId, [
|
||||
this._brandShortName,
|
||||
]);
|
||||
let anchorId = "eme-notification-icon";
|
||||
let firstPlayPref = "browser.eme.ui.firstContentShown";
|
||||
if (
|
||||
!Services.prefs.getPrefType(firstPlayPref) ||
|
||||
!Services.prefs.getBoolPref(firstPlayPref)
|
||||
) {
|
||||
document.getElementById(anchorId).setAttribute("firstplay", "true");
|
||||
Services.prefs.setBoolPref(firstPlayPref, true);
|
||||
} else {
|
||||
document.getElementById(anchorId).removeAttribute("firstplay");
|
||||
}
|
||||
|
||||
let mainAction = {
|
||||
label: gNavigatorBundle.getString(btnLabelId),
|
||||
accessKey: gNavigatorBundle.getString(btnAccessKeyId),
|
||||
callback() {
|
||||
openPreferences("general-drm");
|
||||
},
|
||||
dismiss: true,
|
||||
};
|
||||
let options = {
|
||||
dismissed: true,
|
||||
eventCallback: aTopic => aTopic == "swapping",
|
||||
learnMoreURL:
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
||||
"drm-content",
|
||||
};
|
||||
PopupNotifications.show(
|
||||
browser,
|
||||
"drmContentPlaying",
|
||||
message,
|
||||
anchorId,
|
||||
mainAction,
|
||||
null,
|
||||
options
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(gEMEHandler, "_brandShortName", function() {
|
||||
return document.getElementById("bundle_brand").getString("brandShortName");
|
||||
});
|
||||
|
||||
const TELEMETRY_DDSTAT_SHOWN = 0;
|
||||
const TELEMETRY_DDSTAT_SHOWN_FIRST = 1;
|
||||
const TELEMETRY_DDSTAT_CLICKED = 2;
|
||||
|
@ -426,13 +221,7 @@ let gDecoderDoctorHandler = {
|
|||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.addMessageListener("DecoderDoctor:Notification", gDecoderDoctorHandler);
|
||||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.addMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
|
||||
window.addEventListener("unload", function() {
|
||||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.removeMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
|
||||
window
|
||||
.getGroupMessageManager("browsers")
|
||||
.removeMessageListener("DecoderDoctor:Notification", gDecoderDoctorHandler);
|
||||
|
|
|
@ -352,6 +352,19 @@ let JSWINDOWACTORS = {
|
|||
allFrames: true,
|
||||
},
|
||||
|
||||
EncryptedMedia: {
|
||||
parent: {
|
||||
moduleURI: "resource:///actors/EncryptedMediaParent.jsm",
|
||||
},
|
||||
|
||||
child: {
|
||||
moduleURI: "resource:///actors/EncryptedMediaChild.jsm",
|
||||
observers: ["mediakeys-request"],
|
||||
},
|
||||
|
||||
allFrames: true,
|
||||
},
|
||||
|
||||
FormValidation: {
|
||||
parent: {
|
||||
moduleURI: "resource:///actors/FormValidationParent.jsm",
|
||||
|
|
|
@ -28,14 +28,6 @@ ChromeUtils.defineModuleGetter(
|
|||
"resource:///modules/AboutNewTabService.jsm"
|
||||
);
|
||||
|
||||
var gEMEUIObserver = function(subject, topic, data) {
|
||||
let win = subject.top;
|
||||
let mm = getMessageManagerForWindow(win);
|
||||
if (mm) {
|
||||
mm.sendAsyncMessage("EMEVideo:ContentMediaKeysRequest", data);
|
||||
}
|
||||
};
|
||||
|
||||
var gDecoderDoctorObserver = function(subject, topic, data) {
|
||||
let win = subject.top;
|
||||
let mm = getMessageManagerForWindow(win);
|
||||
|
@ -48,7 +40,6 @@ function getMessageManagerForWindow(aContentWindow) {
|
|||
return aContentWindow.docShell.messageManager;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(gEMEUIObserver, "mediakeys-request");
|
||||
Services.obs.addObserver(gDecoderDoctorObserver, "decoder-doctor-notification");
|
||||
|
||||
// WebRTCChild observer registration. Actor observers require the subject
|
||||
|
|
Загрузка…
Ссылка в новой задаче