190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var keySystem = QueryString.keysystem;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var mediaFile = QueryString.mediafile;
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvar mediaType = QueryString.mediatype || 'video/webm; codecs="vorbis, vp8"';
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvar useMSE = QueryString.usemse == 1;
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default key used to encrypt many media files used in browser tests.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var KEY = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// KEY_ID constant used as init data while encrypting test media files.
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var KEY_ID = getInitDataFromKeyId("0123456789012345");
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Heart beat message header.
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var HEART_BEAT_HEADER = 'HEARTBEAT';
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var EXTERNAL_CLEAR_KEY_KEY_SYSTEM = "org.chromium.externalclearkey";
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Note that his URL has been normalized from the one in clear_key_cdm.cc.
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var EXTERNAL_CLEAR_KEY_HEARTBEAT_URL =
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    'http://test.externalclearkey.chromium.org/';
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function isHeartbeatMessage(msg) {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (msg.length < HEART_BEAT_HEADER.length)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < HEART_BEAT_HEADER.length; ++i) {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (String.fromCharCode(msg[i]) != HEART_BEAT_HEADER[i])
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function loadEncryptedMediaFromURL(video) {
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return loadEncryptedMedia(video, mediaFile, keySystem, KEY, useMSE);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfunction loadEncryptedMedia(video, mediaFile, keySystem, key, useMSE,
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            appendSourceCallbackFn) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var keyRequested = false;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var sourceOpened = false;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add properties to enable verification that events occurred.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  video.receivedKeyAdded = false;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  video.receivedHeartbeat = false;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  video.isHeartbeatExpected = keySystem === EXTERNAL_CLEAR_KEY_KEY_SYSTEM;
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  video.receivedKeyMessage = false;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!(video && mediaFile && keySystem && key)) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    failTest('Missing parameters in loadEncryptedMedia().');
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function onNeedKey(e) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (keyRequested)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keyRequested = true;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    console.log('onNeedKey', e);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      video.webkitGenerateKeyRequest(keySystem, e.initData);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    catch(error) {
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      setResultInTitle(error.name);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  function onKeyAdded(e) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    e.target.receivedKeyAdded = true;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function onKeyMessage(e) {
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    video.receivedKeyMessage = true;
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!e.keySystem || e.keySystem != keySystem) {
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      failTest('keymessage with unexpected keySystem: ' + e.keySystem);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!e.sessionId) {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      failTest('keymessage without a sessionId: ' + e.sessionId);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!e.message) {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      failTest('keymessage without a message: ' + e.message);
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (isHeartbeatMessage(e.message)) {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      console.log('onKeyMessage - heartbeat', e);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      e.target.receivedHeartbeat = true;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      verifyHeartbeatMessage(e);
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // No tested key system returns defaultURL in for key request messages.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (e.defaultURL) {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      failTest('keymessage unexpectedly has defaultURL: ' + e.defaultURL);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // keymessage in response to generateKeyRequest. Reply with key.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    console.log('onKeyMessage - key request', e);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var initData = e.message;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (mediaType.indexOf('mp4') != -1)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      initData = KEY_ID; // Temporary hack for Clear Key in v0.1.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    video.webkitAddKey(keySystem, key, initData);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  function verifyHeartbeatMessage(e) {
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Only External Clear Key sends a HEARTBEAT message.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (e.keySystem != EXTERNAL_CLEAR_KEY_KEY_SYSTEM) {
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      failTest('Unexpected heartbeat from ' + e.keySystem);
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (e.defaultURL != EXTERNAL_CLEAR_KEY_HEARTBEAT_URL) {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      failTest('Heartbeat message with unexpected defaultURL: ' + e.defaultURL);
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  video.addEventListener('webkitneedkey', onNeedKey);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  video.addEventListener('webkitkeymessage', onKeyMessage);
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  video.addEventListener('webkitkeyerror', function() {
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      setResultInTitle("KeyError");
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  });
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  video.addEventListener('webkitkeyadded', onKeyAdded);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  installTitleEventHandler(video, 'error');
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (useMSE) {
1287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    var mediaSource = loadMediaSource(mediaFile, mediaType,
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                      appendSourceCallbackFn);
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    video.src = window.URL.createObjectURL(mediaSource);
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    video.src = mediaFile;
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function getInitDataFromKeyId(keyID) {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var init_key_id = new Uint8Array(keyID.length);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for(var i = 0; i < keyID.length; i++) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    init_key_id[i] = keyID.charCodeAt(i);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return init_key_id;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
143