@ -1276,4 +1276,270 @@ test('calling play() at the end of a video resets the media index', function() {
strictEqual ( player . hls . mediaIndex , 0 , 'index is 1 after the first segment' ) ;
} ) ;
test ( 'calling fetchKeys() when a new playlist is loaded will create an XHR' , function ( ) {
player . src ( {
src : 'https://example.com/encrypted-media.m3u8' ,
type : 'application/vnd.apple.mpegurl'
} ) ;
openMediaSource ( player ) ;
var oldMedia = player . hls . playlists . media ;
player . hls . playlists . media = function ( ) {
return {
segments : [ {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=52'
} ,
uri : 'http://media.example.com/fileSequence52-A.ts'
} , {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=53'
} ,
uri : 'http://media.example.com/fileSequence53-B.ts'
} ]
} ;
} ;
player . hls . playlists . trigger ( 'loadedplaylist' ) ;
strictEqual ( requests . length , 2 , 'a key XHR is created' ) ;
strictEqual ( requests [ 1 ] . url , player . hls . playlists . media ( ) . segments [ 0 ] . key . uri , 'a key XHR is created with correct uri' ) ;
player . hls . playlists . media = oldMedia ;
} ) ;
test ( 'a new keys XHR is created when a previous key XHR finishes' , function ( ) {
player . src ( {
src : 'https://example.com/encrypted-media.m3u8' ,
type : 'application/vnd.apple.mpegurl'
} ) ;
openMediaSource ( player ) ;
var oldMedia = player . hls . playlists . media ;
player . hls . playlists . media = function ( ) {
return {
segments : [ {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=52'
} ,
uri : 'http://media.example.com/fileSequence52-A.ts'
} , {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=53'
} ,
uri : 'http://media.example.com/fileSequence53-B.ts'
} ]
} ;
} ;
player . hls . playlists . trigger ( 'loadedplaylist' ) ;
requests . pop ( ) . respond ( 200 , new Uint8Array ( [ 1 ] ) . buffer ) ;
strictEqual ( requests . length , 2 , 'a key XHR is created' ) ;
strictEqual ( requests [ 1 ] . url , player . hls . playlists . media ( ) . segments [ 1 ] . key . uri , 'a key XHR is created with the correct uri' ) ;
player . hls . playlists . media = oldMedia ;
} ) ;
test ( 'calling fetchKeys() when a seek happens will create an XHR' , function ( ) {
player . src ( {
src : 'https://example.com/encrypted-media.m3u8' ,
type : 'application/vnd.apple.mpegurl'
} ) ;
openMediaSource ( player ) ;
var oldMedia = player . hls . playlists . media ;
player . hls . playlists . media = function ( ) {
return {
segments : [ {
duration : 10 ,
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=52'
} ,
uri : 'http://media.example.com/fileSequence52-A.ts'
} , {
duration : 10 ,
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=53'
} ,
uri : 'http://media.example.com/fileSequence53-B.ts'
} ]
} ;
} ;
player . hls . fetchKeys ( player . hls . playlists . media ( ) , 0 ) ;
player . currentTime ( 11 ) ;
ok ( requests [ 1 ] . aborted , 'the key XHR should be aborted' ) ;
equal ( requests . length , 3 , 'we should get a new key XHR' ) ;
equal ( requests [ 2 ] . url , player . hls . playlists . media ( ) . segments [ 1 ] . key . uri , 'urls should match' ) ;
player . hls . playlists . media = oldMedia ;
} ) ;
test ( 'calling fetchKeys() when a key XHR is in progress will *not* create an XHR' , function ( ) {
player . src ( {
src : 'https://example.com/encrypted-media.m3u8' ,
type : 'application/vnd.apple.mpegurl'
} ) ;
openMediaSource ( player ) ;
var oldMedia = player . hls . playlists . media ;
player . hls . playlists . media = function ( ) {
return {
segments : [ {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=52'
} ,
uri : 'http://media.example.com/fileSequence52-A.ts'
} , {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=53'
} ,
uri : 'http://media.example.com/fileSequence53-B.ts'
} ]
} ;
} ;
strictEqual ( requests . length , 1 , 'no key XHR created for the player' ) ;
player . hls . playlists . trigger ( 'loadedplaylist' ) ;
player . hls . fetchKeys ( player . hls . playlists . media ( ) , 0 ) ;
strictEqual ( requests . length , 2 , 'only the original XHR is available' ) ;
player . hls . playlists . media = oldMedia ;
} ) ;
test ( 'calling fetchKeys() when all keys are fetched, will *not* create an XHR' , function ( ) {
player . src ( {
src : 'https://example.com/encrypted-media.m3u8' ,
type : 'application/vnd.apple.mpegurl'
} ) ;
openMediaSource ( player ) ;
var oldMedia = player . hls . playlists . media ;
player . hls . playlists . media = function ( ) {
return {
segments : [ {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=52' ,
bytes : new Uint8Array ( [ 1 ] )
} ,
uri : 'http://media.example.com/fileSequence52-A.ts'
} , {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=53' ,
bytes : new Uint8Array ( [ 1 ] )
} ,
uri : 'http://media.example.com/fileSequence53-B.ts'
} ]
} ;
} ;
player . hls . fetchKeys ( player . hls . playlists . media ( ) , 0 ) ;
strictEqual ( requests . length , 1 , 'no XHR for keys created since they were all downloaded' ) ;
player . hls . playlists . media = oldMedia ;
} ) ;
test ( 'retries key requests once upon failure' , function ( ) {
player . src ( {
src : 'https://example.com/encrypted-media.m3u8' ,
type : 'application/vnd.apple.mpegurl'
} ) ;
openMediaSource ( player ) ;
var oldMedia = player . hls . playlists . media ;
player . hls . playlists . media = function ( ) {
return {
segments : [ {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=52'
} ,
uri : 'http://media.example.com/fileSequence52-A.ts'
} , {
key : {
'method' : 'AES-128' ,
'uri' : 'https://priv.example.com/key.php?r=53'
} ,
uri : 'http://media.example.com/fileSequence53-B.ts'
} ]
} ;
} ;
player . hls . fetchKeys ( player . hls . playlists . media ( ) , 0 ) ;
requests [ 1 ] . respond ( 404 ) ;
equal ( requests . length , 3 , 'create a new XHR for the same key' ) ;
equal ( requests [ 2 ] . url , requests [ 1 ] . url , 'should be the same key' ) ;
requests [ 2 ] . respond ( 404 ) ;
equal ( requests . length , 4 , 'create a new XHR for the same key' ) ;
notEqual ( requests [ 3 ] . url , requests [ 2 ] . url , 'should be the same key' ) ;
equal ( requests [ 3 ] . url , player . hls . playlists . media ( ) . segments [ 1 ] . key . uri ) ;
player . hls . playlists . media = oldMedia ;
} ) ;
test ( 'skip segments if key requests fail more than once' , function ( ) {
var bytes = [ ] ,
tags = [ { pats : 0 , bytes : 0 } ] ;
videojs . Hls . SegmentParser = mockSegmentParser ( tags ) ;
window . videojs . SourceBuffer = function ( ) {
this . appendBuffer = function ( chunk ) {
bytes . push ( chunk ) ;
} ;
this . abort = function ( ) { } ;
} ;
player . src ( {
src : 'https://example.com/encrypted-media.m3u8' ,
type : 'application/vnd.apple.mpegurl'
} ) ;
openMediaSource ( player ) ;
requests . pop ( ) . respond ( 200 , null ,
'#EXTM3U\n' +
'#EXT-X-KEY:METHOD=AES-128,URI="htts://priv.example.com/key.php?r=52"\n' +
'#EXTINF:2.833,\n' +
'http://media.example.com/fileSequence52-A.ts\n' +
'#EXT-X-KEY:METHOD=AES-128,URI="htts://priv.example.com/key.php?r=53"\n' +
'#EXTINF:15.0,\n' +
'http://media.example.com/fileSequence53-A.ts\n' ) ;
player . hls . playlists . trigger ( 'loadedplaylist' ) ;
player . trigger ( 'timeupdate' ) ;
// respond to ts segment
standardXHRResponse ( requests . pop ( ) ) ;
// fail key
requests . pop ( ) . respond ( 404 ) ;
// fail key, again
requests . pop ( ) . respond ( 404 ) ;
// key for second segment
standardXHRResponse ( requests . pop ( ) ) ;
equal ( bytes . length , 1 , 'bytes from the ts segments should not be added' ) ;
player . trigger ( 'timeupdate' ) ;
tags . push ( { pts : 0 , bytes : 1 } ) ;
// second segment
standardXHRResponse ( requests . pop ( ) ) ;
equal ( bytes . length , 2 , 'bytes from the second ts segment should be added' ) ;
equal ( bytes [ 1 ] , 1 , 'the bytes from the second segment are added and not the first' ) ;
} ) ;
} ) ( window , window . videojs ) ;