chromium/third_party/blink/web_tests/media/encrypted-media/encrypted-media-playback-before-setmediakeys.html

<!DOCTYPE html>
<html>
    <head>
        <title>Playback before SetMediaKeys</title>
        <script src="encrypted-media-utils.js"></script>
        <script src="../../resources/testharness.js"></script>
        <script src="../../resources/testharnessreport.js"></script>
    </head>
    <body>
        <video></video>
        <script>
            promise_test(function(test)
            {
                var video = document.querySelector('video');
                var content = '../content/test-encrypted.webm';
                var mediaKeys;
                var initData;
                var initDataType;
                var mediaKeySession;


                // As this code doesn't wait for the 'message' event to avoid
                // race conditions with 'waitingforkey', specify the key ID and
                // key used by the encrypted content.
                var keyId = stringToUint8Array('0123456789012345');
                var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
                                             0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);

                return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getConfigurationForFile(content)).then(function(access) {
                    return access.createMediaKeys();
                }).then(function(result) {
                    // Store mediaKeys without setting it on the video.
                    mediaKeys = result;
                    video.src = content;
                    video.play();
                    return wait_for_encrypted_event(video);
                }).then(function(e) {
                    // Received the 'encrypted' event(s), so keep a copy of
                    // the initdata for use when creating the session later.
                    initData = e.initData;
                    initDataType = e.initDataType;

                    // Wait until the video indicates that it needs a key to
                    // continue.
                    return wait_for_waitingforkey_event(video);
                }).then(function() {
                    // Make sure the video is NOT paused and not progressing
                    // before a key is provided. This requires the video
                    // to NOT have a clear lead.
                    assert_false(video.paused);
                    assert_equals(video.currentTime, 0);

                    // Create a session.
                    mediaKeySession = mediaKeys.createSession();
                    return mediaKeySession.generateRequest(initDataType, initData);
                }).then(function() {
                    // generateRequest() will cause a 'message' event to
                    // occur specifying the keyId that is needed, but we
                    // ignore it since we already know what keyId is needed.
                    // Add the key needed to decrypt.
                    var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
                    return mediaKeySession.update(jwkSet);
                }).then(function() {
                    // Now setMediaKeys() and playback should start.
                    return video.setMediaKeys(mediaKeys);
                }).then(function() {
                    // Video should start playing now that it can decrypt the
                    // streams, so wait until a little bit of the video has
                    // played.
                    return wait_for_timeupdate_event(video);
                });

                // Typical test duration is 6 seconds on release builds
                // (12 seconds on debug). Since the test is timing out anyway,
                // make the duration 5 seconds so that the timeout function
                // is actually called (instead of simply aborting the test).
            }, 'Playback before SetMediaKeys', { timeout: 5000 });

            // Wait for a pair of 'encrypted' events. Promise resolved on
            // second event.
            function wait_for_encrypted_event(video)
            {
                var encryptedEventCount = 0;
                return new Promise(function(resolve) {
                    video.addEventListener('encrypted', function listener(e) {
                        assert_equals(e.target, video);
                        assert_true(e instanceof window.MediaEncryptedEvent);
                        assert_equals(e.type, 'encrypted');

                        // The same decryption key is used by both the audio
                        // and the video streams so wait for the second event
                        // to ensure we see both events.
                        if (++encryptedEventCount != 2)
                            return;

                        video.removeEventListener('encrypted', listener);
                        resolve(e);
                    });
                });
            };

            // Wait for a 'waitingforkey' event. Promise resolved when the
            // event is received.
            function wait_for_waitingforkey_event(video)
            {
                return new Promise(function(resolve) {
                    video.addEventListener('waitingforkey', function listener(e) {
                        assert_equals(e.target, video);
                        assert_equals(e.type, 'waitingforkey');
                        video.removeEventListener('waitingforkey', listener);
                        resolve(e);
                    });
                });
            };

            // Wait for a 'timeupdate' event. Promise resolved if |video| has
            // played for more than 0.2 seconds.
            function wait_for_timeupdate_event(video)
            {
                return new Promise(function(resolve) {
                    video.addEventListener('timeupdate', function listener(e) {
                        assert_equals(e.target, video);
                        if (video.currentTime < 0.2)
                            return;
                        video.removeEventListener('timeupdate', listener);
                        resolve(e);
                    });
                });
            };
        </script>
    </body>
</html>