1 /* vim: set ts=2 sw=2 sts=2 et tw=80: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 var EXPORTED_SYMBOLS = ["EncryptedMediaParent"];
10 const { XPCOMUtils } = ChromeUtils.importESModule(
11 "resource://gre/modules/XPCOMUtils.sys.mjs"
16 XPCOMUtils.defineLazyGetter(lazy, "gBrandBundle", function() {
17 return Services.strings.createBundle(
18 "chrome://branding/locale/brand.properties"
22 XPCOMUtils.defineLazyGetter(lazy, "gNavigatorBundle", function() {
23 return Services.strings.createBundle(
24 "chrome://browser/locale/browser.properties"
28 XPCOMUtils.defineLazyGetter(lazy, "gFluentStrings", function() {
29 return new Localization(["branding/brand.ftl", "browser/browser.ftl"], true);
32 class EncryptedMediaParent extends JSWindowActorParent {
34 return Services.prefs.getBoolPref("browser.eme.ui.enabled");
37 ensureEMEEnabled(aBrowser, aKeySystem) {
38 Services.prefs.setBoolPref("media.eme.enabled", true);
41 aKeySystem == "com.widevine.alpha" &&
42 Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
43 !Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")
45 Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
50 isKeySystemVisible(aKeySystem) {
55 aKeySystem == "com.widevine.alpha" &&
56 Services.prefs.getPrefType("media.gmp-widevinecdm.visible")
58 return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
63 getMessageWithBrandName(aNotificationId) {
64 let msgId = "emeNotifications." + aNotificationId + ".message";
65 return lazy.gNavigatorBundle.formatStringFromName(msgId, [
66 lazy.gBrandBundle.GetStringFromName("brandShortName"),
70 receiveMessage(aMessage) {
71 // The top level browsing context's embedding element should be a xul browser element.
72 let browser = this.browsingContext.top.embedderElement;
75 // We don't have a browser so bail!
81 parsedData = JSON.parse(aMessage.data);
83 Cu.reportError("Malformed EME video message with data: " + aMessage.data);
86 let { status, keySystem } = parsedData;
88 // First, see if we need to do updates. We don't need to do anything for
90 if (!this.isKeySystemVisible(keySystem)) {
93 if (status == "cdm-not-installed") {
94 Services.obs.notifyObservers(browser, "EMEVideo:CDMMissing");
97 // Don't need to show UI if disabled.
98 if (!this.isUiEnabled()) {
105 // Notification message can be either a string or a DOM fragment.
106 let notificationMessage;
110 // Only show the chain icon for proprietary CDMs. Clearkey is not one.
111 if (keySystem != "org.w3.clearkey") {
112 this.showPopupNotificationForSuccess(browser, keySystem);
119 notificationId = "drmContentDisabled";
120 buttonCallback = () => {
121 this.ensureEMEEnabled(browser, keySystem);
123 notificationMessage = lazy.gNavigatorBundle.GetStringFromName(
124 "emeNotifications.drmContentDisabled.message2"
126 supportPage = "drm-content";
129 case "cdm-not-installed":
130 notificationId = "drmContentCDMInstalling";
131 notificationMessage = this.getMessageWithBrandName(notificationId);
134 case "cdm-not-supported":
135 // Not to pop up user-level notification because they cannot do anything
141 "Unknown message ('" +
143 "') dealing with EME key request: " +
150 // Now actually create the notification
152 let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
153 if (notificationBox.getNotificationWithValue(notificationId)) {
159 buttons.push({ supportPage });
161 if (buttonCallback) {
162 let msgPrefix = "emeNotifications." + notificationId + ".";
163 let manageLabelId = msgPrefix + "button.label";
164 let manageAccessKeyId = msgPrefix + "button.accesskey";
166 label: lazy.gNavigatorBundle.GetStringFromName(manageLabelId),
167 accessKey: lazy.gNavigatorBundle.GetStringFromName(manageAccessKeyId),
168 callback: buttonCallback,
172 let iconURL = "chrome://browser/skin/drm-icon.svg";
173 notificationBox.appendNotification(
176 label: notificationMessage,
178 priority: notificationBox.PRIORITY_INFO_HIGH,
184 async showPopupNotificationForSuccess(aBrowser) {
185 // We're playing EME content! Remove any "we can't play because..." messages.
186 let notificationBox = aBrowser.getTabBrowser().getNotificationBox(aBrowser);
187 ["drmContentDisabled", "drmContentCDMInstalling"].forEach(function(value) {
188 let notification = notificationBox.getNotificationWithValue(value);
190 notificationBox.removeNotification(notification);
194 // Don't bother creating it if it's already there:
196 aBrowser.ownerGlobal.PopupNotifications.getNotification(
204 let msgPrefix = "eme-notifications-drm-content-playing";
205 let msgId = msgPrefix;
206 let manageLabelId = msgPrefix + "-manage";
207 let manageAccessKeyId = msgPrefix + "-manage-accesskey";
208 let dismissLabelId = msgPrefix + "-dismiss";
209 let dismissAccessKeyId = msgPrefix + "-dismiss-accesskey";
217 ] = await lazy.gFluentStrings.formatValues([
225 let anchorId = "eme-notification-icon";
226 let firstPlayPref = "browser.eme.ui.firstContentShown";
227 let document = aBrowser.ownerDocument;
229 !Services.prefs.getPrefType(firstPlayPref) ||
230 !Services.prefs.getBoolPref(firstPlayPref)
232 document.getElementById(anchorId).setAttribute("firstplay", "true");
233 Services.prefs.setBoolPref(firstPlayPref, true);
235 document.getElementById(anchorId).removeAttribute("firstplay");
240 accessKey: manageAccessKey,
242 aBrowser.ownerGlobal.openPreferences("general-drm");
247 let secondaryActions = [
250 accessKey: dismissAccessKey,
258 eventCallback: aTopic => aTopic == "swapping",
260 Services.urlFormatter.formatURLPref("app.support.baseURL") +
264 aBrowser.ownerGlobal.PopupNotifications.show(