Bug 1791785 - When dumping symbols never emit INLINE_ORIGIN directives with an empty...
[gecko.git] / browser / actors / EncryptedMediaParent.jsm
blob8f71bc44e8aad4413457e4a9d86916a6ba185092
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/. */
6 "use strict";
8 var EXPORTED_SYMBOLS = ["EncryptedMediaParent"];
10 const { XPCOMUtils } = ChromeUtils.importESModule(
11   "resource://gre/modules/XPCOMUtils.sys.mjs"
14 const lazy = {};
16 XPCOMUtils.defineLazyGetter(lazy, "gBrandBundle", function() {
17   return Services.strings.createBundle(
18     "chrome://branding/locale/brand.properties"
19   );
20 });
22 XPCOMUtils.defineLazyGetter(lazy, "gNavigatorBundle", function() {
23   return Services.strings.createBundle(
24     "chrome://browser/locale/browser.properties"
25   );
26 });
28 XPCOMUtils.defineLazyGetter(lazy, "gFluentStrings", function() {
29   return new Localization(["branding/brand.ftl", "browser/browser.ftl"], true);
30 });
32 class EncryptedMediaParent extends JSWindowActorParent {
33   isUiEnabled() {
34     return Services.prefs.getBoolPref("browser.eme.ui.enabled");
35   }
37   ensureEMEEnabled(aBrowser, aKeySystem) {
38     Services.prefs.setBoolPref("media.eme.enabled", true);
39     if (
40       aKeySystem &&
41       aKeySystem == "com.widevine.alpha" &&
42       Services.prefs.getPrefType("media.gmp-widevinecdm.enabled") &&
43       !Services.prefs.getBoolPref("media.gmp-widevinecdm.enabled")
44     ) {
45       Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", true);
46     }
47     aBrowser.reload();
48   }
50   isKeySystemVisible(aKeySystem) {
51     if (!aKeySystem) {
52       return false;
53     }
54     if (
55       aKeySystem == "com.widevine.alpha" &&
56       Services.prefs.getPrefType("media.gmp-widevinecdm.visible")
57     ) {
58       return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
59     }
60     return true;
61   }
63   getMessageWithBrandName(aNotificationId) {
64     let msgId = "emeNotifications." + aNotificationId + ".message";
65     return lazy.gNavigatorBundle.formatStringFromName(msgId, [
66       lazy.gBrandBundle.GetStringFromName("brandShortName"),
67     ]);
68   }
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;
74     if (!browser) {
75       // We don't have a browser so bail!
76       return;
77     }
79     let parsedData;
80     try {
81       parsedData = JSON.parse(aMessage.data);
82     } catch (ex) {
83       Cu.reportError("Malformed EME video message with data: " + aMessage.data);
84       return;
85     }
86     let { status, keySystem } = parsedData;
88     // First, see if we need to do updates. We don't need to do anything for
89     // hidden keysystems:
90     if (!this.isKeySystemVisible(keySystem)) {
91       return;
92     }
93     if (status == "cdm-not-installed") {
94       Services.obs.notifyObservers(browser, "EMEVideo:CDMMissing");
95     }
97     // Don't need to show UI if disabled.
98     if (!this.isUiEnabled()) {
99       return;
100     }
102     let notificationId;
103     let buttonCallback;
104     let supportPage;
105     // Notification message can be either a string or a DOM fragment.
106     let notificationMessage;
107     switch (status) {
108       case "available":
109       case "cdm-created":
110         // Only show the chain icon for proprietary CDMs. Clearkey is not one.
111         if (keySystem != "org.w3.clearkey") {
112           this.showPopupNotificationForSuccess(browser, keySystem);
113         }
114         // ... and bail!
115         return;
117       case "api-disabled":
118       case "cdm-disabled":
119         notificationId = "drmContentDisabled";
120         buttonCallback = () => {
121           this.ensureEMEEnabled(browser, keySystem);
122         };
123         notificationMessage = lazy.gNavigatorBundle.GetStringFromName(
124           "emeNotifications.drmContentDisabled.message2"
125         );
126         supportPage = "drm-content";
127         break;
129       case "cdm-not-installed":
130         notificationId = "drmContentCDMInstalling";
131         notificationMessage = this.getMessageWithBrandName(notificationId);
132         break;
134       case "cdm-not-supported":
135         // Not to pop up user-level notification because they cannot do anything
136         // about it.
137         return;
138       default:
139         Cu.reportError(
140           new Error(
141             "Unknown message ('" +
142               status +
143               "') dealing with EME key request: " +
144               aMessage.data
145           )
146         );
147         return;
148     }
150     // Now actually create the notification
152     let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
153     if (notificationBox.getNotificationWithValue(notificationId)) {
154       return;
155     }
157     let buttons = [];
158     if (supportPage) {
159       buttons.push({ supportPage });
160     }
161     if (buttonCallback) {
162       let msgPrefix = "emeNotifications." + notificationId + ".";
163       let manageLabelId = msgPrefix + "button.label";
164       let manageAccessKeyId = msgPrefix + "button.accesskey";
165       buttons.push({
166         label: lazy.gNavigatorBundle.GetStringFromName(manageLabelId),
167         accessKey: lazy.gNavigatorBundle.GetStringFromName(manageAccessKeyId),
168         callback: buttonCallback,
169       });
170     }
172     let iconURL = "chrome://browser/skin/drm-icon.svg";
173     notificationBox.appendNotification(
174       notificationId,
175       {
176         label: notificationMessage,
177         image: iconURL,
178         priority: notificationBox.PRIORITY_INFO_HIGH,
179       },
180       buttons
181     );
182   }
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);
189       if (notification) {
190         notificationBox.removeNotification(notification);
191       }
192     });
194     // Don't bother creating it if it's already there:
195     if (
196       aBrowser.ownerGlobal.PopupNotifications.getNotification(
197         "drmContentPlaying",
198         aBrowser
199       )
200     ) {
201       return;
202     }
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";
211     let [
212       message,
213       manageLabel,
214       manageAccessKey,
215       dismissLabel,
216       dismissAccessKey,
217     ] = await lazy.gFluentStrings.formatValues([
218       msgId,
219       manageLabelId,
220       manageAccessKeyId,
221       dismissLabelId,
222       dismissAccessKeyId,
223     ]);
225     let anchorId = "eme-notification-icon";
226     let firstPlayPref = "browser.eme.ui.firstContentShown";
227     let document = aBrowser.ownerDocument;
228     if (
229       !Services.prefs.getPrefType(firstPlayPref) ||
230       !Services.prefs.getBoolPref(firstPlayPref)
231     ) {
232       document.getElementById(anchorId).setAttribute("firstplay", "true");
233       Services.prefs.setBoolPref(firstPlayPref, true);
234     } else {
235       document.getElementById(anchorId).removeAttribute("firstplay");
236     }
238     let mainAction = {
239       label: manageLabel,
240       accessKey: manageAccessKey,
241       callback() {
242         aBrowser.ownerGlobal.openPreferences("general-drm");
243       },
244       dismiss: true,
245     };
247     let secondaryActions = [
248       {
249         label: dismissLabel,
250         accessKey: dismissAccessKey,
251         callback: () => {},
252         dismiss: true,
253       },
254     ];
256     let options = {
257       dismissed: true,
258       eventCallback: aTopic => aTopic == "swapping",
259       learnMoreURL:
260         Services.urlFormatter.formatURLPref("app.support.baseURL") +
261         "drm-content",
262       hideClose: true,
263     };
264     aBrowser.ownerGlobal.PopupNotifications.show(
265       aBrowser,
266       "drmContentPlaying",
267       message,
268       anchorId,
269       mainAction,
270       secondaryActions,
271       options
272     );
273   }