hls.js 1.5.14-0.canary.10567 → 1.5.14-0.canary.10570

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/hls.d.mts CHANGED
@@ -840,6 +840,7 @@ export declare class EMEController extends Logger implements ComponentAPI {
840
840
  private registerListeners;
841
841
  private unregisterListeners;
842
842
  private getLicenseServerUrl;
843
+ private getLicenseServerUrlOrThrow;
843
844
  private getServerCertificateUrl;
844
845
  private attemptKeySystemAccess;
845
846
  private requestMediaKeySystemAccess;
package/dist/hls.d.ts CHANGED
@@ -840,6 +840,7 @@ export declare class EMEController extends Logger implements ComponentAPI {
840
840
  private registerListeners;
841
841
  private unregisterListeners;
842
842
  private getLicenseServerUrl;
843
+ private getLicenseServerUrlOrThrow;
843
844
  private getServerCertificateUrl;
844
845
  private attemptKeySystemAccess;
845
846
  private requestMediaKeySystemAccess;
package/dist/hls.js CHANGED
@@ -523,7 +523,7 @@
523
523
  // Some browsers don't allow to use bind on console object anyway
524
524
  // fallback to default if needed
525
525
  try {
526
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.14-0.canary.10567");
526
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.14-0.canary.10570");
527
527
  } catch (e) {
528
528
  /* log fn threw an exception. All logger methods are no-ops. */
529
529
  return createLogger();
@@ -1548,6 +1548,27 @@
1548
1548
  };
1549
1549
  return [baseConfig];
1550
1550
  }
1551
+ function parsePlayReadyWRM(keyBytes) {
1552
+ var keyBytesUtf16 = new Uint16Array(keyBytes.buffer, keyBytes.byteOffset, keyBytes.byteLength / 2);
1553
+ var keyByteStr = String.fromCharCode.apply(null, Array.from(keyBytesUtf16));
1554
+
1555
+ // Parse Playready WRMHeader XML
1556
+ var xmlKeyBytes = keyByteStr.substring(keyByteStr.indexOf('<'), keyByteStr.length);
1557
+ var parser = new DOMParser();
1558
+ var xmlDoc = parser.parseFromString(xmlKeyBytes, 'text/xml');
1559
+ var keyData = xmlDoc.getElementsByTagName('KID')[0];
1560
+ if (keyData) {
1561
+ var keyId = keyData.childNodes[0] ? keyData.childNodes[0].nodeValue : keyData.getAttribute('VALUE');
1562
+ if (keyId) {
1563
+ var keyIdArray = base64Decode(keyId).subarray(0, 16);
1564
+ // KID value in PRO is a base64-encoded little endian GUID interpretation of UUID
1565
+ // KID value in ‘tenc’ is a big endian UUID GUID interpretation of UUID
1566
+ changeEndianness(keyIdArray);
1567
+ return keyIdArray;
1568
+ }
1569
+ }
1570
+ return null;
1571
+ }
1551
1572
 
1552
1573
  function sliceUint8(array, start, end) {
1553
1574
  // @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
@@ -2903,6 +2924,8 @@
2903
2924
  if (keyBytes) {
2904
2925
  switch (this.keyFormat) {
2905
2926
  case KeySystemFormats.WIDEVINE:
2927
+ // Setting `pssh` on this LevelKey/DecryptData allows HLS.js to generate a session using
2928
+ // the playlist-key before the "encrypted" event. (Comment out to only use "encrypted" path.)
2906
2929
  this.pssh = keyBytes;
2907
2930
  // In case of widevine keyID is embedded in PSSH box. Read Key ID.
2908
2931
  if (keyBytes.length >= 22) {
@@ -2912,25 +2935,11 @@
2912
2935
  case KeySystemFormats.PLAYREADY:
2913
2936
  {
2914
2937
  var PlayReadyKeySystemUUID = new Uint8Array([0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95]);
2938
+
2939
+ // Setting `pssh` on this LevelKey/DecryptData allows HLS.js to generate a session using
2940
+ // the playlist-key before the "encrypted" event. (Comment out to only use "encrypted" path.)
2915
2941
  this.pssh = mp4pssh(PlayReadyKeySystemUUID, null, keyBytes);
2916
- var keyBytesUtf16 = new Uint16Array(keyBytes.buffer, keyBytes.byteOffset, keyBytes.byteLength / 2);
2917
- var keyByteStr = String.fromCharCode.apply(null, Array.from(keyBytesUtf16));
2918
-
2919
- // Parse Playready WRMHeader XML
2920
- var xmlKeyBytes = keyByteStr.substring(keyByteStr.indexOf('<'), keyByteStr.length);
2921
- var parser = new DOMParser();
2922
- var xmlDoc = parser.parseFromString(xmlKeyBytes, 'text/xml');
2923
- var keyData = xmlDoc.getElementsByTagName('KID')[0];
2924
- if (keyData) {
2925
- var keyId = keyData.childNodes[0] ? keyData.childNodes[0].nodeValue : keyData.getAttribute('VALUE');
2926
- if (keyId) {
2927
- var keyIdArray = base64Decode(keyId).subarray(0, 16);
2928
- // KID value in PRO is a base64-encoded little endian GUID interpretation of UUID
2929
- // KID value in ‘tenc’ is a big endian UUID GUID interpretation of UUID
2930
- changeEndianness(keyIdArray);
2931
- this.keyId = keyIdArray;
2932
- }
2933
- }
2942
+ this.keyId = parsePlayReadyWRM(keyBytes);
2934
2943
  break;
2935
2944
  }
2936
2945
  default:
@@ -2949,15 +2958,15 @@
2949
2958
 
2950
2959
  // Default behavior: assign a new keyId for each uri
2951
2960
  if (!this.keyId || this.keyId.byteLength !== 16) {
2952
- var _keyId = keyUriToKeyIdMap[this.uri];
2953
- if (!_keyId) {
2961
+ var keyId = keyUriToKeyIdMap[this.uri];
2962
+ if (!keyId) {
2954
2963
  var val = Object.keys(keyUriToKeyIdMap).length % Number.MAX_SAFE_INTEGER;
2955
- _keyId = new Uint8Array(16);
2956
- var dv = new DataView(_keyId.buffer, 12, 4); // Just set the last 4 bytes
2964
+ keyId = new Uint8Array(16);
2965
+ var dv = new DataView(keyId.buffer, 12, 4); // Just set the last 4 bytes
2957
2966
  dv.setUint32(0, val);
2958
- keyUriToKeyIdMap[this.uri] = _keyId;
2967
+ keyUriToKeyIdMap[this.uri] = keyId;
2959
2968
  }
2960
- this.keyId = _keyId;
2969
+ this.keyId = keyId;
2961
2970
  }
2962
2971
  return this;
2963
2972
  };
@@ -11679,23 +11688,11 @@
11679
11688
  return timeOffset * 90000 + init90kHz;
11680
11689
  };
11681
11690
 
11682
- /**
11683
- * ADTS parser helper
11684
- * @link https://wiki.multimedia.cx/index.php?title=ADTS
11685
- */
11686
- function getAudioConfig(observer, data, offset, audioCodec) {
11687
- var adtsObjectType;
11688
- var originalAdtsObjectType;
11689
- var adtsExtensionSamplingIndex;
11690
- var adtsChannelConfig;
11691
- var config;
11692
- var userAgent = navigator.userAgent.toLowerCase();
11693
- var manifestCodec = audioCodec;
11691
+ function getAudioConfig(observer, data, offset, manifestCodec) {
11694
11692
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
11695
- // byte 2
11696
- adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
11697
- var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
11698
- if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
11693
+ var byte2 = data[offset + 2];
11694
+ var adtsSamplingIndex = byte2 >> 2 & 0xf;
11695
+ if (adtsSamplingIndex > 12) {
11699
11696
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
11700
11697
  observer.emit(Events.ERROR, Events.ERROR, {
11701
11698
  type: ErrorTypes.MEDIA_ERROR,
@@ -11706,53 +11703,12 @@
11706
11703
  });
11707
11704
  return;
11708
11705
  }
11709
- adtsChannelConfig = (data[offset + 2] & 0x01) << 2;
11710
- // byte 3
11711
- adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
11712
- logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
11713
- // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
11714
- if (/firefox|palemoon/i.test(userAgent)) {
11715
- if (adtsSamplingIndex >= 6) {
11716
- adtsObjectType = 5;
11717
- config = new Array(4);
11718
- // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
11719
- // there is a factor 2 between frame sample rate and output sample rate
11720
- // multiply frequency by 2 (see table below, equivalent to substract 3)
11721
- adtsExtensionSamplingIndex = adtsSamplingIndex - 3;
11722
- } else {
11723
- adtsObjectType = 2;
11724
- config = new Array(2);
11725
- adtsExtensionSamplingIndex = adtsSamplingIndex;
11726
- }
11727
- // Android : always use AAC
11728
- } else if (userAgent.indexOf('android') !== -1) {
11729
- adtsObjectType = 2;
11730
- config = new Array(2);
11731
- adtsExtensionSamplingIndex = adtsSamplingIndex;
11732
- } else {
11733
- /* for other browsers (Chrome/Vivaldi/Opera ...)
11734
- always force audio type to be HE-AAC SBR, as some browsers do not support audio codec switch properly (like Chrome ...)
11735
- */
11736
- adtsObjectType = 5;
11737
- config = new Array(4);
11738
- // if (manifest codec is HE-AAC or HE-AACv2) OR (manifest codec not specified AND frequency less than 24kHz)
11739
- if (audioCodec && (audioCodec.indexOf('mp4a.40.29') !== -1 || audioCodec.indexOf('mp4a.40.5') !== -1) || !audioCodec && adtsSamplingIndex >= 6) {
11740
- // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
11741
- // there is a factor 2 between frame sample rate and output sample rate
11742
- // multiply frequency by 2 (see table below, equivalent to substract 3)
11743
- adtsExtensionSamplingIndex = adtsSamplingIndex - 3;
11744
- } else {
11745
- // if (manifest codec is AAC) AND (frequency less than 24kHz AND nb channel is 1) OR (manifest codec not specified and mono audio)
11746
- // Chrome fails to play back with low frequency AAC LC mono when initialized with HE-AAC. This is not a problem with stereo.
11747
- if (audioCodec && audioCodec.indexOf('mp4a.40.2') !== -1 && (adtsSamplingIndex >= 6 && adtsChannelConfig === 1 || /vivaldi/i.test(userAgent)) || !audioCodec && adtsChannelConfig === 1) {
11748
- adtsObjectType = 2;
11749
- config = new Array(2);
11750
- }
11751
- adtsExtensionSamplingIndex = adtsSamplingIndex;
11752
- }
11753
- }
11706
+ // MPEG-4 Audio Object Type (profile_ObjectType+1)
11707
+ var adtsObjectType = (byte2 >> 6 & 0x3) + 1;
11708
+ var channelCount = data[offset + 3] >> 6 & 0x3 | (byte2 & 1) << 2;
11709
+ var codec = 'mp4a.40.' + adtsObjectType;
11754
11710
  /* refer to http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config
11755
- ISO 14496-3 (AAC).pdf - Table 1.13 — Syntax of AudioSpecificConfig()
11711
+ ISO/IEC 14496-3 - Table 1.13 — Syntax of AudioSpecificConfig()
11756
11712
  Audio Profile / Audio Object Type
11757
11713
  0: Null
11758
11714
  1: AAC Main
@@ -11785,27 +11741,22 @@
11785
11741
  2: 2 channels: front-left, front-right
11786
11742
  */
11787
11743
  // audioObjectType = profile => profile, the MPEG-4 Audio Object Type minus 1
11788
- config[0] = adtsObjectType << 3;
11789
- // samplingFrequencyIndex
11790
- config[0] |= (adtsSamplingIndex & 0x0e) >> 1;
11791
- config[1] |= (adtsSamplingIndex & 0x01) << 7;
11792
- // channelConfiguration
11793
- config[1] |= adtsChannelConfig << 3;
11794
- if (adtsObjectType === 5) {
11795
- // adtsExtensionSamplingIndex
11796
- config[1] |= (adtsExtensionSamplingIndex & 0x0e) >> 1;
11797
- config[2] = (adtsExtensionSamplingIndex & 0x01) << 7;
11798
- // adtsObjectType (force to 2, chrome is checking that object type is less than 5 ???
11799
- // https://chromium.googlesource.com/chromium/src.git/+/master/media/formats/mp4/aac.cc
11800
- config[2] |= 2 << 2;
11801
- config[3] = 0;
11802
- }
11744
+ var samplerate = adtsSamplingRates[adtsSamplingIndex];
11745
+ var aacSampleIndex = adtsSamplingIndex;
11746
+ if (adtsObjectType === 5 || adtsObjectType === 29) {
11747
+ // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
11748
+ // there is a factor 2 between frame sample rate and output sample rate
11749
+ // multiply frequency by 2 (see table above, equivalent to substract 3)
11750
+ aacSampleIndex -= 3;
11751
+ }
11752
+ var config = [adtsObjectType << 3 | (aacSampleIndex & 0x0e) >> 1, (aacSampleIndex & 0x01) << 7 | channelCount << 3];
11753
+ logger.log("manifest codec:" + manifestCodec + ", parsed codec:" + codec + ", channels:" + channelCount + ", rate:" + samplerate + " (ADTS object type:" + adtsObjectType + " sampling index:" + adtsSamplingIndex + ")");
11803
11754
  return {
11804
11755
  config: config,
11805
- samplerate: adtsSamplingRates[adtsSamplingIndex],
11806
- channelCount: adtsChannelConfig,
11807
- codec: 'mp4a.40.' + adtsObjectType,
11808
- parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
11756
+ samplerate: samplerate,
11757
+ channelCount: channelCount,
11758
+ codec: codec,
11759
+ parsedCodec: codec,
11809
11760
  manifestCodec: manifestCodec
11810
11761
  };
11811
11762
  }
@@ -11855,13 +11806,7 @@
11855
11806
  if (!config) {
11856
11807
  return;
11857
11808
  }
11858
- track.config = config.config;
11859
- track.samplerate = config.samplerate;
11860
- track.channelCount = config.channelCount;
11861
- track.codec = config.codec;
11862
- track.manifestCodec = config.manifestCodec;
11863
- track.parsedCodec = config.parsedCodec;
11864
- logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
11809
+ _extends(track, config);
11865
11810
  }
11866
11811
  }
11867
11812
  function getFrameDuration(samplerate) {
@@ -15078,7 +15023,7 @@
15078
15023
  vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
15079
15024
  };
15080
15025
  MP4.esds = function esds(track) {
15081
- var configlen = track.config.length;
15026
+ var config = track.config;
15082
15027
  return new Uint8Array([0x00,
15083
15028
  // version 0
15084
15029
  0x00, 0x00, 0x00,
@@ -15086,16 +15031,18 @@
15086
15031
 
15087
15032
  0x03,
15088
15033
  // descriptor_type
15089
- 0x17 + configlen,
15034
+ 0x19,
15090
15035
  // length
15036
+
15091
15037
  0x00, 0x01,
15092
15038
  // es_id
15039
+
15093
15040
  0x00,
15094
15041
  // stream_priority
15095
15042
 
15096
15043
  0x04,
15097
15044
  // descriptor_type
15098
- 0x0f + configlen,
15045
+ 0x11,
15099
15046
  // length
15100
15047
  0x40,
15101
15048
  // codec : mpeg4_audio
@@ -15108,8 +15055,10 @@
15108
15055
  0x00, 0x00, 0x00, 0x00,
15109
15056
  // avgBitrate
15110
15057
 
15111
- 0x05 // descriptor_type
15112
- ].concat([configlen]).concat(track.config).concat([0x06, 0x01, 0x02])); // GASpecificConfig)); // length + audio config descriptor
15058
+ 0x05,
15059
+ // descriptor_type
15060
+ 0x02].concat(config, [0x06, 0x01, 0x02 // GASpecificConfig)); // length + audio config descriptor
15061
+ ]));
15113
15062
  };
15114
15063
  MP4.audioStsd = function audioStsd(track) {
15115
15064
  var samplerate = track.samplerate;
@@ -17362,7 +17311,7 @@
17362
17311
  return !remuxResult.audio && !remuxResult.video && !remuxResult.text && !remuxResult.id3 && !remuxResult.initSegment;
17363
17312
  }
17364
17313
 
17365
- var version = "1.5.14-0.canary.10567";
17314
+ var version = "1.5.14-0.canary.10570";
17366
17315
 
17367
17316
  // ensure the worker ends up in the bundle
17368
17317
  // If the worker should not be included this gets aliased to empty.js
@@ -24215,7 +24164,7 @@
24215
24164
  }
24216
24165
  var keyId;
24217
24166
  var keySystemDomain;
24218
- if (initDataType === 'sinf' && _this.config.drmSystems[KeySystems.FAIRPLAY]) {
24167
+ if (initDataType === 'sinf' && _this.getLicenseServerUrl(KeySystems.FAIRPLAY)) {
24219
24168
  // Match sinf keyId to playlist skd://keyId=
24220
24169
  var json = bin2str(new Uint8Array(initData));
24221
24170
  try {
@@ -24230,11 +24179,18 @@
24230
24179
  _this.warn(logMessage + " Failed to parse sinf: " + error);
24231
24180
  return;
24232
24181
  }
24233
- } else {
24182
+ } else if (_this.getLicenseServerUrl(KeySystems.WIDEVINE)) {
24234
24183
  // Support Widevine clear-lead key-session creation (otherwise depend on playlist keys)
24235
24184
  var psshResults = parseMultiPssh(initData);
24185
+
24186
+ // TODO: If using keySystemAccessPromises we might want to wait until one is resolved
24187
+ var keySystems = Object.keys(_this.keySystemAccessPromises);
24188
+ if (!keySystems.length) {
24189
+ keySystems = getKeySystemsForConfig(_this.config);
24190
+ }
24236
24191
  var psshInfo = psshResults.filter(function (pssh) {
24237
- return pssh.systemId === KeySystemIds.WIDEVINE;
24192
+ var keySystem = pssh.systemId ? keySystemIdToKeySystemDomain(pssh.systemId) : null;
24193
+ return keySystem ? keySystems.indexOf(keySystem) > -1 : false;
24238
24194
  })[0];
24239
24195
  if (!psshInfo) {
24240
24196
  if (psshResults.length === 0 || psshResults.some(function (pssh) {
@@ -24250,8 +24206,12 @@
24250
24206
  }
24251
24207
  keySystemDomain = keySystemIdToKeySystemDomain(psshInfo.systemId);
24252
24208
  if (psshInfo.version === 0 && psshInfo.data) {
24253
- var offset = psshInfo.data.length - 22;
24254
- keyId = psshInfo.data.subarray(offset, offset + 16);
24209
+ if (keySystemDomain === KeySystems.WIDEVINE) {
24210
+ var offset = psshInfo.data.length - 22;
24211
+ keyId = psshInfo.data.subarray(offset, offset + 16);
24212
+ } else if (keySystemDomain === KeySystems.PLAYREADY) {
24213
+ keyId = parsePlayReadyWRM(psshInfo.data);
24214
+ }
24255
24215
  }
24256
24216
  }
24257
24217
  if (!keySystemDomain || !keyId) {
@@ -24363,7 +24323,13 @@
24363
24323
  if (keySystem === KeySystems.WIDEVINE && widevineLicenseUrl) {
24364
24324
  return widevineLicenseUrl;
24365
24325
  }
24366
- throw new Error("no license server URL configured for key-system \"" + keySystem + "\"");
24326
+ };
24327
+ _proto.getLicenseServerUrlOrThrow = function getLicenseServerUrlOrThrow(keySystem) {
24328
+ var url = this.getLicenseServerUrl(keySystem);
24329
+ if (url === undefined) {
24330
+ throw new Error("no license server URL configured for key-system \"" + keySystem + "\"");
24331
+ }
24332
+ return url;
24367
24333
  };
24368
24334
  _proto.getServerCertificateUrl = function getServerCertificateUrl(keySystem) {
24369
24335
  var drmSystems = this.config.drmSystems;
@@ -24911,7 +24877,7 @@
24911
24877
  var _this13 = this;
24912
24878
  var keyLoadPolicy = this.config.keyLoadPolicy.default;
24913
24879
  return new Promise(function (resolve, reject) {
24914
- var url = _this13.getLicenseServerUrl(keySessionContext.keySystem);
24880
+ var url = _this13.getLicenseServerUrlOrThrow(keySessionContext.keySystem);
24915
24881
  _this13.log("Sending license request to URL: " + url);
24916
24882
  var xhr = new XMLHttpRequest();
24917
24883
  xhr.responseType = 'arraybuffer';
package/dist/hls.js.d.ts CHANGED
@@ -840,6 +840,7 @@ export declare class EMEController extends Logger implements ComponentAPI {
840
840
  private registerListeners;
841
841
  private unregisterListeners;
842
842
  private getLicenseServerUrl;
843
+ private getLicenseServerUrlOrThrow;
843
844
  private getServerCertificateUrl;
844
845
  private attemptKeySystemAccess;
845
846
  private requestMediaKeySystemAccess;