diff --git a/src/experimental/tools/DummyMediaElement/eme.ts b/src/experimental/tools/DummyMediaElement/eme.ts index 9a5f5657e5..e9b2d6288d 100644 --- a/src/experimental/tools/DummyMediaElement/eme.ts +++ b/src/experimental/tools/DummyMediaElement/eme.ts @@ -574,6 +574,10 @@ export class DummyMediaKeySession return Promise.resolve(); } + public getPolicyLevel(): number { + return this._currentPolicyLevel; + } + public updatePolicyLevel(newLevel: number) { this._currentPolicyLevel = newLevel; diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/index.mjs b/tests/contents/DASH_DRM_static_SegmentTemplate/index.mjs new file mode 100644 index 0000000000..2dc7a001cf --- /dev/null +++ b/tests/contents/DASH_DRM_static_SegmentTemplate/index.mjs @@ -0,0 +1,3 @@ +import manifestInfos from "./infos.mjs"; + +export { manifestInfos }; diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/infos.mjs b/tests/contents/DASH_DRM_static_SegmentTemplate/infos.mjs new file mode 100644 index 0000000000..b7d7b6a861 --- /dev/null +++ b/tests/contents/DASH_DRM_static_SegmentTemplate/infos.mjs @@ -0,0 +1,31 @@ +const BASE_URL = + "http://" + + /* eslint-disable no-undef */ + __TEST_CONTENT_SERVER__.URL + + ":" + + __TEST_CONTENT_SERVER__.PORT + + /* eslint-enable no-undef */ + "/DASH_DRM_static_SegmentTemplate/media/"; + +export default { + url: BASE_URL + "encrypted_multiple_keys_number.mpd", + transport: "dash", + isDynamic: false, + isLive: false, + duration: 734, + minimumPosition: 0, + maximumPosition: 734, + availabilityStartTime: 0, + periods: [ + { + start: 0, + duration: 734, + // TODO? + adaptations: { + audio: [], + video: [], + text: [], + }, + }, + ], +}; diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/1-80399bf5/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/1-80399bf5/0001.m4s new file mode 100644 index 0000000000..a134aadb65 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/1-80399bf5/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/1-80399bf5/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/1-80399bf5/init.mp4 new file mode 100644 index 0000000000..60f5b35025 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/1-80399bf5/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/10-80399bf5/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/10-80399bf5/0001.m4s new file mode 100644 index 0000000000..e27d7b6df2 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/10-80399bf5/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/10-80399bf5/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/10-80399bf5/init.mp4 new file mode 100644 index 0000000000..2d58806369 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/10-80399bf5/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/11-90953e09/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/11-90953e09/0001.m4s new file mode 100644 index 0000000000..39f4234773 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/11-90953e09/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/11-90953e09/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/11-90953e09/init.mp4 new file mode 100644 index 0000000000..2886e3e12c Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/11-90953e09/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/12-90953e09/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/12-90953e09/0001.m4s new file mode 100644 index 0000000000..088478fe2e Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/12-90953e09/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/12-90953e09/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/12-90953e09/init.mp4 new file mode 100644 index 0000000000..d22f2bac9c Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/12-90953e09/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/15-585f233f/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/15-585f233f/0001.m4s new file mode 100644 index 0000000000..16cd2119c2 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/15-585f233f/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/15-585f233f/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/15-585f233f/init.mp4 new file mode 100644 index 0000000000..a90fe4d0b4 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/15-585f233f/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/16-4222bd78/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/16-4222bd78/0001.m4s new file mode 100644 index 0000000000..f242760d01 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/16-4222bd78/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/16-4222bd78/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/16-4222bd78/init.mp4 new file mode 100644 index 0000000000..29ec02c6e5 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/16-4222bd78/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/17/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/17/0001.m4s new file mode 100644 index 0000000000..5c32987f36 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/17/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/17/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/17/init.mp4 new file mode 100644 index 0000000000..5bb51e244d Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/17/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/19/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/19/0001.m4s new file mode 100644 index 0000000000..d9b943dd01 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/19/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/19/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/19/init.mp4 new file mode 100644 index 0000000000..891170383b Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/19/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/2-80399bf5/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/2-80399bf5/0001.m4s new file mode 100644 index 0000000000..8fd683dfd8 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/2-80399bf5/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/2-80399bf5/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/2-80399bf5/init.mp4 new file mode 100644 index 0000000000..4e37aaece1 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/2-80399bf5/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/27/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/27/0001.m4s new file mode 100644 index 0000000000..28cbdca019 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/27/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/27/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/27/init.mp4 new file mode 100644 index 0000000000..bb1553584e Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/27/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/3-80399bf5/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/3-80399bf5/0001.m4s new file mode 100644 index 0000000000..da80d3a5e4 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/3-80399bf5/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/3-80399bf5/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/3-80399bf5/init.mp4 new file mode 100644 index 0000000000..71329b03d4 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/3-80399bf5/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/4-90953e09/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/4-90953e09/0001.m4s new file mode 100644 index 0000000000..09fb716ba7 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/4-90953e09/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/4-90953e09/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/4-90953e09/init.mp4 new file mode 100644 index 0000000000..0bc50cd67f Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/4-90953e09/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/5-90953e09/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/5-90953e09/0001.m4s new file mode 100644 index 0000000000..812fbcf3f0 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/5-90953e09/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/5-90953e09/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/5-90953e09/init.mp4 new file mode 100644 index 0000000000..6eeea44b5c Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/5-90953e09/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/8-80399bf5/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/8-80399bf5/0001.m4s new file mode 100644 index 0000000000..cdf50795f3 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/8-80399bf5/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/8-80399bf5/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/8-80399bf5/init.mp4 new file mode 100644 index 0000000000..46fb1628ed Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/8-80399bf5/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/9-80399bf5/0001.m4s b/tests/contents/DASH_DRM_static_SegmentTemplate/media/9-80399bf5/0001.m4s new file mode 100644 index 0000000000..3f768ce9ec Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/9-80399bf5/0001.m4s differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/9-80399bf5/init.mp4 b/tests/contents/DASH_DRM_static_SegmentTemplate/media/9-80399bf5/init.mp4 new file mode 100644 index 0000000000..8d56b697b6 Binary files /dev/null and b/tests/contents/DASH_DRM_static_SegmentTemplate/media/9-80399bf5/init.mp4 differ diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/media/encrypted_multiple_keys_number.mpd b/tests/contents/DASH_DRM_static_SegmentTemplate/media/encrypted_multiple_keys_number.mpd new file mode 100644 index 0000000000..aa84cec211 --- /dev/null +++ b/tests/contents/DASH_DRM_static_SegmentTemplate/media/encrypted_multiple_keys_number.mpd @@ -0,0 +1,127 @@ + + + + + + + + + AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgA5AFoAcwA1AGcAQwBHAEsARgBFAEMAQQBVACsASgArAGQASQA2AFkAdwBRAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA== + + xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AOQBaAHMANQBnAEMARwBLAEYARQBDAEEAVQArAEoAKwBkAEkANgBZAHcAQQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQgDmb9YohQBSAU+J+dI6YwQ== + + + + + + + + + + + + AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBDAFQANgBWAGsATABKAHMAbwAwAG0AaQBZAEgAcABmADcAKwByAFUAbQBRAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA== + xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AQwBUADYAVgBrAEwASgBzAG8AMABtAGkAWQBIAHAAZgA3ACsAcgBVAG0AUQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQkJU+CWyySaOiYHpf7+rUmQ== + + + + + + + + + + + AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgA5AFoAcwA1AGcAQwBHAEsARgBFAEMAQQBVACsASgArAGQASQA2AFkAdwBBAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA== + xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AOQBaAHMANQBnAEMARwBLAEYARQBDAEEAVQArAEoAKwBkAEkANgBZAHcAQQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQgDmb9YohQBSAU+J+dI6YwA== + + + + + + + + + + + + AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBDAFQANgBWAGsATABKAHMAbwAwAG0AaQBZAEgAcABmADcAKwByAFUAbQBRAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA== + xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AQwBUADYAVgBrAEwASgBzAG8AMABtAGkAWQBIAHAAZgA3ACsAcgBVAG0AUQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQkJU+CWyySaOiYHpf7+rUmQ== + + + + + + + + + + AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBQAHkATgBmAFcASABJAHcAOABVAGEAZgBwAEcAMwBDAEwARwBhAGcARgBBAD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA== + xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AUAB5AE4AZgBXAEgASQB3ADgAVQBhAGYAcABHADMAQwBMAEcAYQBnAEYAQQA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQWF8jPzByRvGfpG3CLGagFA== + + + + + + + + + + + AAAB5HBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAcTEAQAAAQABALoBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBlAEwAMABpAFEAawBXADgAdgAwAEcAMgBQAG0AKwBCAFQAYwBPAFIAMwB3AD0APQA8AC8ASwBJAEQAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA== + xAEAAAEAAQC6ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AZQBMADAAaQBRAGsAVwA4AHYAMABHADIAUABtACsAQgBUAGMATwBSADMAdwA9AD0APAAvAEsASQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA= + + + AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQQiK9eLxFQb+2Pm+BTcOR3w== + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/contents/DASH_DRM_static_SegmentTemplate/urls.mjs b/tests/contents/DASH_DRM_static_SegmentTemplate/urls.mjs new file mode 100644 index 0000000000..42482fc073 --- /dev/null +++ b/tests/contents/DASH_DRM_static_SegmentTemplate/urls.mjs @@ -0,0 +1,138 @@ +/* eslint-env node */ + +import * as path from "path"; +import patchSegmentWithTimeOffset from "../utils/patchSegmentWithTimeOffset.mjs"; +import { fileURLToPath } from "url"; + +const currentDirectory = path.dirname(fileURLToPath(import.meta.url)); + +const baseURL = "/DASH_DRM_static_SegmentTemplate/media/"; + +const segments = []; + +// video +[ + "8-80399bf5", + "9-80399bf5", + "10-80399bf5", + "11-90953e09", + "12-90953e09", + "1-80399bf5", + "2-80399bf5", + "3-80399bf5", + "4-90953e09", + "5-90953e09", +].forEach((dir) => { + segments.push({ + url: baseURL + dir + "/init.mp4", + path: path.join(currentDirectory, `./media/${dir}/init.mp4`), + content: "video/mp4", + }); + const duration = [ + "1-80399bf5", + "2-80399bf5", + "3-80399bf5", + "4-90953e09", + "5-90953e09", + ].includes(dir) + ? 96 + : 4799983; + for (let i = 1; i <= 184; i++) { + const nb = String(i).padStart(4, "0"); + segments.push({ + url: baseURL + dir + `/${nb}.m4s`, + path: path.join(currentDirectory, `./media/${dir}/0001.m4s`), + postProcess: (buffer) => patchMp4(buffer, (i - 1) * duration), + content: "video/mp4", + }); + } +}); + +[ + // audio + "15-585f233f", + "16-4222bd78", + "17", +].forEach((dir) => { + segments.push({ + url: baseURL + dir + "/init.mp4", + path: path.join(currentDirectory, `./media/${dir}/init.mp4`), + content: "audio/mp4", + }); + const duration = 95232; + for (let i = 1; i <= 185; i++) { + const nb = String(i).padStart(4, "0"); + segments.push({ + url: baseURL + dir + `/${nb}.m4s`, + path: path.join(currentDirectory, `./media/${dir}/0001.m4s`), + postProcess: (buffer) => patchMp4(buffer, (i - 1) * duration), + content: "audio/mp4", + }); + } +}); + +[ + // subtitles + "19", + "27", +].forEach((dir) => { + segments.push({ + url: baseURL + dir + "/init.mp4", + path: path.join(currentDirectory, `./media/${dir}/init.mp4`), + content: "application/mp4", + }); + const duration = 4000; + for (let i = 1; i <= 184; i++) { + const nb = String(i).padStart(4, "0"); + segments.push({ + url: baseURL + dir + `/${nb}.m4s`, + path: path.join(currentDirectory, `./media/${dir}/0001.m4s`), + postProcess: (buffer) => patchMp4(buffer, (i - 1) * duration), + content: "application/mp4", + }); + } +}); + +export default [ + // Manifest + { + url: baseURL + "encrypted_multiple_keys_number.mpd", + path: path.join(currentDirectory, "./media/encrypted_multiple_keys_number.mpd"), + contentType: "application/dash+xml", + }, + ...segments, +]; + +/** + * Translate groups of 4 big-endian bytes to Integer. + * @param {Uint8Array} bytes + * @param {Number} offset - The offset (from the start of the given array) + * @returns {Number} + */ +function be4toi(bytes, offset) { + return ( + bytes[offset + 0] * 0x1000000 + + bytes[offset + 1] * 0x0010000 + + bytes[offset + 2] * 0x0000100 + + bytes[offset + 3] + ); +} + +function patchMp4(buffer, startTime) { + const bufferu8 = new Uint8Array(buffer); + let ret = bufferu8; + + // If it just finishes with "mdat", fill in the rest with 0 + if ( + bufferu8[bufferu8.length - 4] === 0x6d && + bufferu8[bufferu8.length - 3] === 0x64 && + bufferu8[bufferu8.length - 2] === 0x61 && + bufferu8[bufferu8.length - 1] === 0x74 + ) { + const mdatLen = be4toi(bufferu8, bufferu8.length - 8); + const remainingLength = mdatLen - 8; + ret = new Uint8Array(bufferu8.length + remainingLength); + ret.set(bufferu8, 0); + } + return patchSegmentWithTimeOffset(ret, startTime).buffer; +} diff --git a/tests/contents/urls.mjs b/tests/contents/urls.mjs index 1d6a684ec8..ffcfd06f90 100644 --- a/tests/contents/urls.mjs +++ b/tests/contents/urls.mjs @@ -13,6 +13,7 @@ import urls8 from "./directfile_webm/urls.mjs"; import urls9 from "./DASH_dynamic_SegmentTemplate_Multi_Periods/urls.mjs"; import urls10 from "./DASH_static_broken_cenc_in_MPD/urls.mjs"; import urls11 from "./DASH_static_number_based_SegmentTimeline/urls.mjs"; +import urls12 from "./DASH_DRM_static_SegmentTemplate/urls.mjs"; export default [ ...urls1, @@ -26,4 +27,5 @@ export default [ ...urls9, ...urls10, ...urls11, + ...urls12, ]; diff --git a/tests/integration/scenarios/drm_base.js b/tests/integration/scenarios/drm_base.js new file mode 100644 index 0000000000..eb39c424a8 --- /dev/null +++ b/tests/integration/scenarios/drm_base.js @@ -0,0 +1,655 @@ +import { describe, beforeEach, afterEach, it, expect } from "vitest"; +import { manifestInfos } from "../../contents/DASH_DRM_static_SegmentTemplate"; +import DummyMediaElement from "../../../dist/es2017/experimental/tools/DummyMediaElement"; +import RxPlayer from "../../../dist/es2017"; +import waitForPlayerState, { + waitForLoadedStateAfterLoadVideo, +} from "../../utils/waitForPlayerState"; +import { lockLowestBitrates } from "../../utils/bitrates"; +import sleep from "../../utils/sleep"; + +const textDecoder = new TextDecoder(); +const textEncoder = new TextEncoder(); + +describe("DRM: Basic use cases", function () { + const { url, transport } = manifestInfos; + let player; + const oldMediaSourceSupported = MediaSource.isTypeSupported; + + let dummy; + beforeEach(() => { + MediaSource.isTypeSupported = () => true; + dummy = new DummyMediaElement(); + player = new RxPlayer({ videoElement: dummy }); + player.setWantedBufferAhead(10); + }); + + afterEach(async () => { + MediaSource.isTypeSupported = oldMediaSourceSupported; + player.dispose(); + }); + + it("should trigger error if no key system option is provided", async function () { + lockLowestBitrates(player); + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("MEDIA_IS_ENCRYPTED_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + }); + + it("should load the content if licenses are returned", async function () { + lockLowestBitrates(player); + const expectedKeyIds = [ + "80399bf58a2140148053e27e748e98c1", + "585f233f307246f19fa46dc22c66a014", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + }), + }, + ], + }); + await waitForLoadedStateAfterLoadVideo(player); + expect(player.getVideoRepresentation().id).toEqual("8-80399bf5"); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + expect(askedKeyIds.length).toEqual(expectedKeyIds.length); + + player.stop(); + await sleep(10); + expect(dummy.mediaKeys.sessions).toHaveLength(2); + }); + + it("should close sessions after stop if `closeSessionsOnStop` is set", async function () { + lockLowestBitrates(player); + const expectedKeyIds = [ + "80399bf58a2140148053e27e748e98c1", + "585f233f307246f19fa46dc22c66a014", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + }), + closeSessionsOnStop: true, + }, + ], + }); + await waitForLoadedStateAfterLoadVideo(player); + expect(player.getVideoRepresentation().id).toEqual("8-80399bf5"); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + expect(askedKeyIds.length).toEqual(expectedKeyIds.length); + expect(dummy.mediaKeys.sessions).toHaveLength(2); + + player.stop(); + await sleep(10); + expect(dummy.mediaKeys.sessions).toHaveLength(0); + }); + + it("should trigger specific error if the license request fails", async function () { + lockLowestBitrates(player); + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicense() { + throw new Error("I do not work"); + }, + }, + ], + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("KEY_LOAD_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + }); + + it("should fallback from license request error with a `fallbackOnLastTry` toggle on", async function () { + const failingKeyIds = ["90953e096cb249a3a2607a5fefead499"]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + failingKeyIds, + }), + }, + ], + }); + let brokenVideoLock = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + await waitForLoadedStateAfterLoadVideo(player); + expect(brokenVideoLock).toEqual(1); + expect(["8-80399bf5", "9-80399bf5", "10-80399bf5"]).toContain( + player.getVideoRepresentation().id, + ); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + }); + + it('should fallback from an `"output-restricted"` MediaKeyStatus under the corresponding option', async function () { + const highPolicyLevelKeyIds = ["90953e096cb249a3a2607a5fefead499"]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + onKeyOutputRestricted: "fallback", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + highPolicyLevelKeyIds, + }), + }, + ], + }); + let brokenVideoLock = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + await waitForLoadedStateAfterLoadVideo(player); + expect(brokenVideoLock).toEqual(1); + expect(["8-80399bf5", "9-80399bf5", "10-80399bf5"]).toContain( + player.getVideoRepresentation().id, + ); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + }); + + it('should continue from an `"output-restricted"` MediaKeyStatus under the corresponding option', async function () { + const highPolicyLevelKeyIds = ["90953e096cb249a3a2607a5fefead499"]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + onKeyOutputRestricted: "continue", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + highPolicyLevelKeyIds, + }), + }, + ], + }); + + let brokenVideoLock = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + + await sleep(150); + expect(player.getPlayerState()).toEqual("LOADING"); + expect(brokenVideoLock).toEqual(0); + expect(["11-90953e09", "12-90953e09"]).toContain(player.getVideoRepresentation().id); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + }); + + it('should fail from an `"output-restricted"` MediaKeyStatus under the corresponding option', async function () { + player.setWantedBufferAhead(10); + const highPolicyLevelKeyIds = ["90953e096cb249a3a2607a5fefead499"]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + onKeyOutputRestricted: "error", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + highPolicyLevelKeyIds, + }), + }, + ], + }); + let brokenVideoLock = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("KEY_STATUS_CHANGE_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + expect(brokenVideoLock).toEqual(0); + }); + + it('should fallback from an `"output-restricted"` MediaKeyStatus happening during playback under the corresponding option', async function () { + const mediumPolicyLevelKeyIds = ["90953e096cb249a3a2607a5fefead499"]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + onKeyOutputRestricted: "fallback", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + mediumPolicyLevelKeyIds, + }), + }, + ], + }); + let brokenVideoLock = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + + await waitForLoadedStateAfterLoadVideo(player); + expect(brokenVideoLock).toEqual(0); + expect(["11-90953e09", "12-90953e09"]).toContain(player.getVideoRepresentation().id); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + + await sleep(50); + dummy.mediaKeys.sessions.forEach((s) => { + s.updatePolicyLevel(10); + }); + await waitForPlayerState(player, "PAUSED", ["PLAYING", "RELOADING"]); + expect(brokenVideoLock).toEqual(1); + expect(["8-80399bf5", "9-80399bf5", "10-80399bf5"]).toContain( + player.getVideoRepresentation().id, + ); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + }); + + it('should fail from an `"output-restricted"` MediaKeyStatus happening during playback under the corresponding option', async function () { + player.setWantedBufferAhead(10); + const mediumPolicyLevelKeyIds = ["90953e096cb249a3a2607a5fefead499"]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + onKeyOutputRestricted: "error", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + mediumPolicyLevelKeyIds, + }), + }, + ], + }); + let brokenVideoLock = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + + await waitForLoadedStateAfterLoadVideo(player); + expect(brokenVideoLock).toEqual(0); + expect(["11-90953e09", "12-90953e09"]).toContain(player.getVideoRepresentation().id); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + + await sleep(50); + dummy.mediaKeys.sessions.forEach((s) => { + s.updatePolicyLevel(10); + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("KEY_STATUS_CHANGE_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + expect(brokenVideoLock).toEqual(0); + }); + + it("should re-allow a Representation re-becoming decipherable", async function () { + const mediumPolicyLevelKeyIds = ["90953e096cb249a3a2607a5fefead499"]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + onKeyOutputRestricted: "fallback", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + mediumPolicyLevelKeyIds, + }), + }, + ], + }); + let brokenVideoLock = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + + await waitForLoadedStateAfterLoadVideo(player); + expect(brokenVideoLock).toEqual(0); + expect(["11-90953e09", "12-90953e09"]).toContain(player.getVideoRepresentation().id); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + + await sleep(50); + dummy.mediaKeys.sessions.forEach((s) => { + s.updatePolicyLevel(10); + }); + await waitForPlayerState(player, "PAUSED", ["PLAYING", "RELOADING"]); + expect(brokenVideoLock).toEqual(1); + expect(["8-80399bf5", "9-80399bf5", "10-80399bf5"]).toContain( + player.getVideoRepresentation().id, + ); + expect(player.getVideoTrack().representations.map((r) => r.id)).not.toContain( + "12-90953e09", + ); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + + dummy.mediaKeys.sessions.forEach((s) => { + s.updatePolicyLevel(100); + }); + await sleep(10); + expect(player.getVideoTrack().representations.map((r) => r.id)).toContain( + "12-90953e09", + ); + player.lockVideoRepresentations(["12-90953e09"]); + expect(player.getVideoRepresentation().id).toEqual("12-90953e09"); + }); + + it('should change track if all Representation from the current one are `"output-restricted"` with the corresponding option', async function () { + const mediumPolicyLevelKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "80399bf58a2140148053e27e748e98c1", + ]; + const expectedKeyIds = [ + "90953e096cb249a3a2607a5fefead499", + "585f233f307246f19fa46dc22c66a014", + "80399bf58a2140148053e27e748e98c1", + "80399bf58a2140148053e27e748e98c0", + ]; + const askedKeyIds = []; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + onKeyOutputRestricted: "fallback", + getLicense: generateGetLicense({ + expectedKeyIds, + askedKeyIds, + mediumPolicyLevelKeyIds, + }), + }, + ], + }); + let brokenVideoLock = 0; + let videoTrackUpdate = 0; + player.addEventListener("newAvailablePeriods", (p) => { + player.lockVideoRepresentations({ + periodId: p[0].id, + representations: ["11-90953e09", "12-90953e09"], + }); + }); + player.addEventListener("trackUpdate", (obj) => { + if (obj.trackType === "video") { + if (obj.reason === "no-playable-representation") { + videoTrackUpdate++; + } + } + }); + player.addEventListener("brokenRepresentationsLock", (lock) => { + if (lock.trackType === "video") { + brokenVideoLock++; + } + }); + + await waitForLoadedStateAfterLoadVideo(player); + expect(brokenVideoLock).toEqual(0); + expect(["11-90953e09", "12-90953e09"]).toContain(player.getVideoRepresentation().id); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + + await sleep(50); + dummy.mediaKeys.sessions.forEach((s) => { + s.updatePolicyLevel(10); + }); + await waitForPlayerState(player, "PAUSED", ["PLAYING", "RELOADING"]); + + await sleep(50); + expect(brokenVideoLock).toEqual(1); + expect(videoTrackUpdate).toEqual(0); + dummy.mediaKeys.sessions.forEach((s) => { + s.updatePolicyLevel(10); + }); + await waitForPlayerState(player, "PAUSED", ["PLAYING", "RELOADING"]); + + expect(brokenVideoLock).toEqual(1); + expect(videoTrackUpdate).toEqual(1); + expect(["1-80399bf5", "2-80399bf5", "3-80399bf5"]).toContain( + player.getVideoRepresentation().id, + ); + expect(player.getAudioRepresentation().id).toEqual("15-585f233f"); + expect(player.getError()).toBeNull(); + }); + + function generateGetLicense({ + expectedKeyIds, + askedKeyIds, + highPolicyLevelKeyIds, + mediumPolicyLevelKeyIds, + failingKeyIds, + }) { + return function getLicense(challenge, messageType) { + return new Promise((resolve, reject) => { + setTimeout(() => { + try { + expect(messageType).toEqual("license-request"); + const challengeStr = textDecoder.decode(challenge); + const challengeObj = JSON.parse(challengeStr); + const keys = {}; + challengeObj.keyIds.forEach((kid) => { + if (Array.isArray(expectedKeyIds)) { + expect(expectedKeyIds).toContain(kid); + } + if (Array.isArray(askedKeyIds)) { + askedKeyIds.push(kid); + } + if (Array.isArray(failingKeyIds) && failingKeyIds.includes(kid)) { + const error = new Error("Should fallback!"); + error.noRetry = true; + error.fallbackOnLastTry = true; + reject(error); + } + let policyLevel = 0; + if ( + Array.isArray(highPolicyLevelKeyIds) && + highPolicyLevelKeyIds.includes(kid) + ) { + policyLevel = 200; + } else if ( + Array.isArray(mediumPolicyLevelKeyIds) && + mediumPolicyLevelKeyIds.includes(kid) + ) { + policyLevel = 50; + } + keys[kid] = { + policyLevel, + }; + }); + const license = { + type: "license", + persistent: false, + keys, + }; + const licenseU8 = textEncoder.encode(JSON.stringify(license)); + resolve(licenseU8.buffer); + } catch (e) { + reject(e); + } + }, 50); + }); + }; + } +}); diff --git a/tests/integration/scenarios/drm_getLicenceConfig.js b/tests/integration/scenarios/drm_getLicenceConfig.js new file mode 100644 index 0000000000..55443cadfc --- /dev/null +++ b/tests/integration/scenarios/drm_getLicenceConfig.js @@ -0,0 +1,224 @@ +import { describe, beforeEach, afterEach, it, expect } from "vitest"; +import { manifestInfos } from "../../contents/DASH_DRM_static_SegmentTemplate"; +import DummyMediaElement from "../../../dist/es2017/experimental/tools/DummyMediaElement"; +import RxPlayer from "../../../dist/es2017"; +import waitForPlayerState from "../../utils/waitForPlayerState"; +import { lockLowestBitrates } from "../../utils/bitrates"; + +const textDecoder = new TextDecoder(); + +describe("DRM: getLicenseConfig", () => { + const { url, transport } = manifestInfos; + let player; + const oldMediaSourceSupported = MediaSource.isTypeSupported; + + let dummy; + beforeEach(() => { + MediaSource.isTypeSupported = () => true; + dummy = new DummyMediaElement(); + player = new RxPlayer({ videoElement: dummy }); + player.setWantedBufferAhead(10); + }); + + afterEach(async () => { + MediaSource.isTypeSupported = oldMediaSourceSupported; + player.dispose(); + }); + + it("should attempt the license request 3 times by default", async function () { + lockLowestBitrates(player); + const expectedKeyIds = [ + "80399bf58a2140148053e27e748e98c1", + "585f233f307246f19fa46dc22c66a014", + ]; + const askedKeyIds = {}; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicense(challenge) { + const challengeStr = textDecoder.decode(challenge); + const challengeObj = JSON.parse(challengeStr); + challengeObj.keyIds.forEach((kid) => { + expect(expectedKeyIds).toContain(kid); + if (askedKeyIds[kid] === undefined) { + askedKeyIds[kid] = 1; + } else { + askedKeyIds[kid]++; + } + throw new Error("A"); + }); + }, + }, + ], + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + expect(askedKeyIds).toHaveProperty(expectedKeyIds[0]); + expect(askedKeyIds).toHaveProperty(expectedKeyIds[1]); + if (askedKeyIds[expectedKeyIds[0]] === 3) { + expect(askedKeyIds[expectedKeyIds[1]]).toEqual(2); + } else if (askedKeyIds[expectedKeyIds[1]] === 3) { + expect(askedKeyIds[expectedKeyIds[0]]).toEqual(2); + } else { + throw new Error("No key has 3 request attempts: " + JSON.stringify(askedKeyIds)); + } + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("KEY_LOAD_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + }); + + it("should update the number of attempts with getLicenseConfig", async function () { + lockLowestBitrates(player); + const expectedKeyIds = [ + "80399bf58a2140148053e27e748e98c1", + "585f233f307246f19fa46dc22c66a014", + ]; + const askedKeyIds = {}; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicenseConfig: { + retry: 1, + }, + getLicense(challenge) { + const challengeStr = textDecoder.decode(challenge); + const challengeObj = JSON.parse(challengeStr); + challengeObj.keyIds.forEach((kid) => { + expect(expectedKeyIds).toContain(kid); + if (askedKeyIds[kid] === undefined) { + askedKeyIds[kid] = 1; + } else { + askedKeyIds[kid]++; + } + throw new Error("A"); + }); + }, + }, + ], + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + expect(askedKeyIds).toHaveProperty(expectedKeyIds[0]); + expect(askedKeyIds).toHaveProperty(expectedKeyIds[1]); + if (askedKeyIds[expectedKeyIds[0]] === 2) { + expect(askedKeyIds[expectedKeyIds[1]]).toEqual(1); + } else if (askedKeyIds[expectedKeyIds[1]] === 2) { + expect(askedKeyIds[expectedKeyIds[0]]).toEqual(1); + } else { + throw new Error("No key has 3 request attempts: " + JSON.stringify(askedKeyIds)); + } + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("KEY_LOAD_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + }); + + it("should not retry if `noRetry` is set on the error", async function () { + lockLowestBitrates(player); + const expectedKeyIds = [ + "80399bf58a2140148053e27e748e98c1", + "585f233f307246f19fa46dc22c66a014", + ]; + const askedKeyIds = {}; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicenseConfig: { + retry: 1, + }, + getLicense(challenge) { + const challengeStr = textDecoder.decode(challenge); + const challengeObj = JSON.parse(challengeStr); + challengeObj.keyIds.forEach((kid) => { + expect(expectedKeyIds).toContain(kid); + if (askedKeyIds[kid] === undefined) { + askedKeyIds[kid] = 1; + } else { + askedKeyIds[kid]++; + } + const error = new Error("A"); + error.noRetry = true; + throw error; + }); + }, + }, + ], + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + expect(Object.keys(askedKeyIds)).toHaveLength(1); + expect(askedKeyIds[Object.keys(askedKeyIds)[0]]).toEqual(1); + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("KEY_LOAD_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + }); + + it("should update a timeout with getLicenseConfig", async function () { + lockLowestBitrates(player); + const expectedKeyIds = [ + "80399bf58a2140148053e27e748e98c1", + "585f233f307246f19fa46dc22c66a014", + ]; + const askedKeyIds = {}; + player.loadVideo({ + url, + transport, + autoPlay: false, + textTrackMode: "html", + textTrackElement: document.createElement("div"), + keySystems: [ + { + type: "com.microsoft.playready", + getLicenseConfig: { + retry: 0, + timeout: 1, + }, + getLicense(challenge) { + return new Promise((resolve) => { + setTimeout(() => { + const challengeStr = textDecoder.decode(challenge); + const challengeObj = JSON.parse(challengeStr); + challengeObj.keyIds.forEach((kid) => { + expect(expectedKeyIds).toContain(kid); + if (askedKeyIds[kid] === undefined) { + askedKeyIds[kid] = 1; + } else { + askedKeyIds[kid]++; + } + }); + resolve({}); + }, 10); + }); + }, + }, + ], + }); + await waitForPlayerState(player, "STOPPED", ["LOADING"]); + expect(askedKeyIds).toEqual({}); + const error = player.getError(); + expect(error).not.toBeNull(); + expect(error.code).to.equal("KEY_LOAD_ERROR"); + expect(error.name).to.equal("EncryptedMediaError"); + expect(error.type).to.equal("ENCRYPTED_MEDIA_ERROR"); + }); +});