@@ -535,147 +535,185 @@ class EMEController extends Logger implements ComponentAPI {
535
535
return ;
536
536
}
537
537
538
- let keyId : Uint8Array | null | undefined ;
539
- let keySystemDomain : KeySystems | undefined ;
540
-
541
- if (
542
- initDataType === 'sinf' &&
543
- this . getLicenseServerUrl ( KeySystems . FAIRPLAY )
544
- ) {
545
- // Match sinf keyId to playlist skd://keyId=
546
- const json = bin2str ( new Uint8Array ( initData ) ) ;
547
- try {
548
- const sinf = base64Decode ( JSON . parse ( json ) . sinf ) ;
549
- const tenc = parseSinf ( sinf ) ;
550
- if ( ! tenc ) {
551
- throw new Error (
552
- `'schm' box missing or not cbcs/cenc with schi > tenc` ,
553
- ) ;
554
- }
555
- keyId = tenc . subarray ( 8 , 24 ) ;
556
- keySystemDomain = KeySystems . FAIRPLAY ;
557
- } catch ( error ) {
558
- this . warn ( `${ logMessage } Failed to parse sinf: ${ error } ` ) ;
559
- return ;
560
- }
561
- } else if ( this . getLicenseServerUrl ( KeySystems . WIDEVINE ) ) {
562
- // Support Widevine clear-lead key-session creation (otherwise depend on playlist keys)
563
- const psshResults = parseMultiPssh ( initData ) ;
564
-
565
- // TODO: If using keySystemAccessPromises we might want to wait until one is resolved
538
+ if ( ! this . keyFormatPromise ) {
566
539
let keySystems = Object . keys (
567
540
this . keySystemAccessPromises ,
568
541
) as KeySystems [ ] ;
569
542
if ( ! keySystems . length ) {
570
543
keySystems = getKeySystemsForConfig ( this . config ) ;
571
544
}
545
+ const keyFormats = keySystems
546
+ . map ( keySystemToKeySystemFormat )
547
+ . filter ( ( k ) => ! ! k ) as KeySystemFormats [ ] ;
548
+ this . keyFormatPromise = this . getKeyFormatPromise ( keyFormats ) ;
549
+ }
572
550
573
- const psshInfo = psshResults . filter ( ( pssh ) : pssh is PsshData => {
574
- const keySystem = pssh . systemId
575
- ? keySystemIdToKeySystemDomain ( pssh . systemId )
576
- : null ;
577
- return keySystem ? keySystems . indexOf ( keySystem ) > - 1 : false ;
578
- } ) [ 0 ] ;
551
+ this . keyFormatPromise . then ( ( keySystemFormat ) => {
552
+ const keySystem = keySystemFormatToKeySystemDomain ( keySystemFormat ) ;
579
553
580
- if ( ! psshInfo ) {
554
+ let keyId : Uint8Array | null | undefined ;
555
+ let keySystemDomain : KeySystems | undefined ;
556
+
557
+ if ( initDataType === 'sinf' ) {
558
+ if ( keySystem !== KeySystems . FAIRPLAY ) {
559
+ this . warn (
560
+ `Ignoring unexpected "${ event . type } " event with init data type: "${ initDataType } " for selected key-system ${ keySystem } ` ,
561
+ ) ;
562
+ return ;
563
+ }
564
+ // Match sinf keyId to playlist skd://keyId=
565
+ const json = bin2str ( new Uint8Array ( initData ) ) ;
566
+ try {
567
+ const sinf = base64Decode ( JSON . parse ( json ) . sinf ) ;
568
+ const tenc = parseSinf ( sinf ) ;
569
+ if ( ! tenc ) {
570
+ throw new Error (
571
+ `'schm' box missing or not cbcs/cenc with schi > tenc` ,
572
+ ) ;
573
+ }
574
+ keyId = tenc . subarray ( 8 , 24 ) ;
575
+ keySystemDomain = KeySystems . FAIRPLAY ;
576
+ } catch ( error ) {
577
+ this . warn ( `${ logMessage } Failed to parse sinf: ${ error } ` ) ;
578
+ return ;
579
+ }
580
+ } else {
581
581
if (
582
- psshResults . length === 0 ||
583
- psshResults . some ( ( pssh ) : pssh is PsshInvalidResult => ! pssh . systemId )
582
+ keySystem !== KeySystems . WIDEVINE &&
583
+ keySystem !== KeySystems . PLAYREADY
584
584
) {
585
- this . warn ( `${ logMessage } contains incomplete or invalid pssh data` ) ;
586
- } else {
587
- this . log (
588
- `ignoring ${ logMessage } for ${ ( psshResults as PsshData [ ] )
589
- . map ( ( pssh ) => keySystemIdToKeySystemDomain ( pssh . systemId ) )
590
- . join ( ',' ) } pssh data in favor of playlist keys`,
585
+ this . warn (
586
+ `Ignoring unexpected "${ event . type } " event with init data type: "${ initDataType } " for selected key-system ${ keySystem } ` ,
591
587
) ;
588
+ return ;
592
589
}
593
- return ;
594
- }
590
+ // Support Widevine/PlayReady clear-lead key-session creation (otherwise depend on playlist keys)
591
+ const psshResults = parseMultiPssh ( initData ) ;
595
592
596
- keySystemDomain = keySystemIdToKeySystemDomain ( psshInfo . systemId ) ;
597
- if ( psshInfo . version === 0 && psshInfo . data ) {
598
- if ( keySystemDomain === KeySystems . WIDEVINE ) {
599
- const offset = psshInfo . data . length - 22 ;
600
- keyId = psshInfo . data . subarray ( offset , offset + 16 ) ;
601
- } else if ( keySystemDomain === KeySystems . PLAYREADY ) {
602
- keyId = parsePlayReadyWRM ( psshInfo . data ) ;
593
+ const psshInfos = psshResults . filter (
594
+ ( pssh ) : pssh is PsshData =>
595
+ ! ! pssh . systemId &&
596
+ keySystemIdToKeySystemDomain ( pssh . systemId ) === keySystem ,
597
+ ) ;
598
+
599
+ if ( psshInfos . length ) {
600
+ this . warn (
601
+ `${ logMessage } Using first of ${ psshInfos . length } pssh found for selected key-system ${ keySystem } ` ,
602
+ ) ;
603
603
}
604
- }
605
- }
606
604
607
- if ( ! keySystemDomain || ! keyId ) {
608
- return ;
609
- }
605
+ const psshInfo = psshInfos [ 0 ] ;
610
606
611
- const keyIdHex = Hex . hexDump ( keyId ) ;
612
- const { keyIdToKeySessionPromise, mediaKeySessions } = this ;
607
+ if ( ! psshInfo ) {
608
+ if (
609
+ psshResults . length === 0 ||
610
+ psshResults . some (
611
+ ( pssh ) : pssh is PsshInvalidResult => ! pssh . systemId ,
612
+ )
613
+ ) {
614
+ this . warn ( `${ logMessage } contains incomplete or invalid pssh data` ) ;
615
+ } else {
616
+ this . log (
617
+ `ignoring ${ logMessage } for ${ ( psshResults as PsshData [ ] )
618
+ . map ( ( pssh ) => keySystemIdToKeySystemDomain ( pssh . systemId ) )
619
+ . join ( ',' ) } pssh data in favor of playlist keys`,
620
+ ) ;
621
+ }
622
+ return ;
623
+ }
613
624
614
- let keySessionContextPromise = keyIdToKeySessionPromise [ keyIdHex ] ;
615
- for ( let i = 0 ; i < mediaKeySessions . length ; i ++ ) {
616
- // Match playlist key
617
- const keyContext = mediaKeySessions [ i ] ;
618
- const decryptdata = keyContext . decryptdata ;
619
- if ( ! decryptdata . keyId ) {
620
- continue ;
621
- }
622
- const oldKeyIdHex = Hex . hexDump ( decryptdata . keyId ) ;
623
- if (
624
- keyIdHex === oldKeyIdHex ||
625
- decryptdata . uri . replace ( / - / g, '' ) . indexOf ( keyIdHex ) !== - 1
626
- ) {
627
- keySessionContextPromise = keyIdToKeySessionPromise [ oldKeyIdHex ] ;
628
- if ( decryptdata . pssh ) {
629
- break ;
625
+ keySystemDomain = keySystemIdToKeySystemDomain ( psshInfo . systemId ) ;
626
+ if ( psshInfo . version === 0 && psshInfo . data ) {
627
+ if ( keySystemDomain === KeySystems . WIDEVINE ) {
628
+ const offset = psshInfo . data . length - 22 ;
629
+ keyId = psshInfo . data . subarray ( offset , offset + 16 ) ;
630
+ } else if ( keySystemDomain === KeySystems . PLAYREADY ) {
631
+ keyId = parsePlayReadyWRM ( psshInfo . data ) ;
632
+ }
630
633
}
631
- delete keyIdToKeySessionPromise [ oldKeyIdHex ] ;
632
- decryptdata . pssh = new Uint8Array ( initData ) ;
633
- decryptdata . keyId = keyId ;
634
- keySessionContextPromise = keyIdToKeySessionPromise [ keyIdHex ] =
635
- keySessionContextPromise . then ( ( ) => {
636
- return this . generateRequestWithPreferredKeySession (
637
- keyContext ,
638
- initDataType ,
639
- initData ,
640
- 'encrypted-event-key-match' ,
641
- ) ;
642
- } ) ;
643
- keySessionContextPromise . catch ( ( error ) => this . handleError ( error ) ) ;
644
- break ;
645
634
}
646
- }
647
635
648
- if ( ! keySessionContextPromise ) {
649
- // Clear-lead key (not encountered in playlist)
650
- keySessionContextPromise = keyIdToKeySessionPromise [ keyIdHex ] =
651
- this . getKeySystemSelectionPromise ( [ keySystemDomain ] ) . then (
652
- ( { keySystem, mediaKeys } ) => {
653
- this . throwIfDestroyed ( ) ;
654
- const decryptdata = new LevelKey (
655
- 'ISO-23001-7' ,
656
- keyIdHex ,
657
- keySystemToKeySystemFormat ( keySystem ) ?? '' ,
658
- ) ;
659
- decryptdata . pssh = new Uint8Array ( initData ) ;
660
- decryptdata . keyId = keyId as Uint8Array ;
661
- return this . attemptSetMediaKeys ( keySystem , mediaKeys ) . then ( ( ) => {
662
- this . throwIfDestroyed ( ) ;
663
- const keySessionContext = this . createMediaKeySessionContext ( {
664
- decryptdata,
665
- keySystem,
666
- mediaKeys,
667
- } ) ;
636
+ if ( ! keySystemDomain || ! keyId ) {
637
+ return ;
638
+ }
639
+
640
+ const keyIdHex = Hex . hexDump ( keyId ) ;
641
+ const { keyIdToKeySessionPromise, mediaKeySessions } = this ;
642
+
643
+ let keySessionContextPromise = keyIdToKeySessionPromise [ keyIdHex ] ;
644
+ for ( let i = 0 ; i < mediaKeySessions . length ; i ++ ) {
645
+ // Match playlist key
646
+ const keyContext = mediaKeySessions [ i ] ;
647
+ const decryptdata = keyContext . decryptdata ;
648
+ if ( ! decryptdata . keyId ) {
649
+ continue ;
650
+ }
651
+ const oldKeyIdHex = Hex . hexDump ( decryptdata . keyId ) ;
652
+ if (
653
+ keyIdHex === oldKeyIdHex ||
654
+ decryptdata . uri . replace ( / - / g, '' ) . indexOf ( keyIdHex ) !== - 1
655
+ ) {
656
+ keySessionContextPromise = keyIdToKeySessionPromise [ oldKeyIdHex ] ;
657
+ if ( decryptdata . pssh ) {
658
+ break ;
659
+ }
660
+ delete keyIdToKeySessionPromise [ oldKeyIdHex ] ;
661
+ decryptdata . pssh = new Uint8Array ( initData ) ;
662
+ decryptdata . keyId = keyId ;
663
+ keySessionContextPromise = keyIdToKeySessionPromise [ keyIdHex ] =
664
+ keySessionContextPromise . then ( ( ) => {
668
665
return this . generateRequestWithPreferredKeySession (
669
- keySessionContext ,
666
+ keyContext ,
670
667
initDataType ,
671
668
initData ,
672
- 'encrypted-event-no -match' ,
669
+ 'encrypted-event-key -match' ,
673
670
) ;
674
671
} ) ;
675
- } ,
676
- ) ;
677
- keySessionContextPromise . catch ( ( error ) => this . handleError ( error ) ) ;
678
- }
672
+ keySessionContextPromise . catch ( ( error ) => this . handleError ( error ) ) ;
673
+ break ;
674
+ }
675
+ }
676
+
677
+ if ( ! keySessionContextPromise ) {
678
+ if ( keySystemDomain !== keySystem ) {
679
+ this . log (
680
+ `Ignoring "${ event . type } " event with ${ keySystemDomain } init data for selected key-system ${ keySystem } ` ,
681
+ ) ;
682
+ return ;
683
+ }
684
+ // "Clear-lead" (misc key not encountered in playlist)
685
+ keySessionContextPromise = keyIdToKeySessionPromise [ keyIdHex ] =
686
+ this . getKeySystemSelectionPromise ( [ keySystemDomain ] ) . then (
687
+ ( { keySystem, mediaKeys } ) => {
688
+ this . throwIfDestroyed ( ) ;
689
+
690
+ const decryptdata = new LevelKey (
691
+ 'ISO-23001-7' ,
692
+ keyIdHex ,
693
+ keySystemToKeySystemFormat ( keySystem ) ?? '' ,
694
+ ) ;
695
+ decryptdata . pssh = new Uint8Array ( initData ) ;
696
+ decryptdata . keyId = keyId as Uint8Array ;
697
+ return this . attemptSetMediaKeys ( keySystem , mediaKeys ) . then ( ( ) => {
698
+ this . throwIfDestroyed ( ) ;
699
+ const keySessionContext = this . createMediaKeySessionContext ( {
700
+ decryptdata,
701
+ keySystem,
702
+ mediaKeys,
703
+ } ) ;
704
+ return this . generateRequestWithPreferredKeySession (
705
+ keySessionContext ,
706
+ initDataType ,
707
+ initData ,
708
+ 'encrypted-event-no-match' ,
709
+ ) ;
710
+ } ) ;
711
+ } ,
712
+ ) ;
713
+
714
+ keySessionContextPromise . catch ( ( error ) => this . handleError ( error ) ) ;
715
+ }
716
+ } ) ;
679
717
} ;
680
718
681
719
private onWaitingForKey = ( event : Event ) => {
0 commit comments