Files
shaka-player/test/util/pssh_unit.js
T
Joey Parrish 11f3347a48 Fix static method aliases
We used to alias static utility methods by assigning the method itself
to a local variable.  This is not allowed by the new Closure Compiler
release that we are adopting, and for good reason.

The old compiler did not understand the use of "this" in static
methods, but the new one does.  And it turns out that when we start
using "this" in static methods (see #2532), aliasing the method itself
can break everything.

When you refer to "this" in a static method, it refers to the class.
This is really useful in utility classes that have private static
methods they use to perform common tasks.  However, just as it ruins
the value of "this" to alias an instance method, the same is true of
an ES6 class's static method.

The fix is to always alias the class instead of the method.  The new
compiler will simply not let us get away with the old way any more, so
regressions after this are unlikely.

Issue #2528 (compiler upgrade)
Issue #2532 (static "this")

Change-Id: Id800d466e639c7cbcf4aa6fbb05114c772a2229f
2020-04-30 19:28:53 +00:00

226 lines
9.3 KiB
JavaScript

/** @license
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
describe('Pssh', () => {
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
const WIDEVINE_SYSTEM_ID = 'edef8ba979d64acea3c827dcd51d21ed';
const PLAYREADY_SYSTEM_ID = '9a04f07998404286ab92e65be0885f95';
const GENERIC_SYSTEM_ID = '1077efecc0b24d02ace33c1e52e2fb4b';
const WIDEVINE_PSSH =
'00000028' + // atom size
'70737368' + // atom type='pssh'
'00000000' + // v0, flags=0
'edef8ba979d64acea3c827dcd51d21ed' + // system id (Widevine)
'00000008' + // data size
'0102030405060708'; // data
const PLAYREADY_PSSH =
'00000028' + // atom size
'70737368' + // atom type 'pssh'
'00000000' + // v0, flags=0
'9a04f07998404286ab92e65be0885f95' + // system id (PlayReady)
'00000008' + // data size
'0102030405060708'; // data
const GENERIC_PSSH =
'00000044' + // atom size
'70737368' + // atom type 'pssh'
'01000000' + // v1, flags=0
'1077efecc0b24d02ace33c1e52e2fb4b' + // system id (generic CENC)
'00000002' + // key ID count
'30313233343536373839303132333435' + // key ID='0123456789012345'
'38393031323334354142434445464748' + // key ID='ABCDEFGHIJKLMNOP'
'00000000'; // data size=0
const ZERO_SIZED_GENERIC_PSSH =
'00000000' + // atom size (whole buffer)
'70737368' + // atom type='pssh'
'01000000' + // v1, flags=0
'1077efecc0b24d02ace33c1e52e2fb4b' + // system id (generic CENC)
'00000002' + // key ID count
'30313233343536373839303132333435' + // key ID='0123456789012345'
'38393031323334354142434445464748' + // key ID='ABCDEFGHIJKLMNOP'
'00000000'; // data size=0
const OTHER_BOX =
'00000018' + // atom size
'77686174' + // atom type 'what'
'deadbeefdeadbeefdeadbeefdeadbeef'; // garbage box data
const TRUNCATED_WIDEVINE_PSSH =
WIDEVINE_PSSH.substr(0, WIDEVINE_PSSH.length - 6);
const TRUNCATED_PLAYREADY_PSSH =
PLAYREADY_PSSH.substr(0, PLAYREADY_PSSH.length - 6);
const TRUNCATED_GENERIC_PSSH =
GENERIC_PSSH.substr(0, GENERIC_PSSH.length - 6);
it('parses a Widevine PSSH', () => {
const pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(WIDEVINE_PSSH));
expect(pssh.systemIds.length).toBe(1);
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(0);
});
it('parses a PlayReady PSSH', () => {
const pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(PLAYREADY_PSSH));
expect(pssh.systemIds.length).toBe(1);
expect(pssh.systemIds[0]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(0);
});
it('parses a generic CENC PSSH', () => {
const pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(GENERIC_PSSH));
expect(pssh.systemIds.length).toBe(1);
expect(pssh.systemIds[0]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
});
it('throws on a truncated PSSH', () => {
const psshs = [
Uint8ArrayUtils.fromHex(TRUNCATED_WIDEVINE_PSSH),
Uint8ArrayUtils.fromHex(TRUNCATED_PLAYREADY_PSSH),
Uint8ArrayUtils.fromHex(TRUNCATED_GENERIC_PSSH),
Uint8ArrayUtils.fromHex(WIDEVINE_PSSH + TRUNCATED_PLAYREADY_PSSH),
Uint8ArrayUtils.fromHex(WIDEVINE_PSSH + TRUNCATED_GENERIC_PSSH),
Uint8ArrayUtils.fromHex(PLAYREADY_PSSH + TRUNCATED_WIDEVINE_PSSH),
Uint8ArrayUtils.fromHex(PLAYREADY_PSSH + TRUNCATED_GENERIC_PSSH),
Uint8ArrayUtils.fromHex(GENERIC_PSSH + TRUNCATED_WIDEVINE_PSSH),
Uint8ArrayUtils.fromHex(GENERIC_PSSH + TRUNCATED_PLAYREADY_PSSH),
];
for (const pssh of psshs) {
const expected = shaka.test.Util.jasmineError(new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.MEDIA,
shaka.util.Error.Code.BUFFER_READ_OUT_OF_BOUNDS));
expect(() => new shaka.util.Pssh(pssh)).toThrow(expected);
}
});
it('parses concatenated PSSHs in any order', () => {
let pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
WIDEVINE_PSSH + PLAYREADY_PSSH));
expect(pssh.systemIds.length).toBe(2);
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(0);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
PLAYREADY_PSSH + WIDEVINE_PSSH));
expect(pssh.systemIds[0]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(0);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
WIDEVINE_PSSH + GENERIC_PSSH));
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
GENERIC_PSSH + WIDEVINE_PSSH));
expect(pssh.systemIds[0]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
WIDEVINE_PSSH + PLAYREADY_PSSH + GENERIC_PSSH));
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.systemIds[2]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
PLAYREADY_PSSH + WIDEVINE_PSSH + GENERIC_PSSH));
expect(pssh.systemIds[0]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.systemIds[2]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
WIDEVINE_PSSH + GENERIC_PSSH + PLAYREADY_PSSH));
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.systemIds[2]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
PLAYREADY_PSSH + GENERIC_PSSH + WIDEVINE_PSSH));
expect(pssh.systemIds[0]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.systemIds[2]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
GENERIC_PSSH + WIDEVINE_PSSH + PLAYREADY_PSSH));
expect(pssh.systemIds[0]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.systemIds[2]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
GENERIC_PSSH + PLAYREADY_PSSH + WIDEVINE_PSSH));
expect(pssh.systemIds[0]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.systemIds[2]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
});
it('ignores non-PSSH boxes and continues parsing', () => {
let pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
OTHER_BOX + WIDEVINE_PSSH));
expect(pssh.systemIds.length).toBe(1);
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
WIDEVINE_PSSH + OTHER_BOX));
expect(pssh.systemIds.length).toBe(1);
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(0);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
PLAYREADY_PSSH + OTHER_BOX + WIDEVINE_PSSH));
expect(pssh.systemIds.length).toBe(2);
expect(pssh.systemIds[0]).toBe(PLAYREADY_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(0);
});
it('parses a zero-sized PSSH box', () => {
let pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
ZERO_SIZED_GENERIC_PSSH));
expect(pssh.systemIds.length).toBe(1);
expect(pssh.systemIds[0]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
pssh = new shaka.util.Pssh(Uint8ArrayUtils.fromHex(
WIDEVINE_PSSH + ZERO_SIZED_GENERIC_PSSH));
expect(pssh.systemIds.length).toBe(2);
expect(pssh.systemIds[0]).toBe(WIDEVINE_SYSTEM_ID);
expect(pssh.systemIds[1]).toBe(GENERIC_SYSTEM_ID);
expect(pssh.cencKeyIds.length).toBe(2);
});
it('extracts boundaries for concatenated boxes', () => {
const psshData = Uint8ArrayUtils.fromHex(
GENERIC_PSSH +
WIDEVINE_PSSH +
OTHER_BOX +
PLAYREADY_PSSH);
const pssh = new shaka.util.Pssh(psshData);
expect(pssh.data.length).toBe(3);
expect(Uint8ArrayUtils.toHex(pssh.data[0])).toBe(GENERIC_PSSH);
expect(Uint8ArrayUtils.toHex(pssh.data[1])).toBe(WIDEVINE_PSSH);
expect(Uint8ArrayUtils.toHex(pssh.data[2])).toBe(PLAYREADY_PSSH);
});
});