@@ -59,6 +59,7 @@ export interface MediaKeySessionContext {
5959 mediaKeys : MediaKeys ;
6060 mediaKeysSession : MediaKeySession ;
6161 keyStatuses : { [ keyId : string ] : MediaKeyStatus } ;
62+ keyStatusTimeouts ?: { [ keyId : string ] : number } ;
6263 licenseXhr ?: XMLHttpRequest ;
6364 _onmessage ?: ( this : MediaKeySession , ev : MediaKeyMessageEvent ) => any ;
6465 _onkeystatuseschange ?: ( this : MediaKeySession , ev : Event ) => any ;
@@ -71,6 +72,7 @@ export type MediaKeySessionContextAndLevelKey = {
7172 mediaKeys : MediaKeys ;
7273 mediaKeysSession : MediaKeySession ;
7374 keyStatuses : { [ keyId : string ] : MediaKeyStatus } ;
75+ keyStatusTimeouts ?: { [ keyId : string ] : number } ;
7476 licenseXhr ?: XMLHttpRequest ;
7577} ;
7678
@@ -873,54 +875,8 @@ class EMEController extends Logger implements ComponentAPI {
873875 }
874876 } ) ;
875877
876- const onkeystatuseschange = ( context . _onkeystatuseschange = (
877- event : Event ,
878- ) => {
879- const keySession = context . mediaKeysSession ;
880- if ( ! keySession as any ) {
881- licenseStatus . emit ( 'error' , new Error ( 'invalid state' ) ) ;
882- return ;
883- }
884-
885- // populate/update context.keyStatuses
886- this . onKeyStatusChange ( context ) ;
887-
888- // renew when a key status comes back expired
889- const keyIds = Object . keys ( context . keyStatuses ) ;
890- if ( keyIds . some ( ( id ) => context . keyStatuses [ id ] === 'expired' ) ) {
891- this . log (
892- `${ context . keySystem } expired for key ${ stringify ( context . keyStatuses ) } ` ,
893- ) ;
894- this . renewKeySession ( context , levelKey ) ;
895- }
896-
897- // handle status of current key
898- let keyStatus = context . keyStatuses [ keyId ] as MediaKeyStatus | undefined ;
878+ const handleKeyStatus = ( keyStatus : MediaKeyStatus ) => {
899879 let keyError : EMEKeyError | Error | undefined ;
900- if ( ! keyStatus ) {
901- // Handle case where no keyIds matched but all have the same status
902- const keyIds = Object . keys ( context . keyStatuses ) ;
903- if ( keyIds . length ) {
904- const keyStatuses = keyIds . map ( ( id ) => context . keyStatuses [ id ] ) ;
905- const firstStatus = keyStatuses [ 0 ] ;
906- const allSameStatus = ! keyStatuses . some (
907- ( status ) => status . substring ( 0 , 6 ) !== firstStatus . substring ( 0 , 6 ) ,
908- ) ;
909- if ( allSameStatus ) {
910- keyStatus = firstStatus ;
911- } else if ( keyStatuses . some ( ( status ) => status === 'expired' ) ) {
912- keyStatus = 'expired' ;
913- } else if ( keyStatuses . some ( ( status ) => status === 'released' ) ) {
914- keyStatus = 'released' ;
915- }
916- }
917- if ( ! keyStatus ) {
918- keyStatus = 'internal-error' ;
919- }
920- this . log (
921- `No status for keyId ${ keyId } . Using session key-status ${ keyStatus } (${ stringify ( context . keyStatuses ) } ).` ,
922- ) ;
923- }
924880 if ( keyStatus . startsWith ( 'usable' ) ) {
925881 licenseStatus . emit ( 'resolved' ) ;
926882 } else if (
@@ -949,6 +905,59 @@ class EMEController extends Logger implements ComponentAPI {
949905 this . handleError ( keyError ) ;
950906 }
951907 }
908+ } ;
909+ const onkeystatuseschange = ( context . _onkeystatuseschange = (
910+ event : Event ,
911+ ) => {
912+ const keySession = context . mediaKeysSession ;
913+ if ( ! keySession as any ) {
914+ licenseStatus . emit ( 'error' , new Error ( 'invalid state' ) ) ;
915+ return ;
916+ }
917+
918+ // populate/update context.keyStatuses
919+ this . onKeyStatusChange ( context ) ;
920+
921+ // renew when a key status comes back expired
922+ const keyIds = Object . keys ( context . keyStatuses ) ;
923+ if ( keyIds . some ( ( id ) => context . keyStatuses [ id ] === 'expired' ) ) {
924+ this . log (
925+ `${ context . keySystem } expired for key ${ stringify ( context . keyStatuses ) } ` ,
926+ ) ;
927+ this . renewKeySession ( context , levelKey ) ;
928+ }
929+
930+ // handle status of current key
931+ let keyStatus = context . keyStatuses [ keyId ] as MediaKeyStatus | undefined ;
932+
933+ if ( ! keyStatus ) {
934+ keyStatus = 'status-pending' ;
935+ const keyIds = Object . keys ( context . keyStatuses ) ;
936+ if ( keyIds . length ) {
937+ const timeout = ( this . hls as any ) ?. config . keyLoadPolicy . default
938+ . maxTimeToFirstByteMs ;
939+ context . keyStatusTimeouts ||= { } ;
940+ context . keyStatusTimeouts [ keyId ] ||= self . setTimeout ( ( ) => {
941+ if ( ! context . levelKeys . length || ! this . mediaKeys ) {
942+ return ;
943+ }
944+
945+ if ( keyId in context . keyStatuses ) {
946+ keyStatus = context . keyStatuses [ keyId ] ;
947+ } else {
948+ this . log (
949+ `key status for ${ keyId } in session ${ context . mediaKeysSession . sessionId } timed out after 5s.` ,
950+ ) ;
951+ keyStatus = 'internal-error' ;
952+ }
953+ handleKeyStatus ( keyStatus ) ;
954+ } , timeout ) ;
955+ this . log (
956+ `No status for keyId ${ keyId } . Using session key-status ${ keyStatus } (${ stringify ( context . keyStatuses ) } ).` ,
957+ ) ;
958+ }
959+ }
960+ handleKeyStatus ( keyStatus ) ;
952961 } ) ;
953962
954963 addEventListener ( context . mediaKeysSession , 'message' , onmessage ) ;
@@ -1526,6 +1535,12 @@ class EMEController extends Logger implements ComponentAPI {
15261535 if ( index > - 1 ) {
15271536 this . mediaKeySessions . splice ( index , 1 ) ;
15281537 }
1538+ const { keyStatusTimeouts } = mediaKeySessionContext ;
1539+ if ( keyStatusTimeouts ) {
1540+ Object . keys ( keyStatusTimeouts ) . forEach ( ( keyId ) =>
1541+ self . clearTimeout ( keyStatusTimeouts [ keyId ] ) ,
1542+ ) ;
1543+ }
15291544 const { drmSystemOptions } = this . config ;
15301545 const removePromise = isPersistentSessionType ( drmSystemOptions )
15311546 ? new Promise ( ( resolve , reject ) => {
0 commit comments