1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // The PlayerUtils provides utility functions to binding common media events
6 // to specific player functions. It also provides functions to load media source
7 // base on test configurations.
8 var PlayerUtils
= new function() {
11 // Prepares a video element for playback by setting default event handlers
12 // and source attribute.
13 PlayerUtils
.registerDefaultEventListeners = function(player
) {
14 Utils
.timeLog('Registering video event handlers.');
15 // Map from event name to event listener function name. It is common for
16 // event listeners to be named onEventName.
17 var eventListenerMap
= {
18 'encrypted': 'onEncrypted',
19 'webkitneedkey': 'onWebkitNeedKey',
20 'webkitkeymessage': 'onWebkitKeyMessage',
21 'webkitkeyadded': 'onWebkitKeyAdded',
22 'webkitkeyerror': 'onWebkitKeyError'
24 for (eventName
in eventListenerMap
) {
25 var eventListenerFunction
= player
[eventListenerMap
[eventName
]];
26 if (eventListenerFunction
) {
27 player
.video
.addEventListener(eventName
, function(e
) {
28 player
[eventListenerMap
[e
.type
]](e
);
33 player
.video
.addEventListener('error', function(error
) {
34 // This most likely happens on pipeline failures (e.g. when the CDM
36 Utils
.timeLog('onHTMLElementError', error
);
37 Utils
.failTest(error
);
41 // Register the necessary event handlers needed when playing encrypted content
42 // using the unprefixed API. Returns a promise that resolves to the player.
43 PlayerUtils
.registerEMEEventListeners = function(player
) {
44 player
.video
.addEventListener('encrypted', function(message
) {
46 function addMediaKeySessionListeners(mediaKeySession
) {
47 mediaKeySession
.addEventListener('message', function(message
) {
48 player
.video
.receivedKeyMessage
= true;
49 if (Utils
.isRenewalMessage(message
)) {
50 Utils
.timeLog('MediaKeySession onMessage - renewal', message
);
51 player
.video
.receivedRenewalMessage
= true;
53 if (message
.messageType
!= 'license-request') {
54 Utils
.failTest('Unexpected message type "' + message
.messageType
+
56 EME_MESSAGE_UNEXPECTED_TYPE
);
59 player
.onMessage(message
);
64 if (player
.testConfig
.sessionToLoad
) {
65 Utils
.timeLog('Loading session: ' + player
.testConfig
.sessionToLoad
);
67 message
.target
.mediaKeys
.createSession('persistent-license');
68 addMediaKeySessionListeners(session
);
69 session
.load(player
.testConfig
.sessionToLoad
)
73 Utils
.failTest('Session not found.', EME_SESSION_NOT_FOUND
);
75 function(error
) { Utils
.failTest(error
, EME_LOAD_FAILED
); });
77 Utils
.timeLog('Creating new media key session for initDataType: ' +
78 message
.initDataType
+ ', initData: ' +
79 Utils
.getHexString(new Uint8Array(message
.initData
)));
80 var session
= message
.target
.mediaKeys
.createSession();
81 addMediaKeySessionListeners(session
);
82 session
.generateRequest(message
.initDataType
, message
.initData
)
83 .catch(function(error
) {
84 // Ignore the error if a crash is expected. This ensures that
85 // the decoder actually detects and reports the error.
86 if (this.testConfig
.keySystem
!=
87 'org.chromium.externalclearkey.crash') {
88 Utils
.failTest(error
, EME_GENERATEREQUEST_FAILED
);
97 this.registerDefaultEventListeners(player
);
98 player
.video
.receivedKeyMessage
= false;
99 Utils
.timeLog('Setting video media keys: ' + player
.testConfig
.keySystem
);
101 if (player
.testConfig
.sessionToLoad
) {
103 persistentState
: "required",
104 sessionTypes
: ["temporary", "persistent-license"]
107 return navigator
.requestMediaKeySystemAccess(
108 player
.testConfig
.keySystem
, [config
])
109 .then(function(access
) { return access
.createMediaKeys(); })
110 .then(function(mediaKeys
) {
111 return player
.video
.setMediaKeys(mediaKeys
);
113 .then(function(result
) { return player
; })
114 .catch(function(error
) { Utils
.failTest(error
, NOTSUPPORTEDERROR
); });
117 // Register the necessary event handlers needed when playing encrypted content
118 // using the prefixed API. Even though the prefixed API is all synchronous,
119 // returns a promise that resolves to the player.
120 PlayerUtils
.registerPrefixedEMEEventListeners = function(player
) {
121 player
.video
.addEventListener('webkitneedkey', function(message
) {
122 var initData
= message
.initData
;
123 if (player
.testConfig
.sessionToLoad
) {
124 Utils
.timeLog('Loading session: ' + player
.testConfig
.sessionToLoad
);
126 Utils
.convertToUint8Array(PREFIXED_EME_API_LOAD_SESSION_HEADER
+
127 player
.testConfig
.sessionToLoad
);
129 Utils
.timeLog(player
.testConfig
.keySystem
+
130 ' Generate key request, initData: ' +
131 Utils
.getHexString(initData
));
133 message
.target
.webkitGenerateKeyRequest(player
.testConfig
.keySystem
,
140 player
.video
.addEventListener('webkitkeyadded', function(message
) {
141 Utils
.timeLog('onWebkitKeyAdded', message
);
142 message
.target
.receivedKeyAdded
= true;
145 player
.video
.addEventListener('webkitkeyerror', function(error
) {
146 Utils
.timeLog('onWebkitKeyError',
147 'KeySystem: ' + error
.keySystem
+ ', sessionId: ' +
148 error
.sessionId
+ ', errorCode: ' + error
.errorCode
.code
+
149 ', systemCode: ' + error
.systemCode
);
150 Utils
.failTest(error
, PREFIXED_EME_ERROR_EVENT
);
153 player
.video
.addEventListener('webkitkeymessage', function(message
) {
154 Utils
.timeLog('onWebkitKeyMessage', message
);
155 message
.target
.receivedKeyMessage
= true;
156 if (Utils
.isRenewalMessagePrefixed(message
.message
)) {
157 Utils
.timeLog('onWebkitKeyMessage - renewal', message
);
158 message
.target
.receivedRenewalMessage
= true;
162 // The prefixed API is all synchronous, so wrap the calls in a promise.
163 return new Promise(function(resolve
, reject
) {
164 PlayerUtils
.registerDefaultEventListeners(player
);
165 player
.video
.receivedKeyMessage
= false;
170 PlayerUtils
.setVideoSource = function(player
) {
171 if (player
.testConfig
.useMSE
) {
172 Utils
.timeLog('Loading media using MSE.');
174 MediaSourceUtils
.loadMediaSourceFromTestConfig(player
.testConfig
);
175 player
.video
.src
= window
.URL
.createObjectURL(mediaSource
);
177 Utils
.timeLog('Loading media using src.');
178 player
.video
.src
= player
.testConfig
.mediaFile
;
182 // Initialize the player to play encrypted content. Returns a promise that
183 // resolves to the player.
184 PlayerUtils
.initEMEPlayer = function(player
) {
185 return player
.registerEventListeners().then(function(result
) {
186 PlayerUtils
.setVideoSource(player
);
191 // Return the appropriate player based on test configuration.
192 PlayerUtils
.createPlayer = function(video
, testConfig
) {
193 // Update keySystem if using prefixed Clear Key since it is not available as a
194 // separate key system to choose from; however it can be set in URL query.
195 var usePrefixedEME
= testConfig
.usePrefixedEME
;
196 if (testConfig
.keySystem
== CLEARKEY
&& usePrefixedEME
)
197 testConfig
.keySystem
= PREFIXED_CLEARKEY
;
199 function getPlayerType(keySystem
) {
201 case WIDEVINE_KEYSYSTEM
:
203 return PrefixedWidevinePlayer
;
204 return WidevinePlayer
;
205 case PREFIXED_CLEARKEY
:
206 return PrefixedClearKeyPlayer
;
207 case EXTERNAL_CLEARKEY
:
210 return PrefixedClearKeyPlayer
;
211 return ClearKeyPlayer
;
212 case FILE_IO_TEST_KEYSYSTEM
:
213 return FileIOTestPlayer
;
215 Utils
.timeLog(keySystem
+ ' is not a known key system');
217 return PrefixedClearKeyPlayer
;
218 return ClearKeyPlayer
;
221 var Player
= getPlayerType(testConfig
.keySystem
);
222 return new Player(video
, testConfig
);