Home Reference Source

src/utils/mediakeys-helper.ts

  1. import type { DRMSystemOptions, EMEControllerConfig } from '../config';
  2.  
  3. /**
  4. * @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/requestMediaKeySystemAccess
  5. */
  6. export enum KeySystems {
  7. CLEARKEY = 'org.w3.clearkey',
  8. FAIRPLAY = 'com.apple.fps',
  9. PLAYREADY = 'com.microsoft.playready',
  10. WIDEVINE = 'com.widevine.alpha',
  11. }
  12.  
  13. // Playlist #EXT-X-KEY KEYFORMAT values
  14. export enum KeySystemFormats {
  15. CLEARKEY = 'org.w3.clearkey',
  16. FAIRPLAY = 'com.apple.streamingkeydelivery',
  17. PLAYREADY = 'com.microsoft.playready',
  18. WIDEVINE = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed',
  19. }
  20.  
  21. export function keySystemFormatToKeySystemDomain(
  22. format: KeySystemFormats
  23. ): KeySystems | undefined {
  24. switch (format) {
  25. case KeySystemFormats.FAIRPLAY:
  26. return KeySystems.FAIRPLAY;
  27. case KeySystemFormats.PLAYREADY:
  28. return KeySystems.PLAYREADY;
  29. case KeySystemFormats.WIDEVINE:
  30. return KeySystems.WIDEVINE;
  31. case KeySystemFormats.CLEARKEY:
  32. return KeySystems.CLEARKEY;
  33. }
  34. }
  35.  
  36. // System IDs for which we can extract a key ID from "encrypted" event PSSH
  37. export enum KeySystemIds {
  38. // CENC = '1077efecc0b24d02ace33c1e52e2fb4b'
  39. // CLEARKEY = 'e2719d58a985b3c9781ab030af78d30e',
  40. // FAIRPLAY = '94ce86fb07ff4f43adb893d2fa968ca2',
  41. // PLAYREADY = '9a04f07998404286ab92e65be0885f95',
  42. WIDEVINE = 'edef8ba979d64acea3c827dcd51d21ed',
  43. }
  44.  
  45. export function keySystemIdToKeySystemDomain(
  46. systemId: KeySystemIds
  47. ): KeySystems | undefined {
  48. if (systemId === KeySystemIds.WIDEVINE) {
  49. return KeySystems.WIDEVINE;
  50. // } else if (systemId === KeySystemIds.PLAYREADY) {
  51. // return KeySystems.PLAYREADY;
  52. // } else if (systemId === KeySystemIds.CENC || systemId === KeySystemIds.CLEARKEY) {
  53. // return KeySystems.CLEARKEY;
  54. }
  55. }
  56.  
  57. export function keySystemDomainToKeySystemFormat(
  58. keySystem: KeySystems
  59. ): KeySystemFormats | undefined {
  60. switch (keySystem) {
  61. case KeySystems.FAIRPLAY:
  62. return KeySystemFormats.FAIRPLAY;
  63. case KeySystems.PLAYREADY:
  64. return KeySystemFormats.PLAYREADY;
  65. case KeySystems.WIDEVINE:
  66. return KeySystemFormats.WIDEVINE;
  67. case KeySystems.CLEARKEY:
  68. return KeySystemFormats.CLEARKEY;
  69. }
  70. }
  71.  
  72. export function getKeySystemsForConfig(
  73. config: EMEControllerConfig
  74. ): KeySystems[] {
  75. const { drmSystems, widevineLicenseUrl } = config;
  76. const keySystemsToAttempt: KeySystems[] = drmSystems
  77. ? [
  78. KeySystems.FAIRPLAY,
  79. KeySystems.WIDEVINE,
  80. KeySystems.PLAYREADY,
  81. KeySystems.CLEARKEY,
  82. ].filter((keySystem) => !!drmSystems[keySystem])
  83. : [];
  84. if (!keySystemsToAttempt[KeySystems.WIDEVINE] && widevineLicenseUrl) {
  85. keySystemsToAttempt.push(KeySystems.WIDEVINE);
  86. }
  87. return keySystemsToAttempt;
  88. }
  89.  
  90. export type MediaKeyFunc = (
  91. keySystem: KeySystems,
  92. supportedConfigurations: MediaKeySystemConfiguration[]
  93. ) => Promise<MediaKeySystemAccess>;
  94.  
  95. export const requestMediaKeySystemAccess = (function (): MediaKeyFunc | null {
  96. if (
  97. typeof self !== 'undefined' &&
  98. self.navigator &&
  99. self.navigator.requestMediaKeySystemAccess
  100. ) {
  101. return self.navigator.requestMediaKeySystemAccess.bind(self.navigator);
  102. } else {
  103. return null;
  104. }
  105. })();
  106.  
  107. /**
  108. * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaKeySystemConfiguration
  109. */
  110. export function getSupportedMediaKeySystemConfigurations(
  111. keySystem: KeySystems,
  112. audioCodecs: string[],
  113. videoCodecs: string[],
  114. drmSystemOptions: DRMSystemOptions
  115. ): MediaKeySystemConfiguration[] {
  116. let initDataTypes: string[];
  117. switch (keySystem) {
  118. case KeySystems.FAIRPLAY:
  119. initDataTypes = ['cenc', 'sinf'];
  120. break;
  121. case KeySystems.WIDEVINE:
  122. case KeySystems.PLAYREADY:
  123. initDataTypes = ['cenc'];
  124. break;
  125. case KeySystems.CLEARKEY:
  126. initDataTypes = ['cenc', 'keyids'];
  127. break;
  128. default:
  129. throw new Error(`Unknown key-system: ${keySystem}`);
  130. }
  131. return createMediaKeySystemConfigurations(
  132. initDataTypes,
  133. audioCodecs,
  134. videoCodecs,
  135. drmSystemOptions
  136. );
  137. }
  138.  
  139. function createMediaKeySystemConfigurations(
  140. initDataTypes: string[],
  141. audioCodecs: string[],
  142. videoCodecs: string[],
  143. drmSystemOptions: DRMSystemOptions
  144. ): MediaKeySystemConfiguration[] {
  145. const baseConfig: MediaKeySystemConfiguration = {
  146. initDataTypes: initDataTypes,
  147. persistentState: drmSystemOptions.persistentState || 'not-allowed',
  148. distinctiveIdentifier:
  149. drmSystemOptions.distinctiveIdentifier || 'not-allowed',
  150. sessionTypes: drmSystemOptions.sessionTypes || [
  151. drmSystemOptions.sessionType || 'temporary',
  152. ],
  153. audioCapabilities: audioCodecs.map((codec) => ({
  154. contentType: `audio/mp4; codecs="${codec}"`,
  155. robustness: drmSystemOptions.audioRobustness || '',
  156. encryptionScheme: drmSystemOptions.audioEncryptionScheme || null,
  157. })),
  158. videoCapabilities: videoCodecs.map((codec) => ({
  159. contentType: `video/mp4; codecs="${codec}"`,
  160. robustness: drmSystemOptions.videoRobustness || '',
  161. encryptionScheme: drmSystemOptions.videoEncryptionScheme || null,
  162. })),
  163. };
  164.  
  165. return [baseConfig];
  166. }