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 { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
11 const { XPCOMUtils } = ChromeUtils.import(
12 "resource://gre/modules/XPCOMUtils.jsm"
15 XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
16 return Services.strings.createBundle(
17 "chrome://branding/locale/brand.properties"
21 XPCOMUtils.defineLazyGetter(this, "gNavigatorBundle", function() {
22 return Services.strings.createBundle(
23 "chrome://browser/locale/browser.properties"
27 XPCOMUtils.defineLazyGetter(this, "gFluentStrings", function() {
28 return new Localization(["branding/brand.ftl", "browser/browser.ftl"], true);
31 XPCOMUtils.defineLazyPreferenceGetter(
33 "gProtonDoorhangersEnabled",
34 "browser.proton.doorhangers.enabled",
38 class EncryptedMediaParent extends JSWindowActorParent {
40 return Services.prefs.getBoolPref("browser.eme.ui.enabled");
43 ensureEMEEnabled(aBrowser, aKeySystem) {
44 Services.prefs.setBoolPref("media.eme.enabled", true);
47 aKeySystem == "com.widevine.alpha" &&
48 Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
49 !Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")
51 Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
56 isKeySystemVisible(aKeySystem) {
61 aKeySystem == "com.widevine.alpha" &&
62 Services.prefs.getPrefType("media.gmp-widevinecdm.visible")
64 return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
69 getMessageWithBrandName(aNotificationId) {
70 let msgId = "emeNotifications." + aNotificationId + ".message";
71 return gNavigatorBundle.formatStringFromName(msgId, [
72 gBrandBundle.GetStringFromName("brandShortName"),
76 receiveMessage(aMessage) {
77 // The top level browsing context's embedding element should be a xul browser element.
78 let browser = this.browsingContext.top.embedderElement;
81 // We don't have a browser so bail!
87 parsedData = JSON.parse(aMessage.data);
89 Cu.reportError("Malformed EME video message with data: " + aMessage.data);
92 let { status, keySystem } = parsedData;
94 // First, see if we need to do updates. We don't need to do anything for
96 if (!this.isKeySystemVisible(keySystem)) {
99 if (status == "cdm-not-installed") {
100 Services.obs.notifyObservers(browser, "EMEVideo:CDMMissing");
103 // Don't need to show UI if disabled.
104 if (!this.isUiEnabled()) {
111 // Notification message can be either a string or a DOM fragment.
112 let notificationMessage;
116 // Only show the chain icon for proprietary CDMs. Clearkey is not one.
117 if (keySystem != "org.w3.clearkey") {
118 this.showPopupNotificationForSuccess(browser, keySystem);
125 notificationId = "drmContentDisabled";
126 buttonCallback = () => {
127 this.ensureEMEEnabled(browser, keySystem);
129 notificationMessage = gNavigatorBundle.GetStringFromName(
130 "emeNotifications.drmContentDisabled.message2"
132 supportPage = "drm-content";
135 case "cdm-not-installed":
136 notificationId = "drmContentCDMInstalling";
137 notificationMessage = this.getMessageWithBrandName(notificationId);
140 case "cdm-not-supported":
141 // Not to pop up user-level notification because they cannot do anything
147 "Unknown message ('" +
149 "') dealing with EME key request: " +
156 // Now actually create the notification
158 let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
159 if (notificationBox.getNotificationWithValue(notificationId)) {
165 buttons.push({ supportPage });
167 if (buttonCallback) {
168 let msgPrefix = "emeNotifications." + notificationId + ".";
169 let manageLabelId = msgPrefix + "button.label";
170 let manageAccessKeyId = msgPrefix + "button.accesskey";
172 label: gNavigatorBundle.GetStringFromName(manageLabelId),
173 accessKey: gNavigatorBundle.GetStringFromName(manageAccessKeyId),
174 callback: buttonCallback,
178 let iconURL = "chrome://browser/skin/drm-icon.svg";
179 notificationBox.appendNotification(
183 notificationBox.PRIORITY_INFO_HIGH,
188 async showPopupNotificationForSuccess(aBrowser) {
189 // We're playing EME content! Remove any "we can't play because..." messages.
190 let notificationBox = aBrowser.getTabBrowser().getNotificationBox(aBrowser);
191 ["drmContentDisabled", "drmContentCDMInstalling"].forEach(function(value) {
192 let notification = notificationBox.getNotificationWithValue(value);
194 notificationBox.removeNotification(notification);
198 // Don't bother creating it if it's already there:
200 aBrowser.ownerGlobal.PopupNotifications.getNotification(
208 let msgPrefix = "eme-notifications-drm-content-playing";
209 let msgId = msgPrefix;
210 let manageLabelId = msgPrefix + "-manage";
211 let manageAccessKeyId = msgPrefix + "-manage-accesskey";
212 let dismissLabelId = msgPrefix + "-dismiss";
213 let dismissAccessKeyId = msgPrefix + "-dismiss-accesskey";
221 ] = await gFluentStrings.formatValues([
229 let anchorId = "eme-notification-icon";
230 let firstPlayPref = "browser.eme.ui.firstContentShown";
231 let document = aBrowser.ownerDocument;
233 !Services.prefs.getPrefType(firstPlayPref) ||
234 !Services.prefs.getBoolPref(firstPlayPref)
236 document.getElementById(anchorId).setAttribute("firstplay", "true");
237 Services.prefs.setBoolPref(firstPlayPref, true);
239 document.getElementById(anchorId).removeAttribute("firstplay");
244 accessKey: manageAccessKey,
246 aBrowser.ownerGlobal.openPreferences("general-drm");
249 disableHighlight: gProtonDoorhangersEnabled,
252 let secondaryActions = [
255 accessKey: dismissAccessKey,
263 eventCallback: aTopic => aTopic == "swapping",
265 Services.urlFormatter.formatURLPref("app.support.baseURL") +
269 aBrowser.ownerGlobal.PopupNotifications.show(