@webex/web-client-media-engine 3.34.5 → 3.35.0

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/cjs/index.js CHANGED
@@ -7740,6 +7740,7 @@ exports.WcmeErrorType = void 0;
7740
7740
  WcmeErrorType["SET_SOURCE_STATE_OVERRIDE_FAILED"] = "SET_SOURCE_STATE_OVERRIDE_FAILED";
7741
7741
  WcmeErrorType["DATA_CHANNEL_SEND_FAILED"] = "DATA_CHANNEL_SEND_FAILED";
7742
7742
  WcmeErrorType["RENEW_PEER_CONNECTION_FAILED"] = "RENEW_PEER_CONNECTION_FAILED";
7743
+ WcmeErrorType["UNSUPPORTED_CONFIG"] = "UNSUPPORTED_CONFIG";
7743
7744
  })(exports.WcmeErrorType || (exports.WcmeErrorType = {}));
7744
7745
  class WcmeError {
7745
7746
  constructor(type, message = '') {
@@ -10099,6 +10100,12 @@ class BrowserInfo {
10099
10100
  }
10100
10101
  BrowserInfo.browser = Bowser.getParser(window.navigator.userAgent);
10101
10102
 
10103
+ class CpuInfo {
10104
+ static getNumLogicalCores() {
10105
+ return navigator.hardwareConcurrency;
10106
+ }
10107
+ }
10108
+
10102
10109
  var SystemInfoEvents;
10103
10110
  (function (SystemInfoEvents) {
10104
10111
  SystemInfoEvents["CpuPressureStateChange"] = "cpu-pressure-state-change";
@@ -10136,7 +10143,58 @@ var CapabilityState;
10136
10143
  CapabilityState["NOT_CAPABLE"] = "not capable";
10137
10144
  CapabilityState["CAPABLE"] = "capable";
10138
10145
  CapabilityState["UNKNOWN"] = "unknown";
10139
- })(CapabilityState || (CapabilityState = {}));
10146
+ })(CapabilityState || (CapabilityState = {}));
10147
+ class WebCapabilities {
10148
+ static isCapableOfBackgroundNoiseRemoval() {
10149
+ const numCores = CpuInfo.getNumLogicalCores();
10150
+ if (numCores === undefined) {
10151
+ return CapabilityState.UNKNOWN;
10152
+ }
10153
+ if (numCores < 2) {
10154
+ return CapabilityState.NOT_CAPABLE;
10155
+ }
10156
+ return CapabilityState.CAPABLE;
10157
+ }
10158
+ static isCapableOfVirtualBackground() {
10159
+ const numCores = CpuInfo.getNumLogicalCores();
10160
+ if (numCores === undefined) {
10161
+ return CapabilityState.UNKNOWN;
10162
+ }
10163
+ if (numCores < 2) {
10164
+ return CapabilityState.NOT_CAPABLE;
10165
+ }
10166
+ return CapabilityState.CAPABLE;
10167
+ }
10168
+ static isCapableOfReceiving1080pVideo() {
10169
+ const numCores = CpuInfo.getNumLogicalCores();
10170
+ if (numCores === undefined) {
10171
+ return CapabilityState.UNKNOWN;
10172
+ }
10173
+ if (numCores < 2) {
10174
+ return CapabilityState.NOT_CAPABLE;
10175
+ }
10176
+ return CapabilityState.CAPABLE;
10177
+ }
10178
+ static isCapableOfSending1080pVideo() {
10179
+ const numCores = CpuInfo.getNumLogicalCores();
10180
+ if (numCores === undefined) {
10181
+ return CapabilityState.UNKNOWN;
10182
+ }
10183
+ if (numCores < 8) {
10184
+ return CapabilityState.NOT_CAPABLE;
10185
+ }
10186
+ return CapabilityState.CAPABLE;
10187
+ }
10188
+ static supportsEncodedStreamTransforms() {
10189
+ return window.RTCRtpScriptTransform &&
10190
+ window.RTCRtpSender &&
10191
+ 'transform' in RTCRtpSender.prototype &&
10192
+ window.RTCRtpReceiver &&
10193
+ 'transform' in RTCRtpReceiver.prototype
10194
+ ? CapabilityState.CAPABLE
10195
+ : CapabilityState.NOT_CAPABLE;
10196
+ }
10197
+ }
10140
10198
 
10141
10199
  const simulcastMaxFrameSizes = {
10142
10200
  0: '240',
@@ -11060,6 +11118,21 @@ class HomerMsg {
11060
11118
  }
11061
11119
  }
11062
11120
 
11121
+ var EncodedTransformType;
11122
+ (function (EncodedTransformType) {
11123
+ EncodedTransformType["AudioLevelMonitor"] = "audio-level-monitor";
11124
+ })(EncodedTransformType || (EncodedTransformType = {}));
11125
+ var MainMsgType;
11126
+ (function (MainMsgType) {
11127
+ MainMsgType["GetMetadata"] = "get-metadata";
11128
+ MainMsgType["ClearMetadata"] = "clear-metadata";
11129
+ })(MainMsgType || (MainMsgType = {}));
11130
+ var WorkerMsgType;
11131
+ (function (WorkerMsgType) {
11132
+ WorkerMsgType["Response"] = "response";
11133
+ WorkerMsgType["Log"] = "log";
11134
+ })(WorkerMsgType || (WorkerMsgType = {}));
11135
+
11063
11136
  class MidPredictor {
11064
11137
  constructor() {
11065
11138
  this.currentMid = 0;
@@ -11240,6 +11313,7 @@ class ReceiveOnlyTransceiver extends Transceiver {
11240
11313
  constructor(config) {
11241
11314
  super(config);
11242
11315
  this.metadata = { isActiveSpeaker: false };
11316
+ this.getEncodedStreamMetadataCallback = () => Promise.resolve(undefined);
11243
11317
  this.munger = config.munger;
11244
11318
  this._receiveSlot = new ReceiveSlot(() => {
11245
11319
  if (!this._rtcRtpTransceiver.mid) {
@@ -11248,6 +11322,9 @@ class ReceiveOnlyTransceiver extends Transceiver {
11248
11322
  return this.munger.getReceiverId();
11249
11323
  }, this._rtcRtpTransceiver.receiver.track);
11250
11324
  }
11325
+ setEncodedStreamMetadataCallback(callback) {
11326
+ this.getEncodedStreamMetadataCallback = callback;
11327
+ }
11251
11328
  replaceTransceiver(newRtcRtpTransceiver) {
11252
11329
  super.replaceTransceiver(newRtcRtpTransceiver);
11253
11330
  this._receiveSlot._replaceTrack(newRtcRtpTransceiver.receiver.track);
@@ -11262,7 +11339,10 @@ class ReceiveOnlyTransceiver extends Transceiver {
11262
11339
  getStats() {
11263
11340
  return __awaiter(this, void 0, void 0, function* () {
11264
11341
  const statsMap = new Map();
11265
- const statsReport = yield this.receiver.getStats();
11342
+ const [statsReport, encodedStreamMetadata] = yield Promise.all([
11343
+ this.receiver.getStats(),
11344
+ this.getEncodedStreamMetadataCallback(),
11345
+ ]);
11266
11346
  statsReport.forEach((stats, key) => {
11267
11347
  if (stats.type === 'inbound-rtp') {
11268
11348
  stats.mid = this.mid;
@@ -11276,6 +11356,10 @@ class ReceiveOnlyTransceiver extends Transceiver {
11276
11356
  stats.lastRequestedUpdateTimestamp = this.metadata.lastRequestedUpdateTimestamp;
11277
11357
  stats.isActiveSpeaker = this.metadata.isActiveSpeaker;
11278
11358
  stats.lastActiveSpeakerUpdateTimestamp = this.metadata.lastActiveSpeakerUpdateTimestamp;
11359
+ stats.maxAudioLevelFromRtpHeader =
11360
+ encodedStreamMetadata && 'maxAudioLevel' in encodedStreamMetadata
11361
+ ? encodedStreamMetadata.maxAudioLevel
11362
+ : undefined;
11279
11363
  Object.assign(stats, this.receiverId);
11280
11364
  }
11281
11365
  statsMap.set(key, stats);
@@ -15458,6 +15542,154 @@ const organizeTransceiverStats = (sendTransceivers, recvTransceivers, peerConnec
15458
15542
  return result;
15459
15543
  });
15460
15544
 
15545
+ var WorkerClass = null;
15546
+
15547
+ try {
15548
+ var WorkerThreads =
15549
+ typeof module !== 'undefined' && typeof module.require === 'function' && module.require('worker_threads') ||
15550
+ typeof __non_webpack_require__ === 'function' && __non_webpack_require__('worker_threads') ||
15551
+ typeof require === 'function' && require('worker_threads');
15552
+ WorkerClass = WorkerThreads.Worker;
15553
+ } catch(e) {} // eslint-disable-line
15554
+
15555
+ function decodeBase64$1(base64, enableUnicode) {
15556
+ return Buffer.from(base64, 'base64').toString(enableUnicode ? 'utf16' : 'utf8');
15557
+ }
15558
+
15559
+ function createBase64WorkerFactory$2(base64, sourcemapArg, enableUnicodeArg) {
15560
+ var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
15561
+ var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
15562
+ var source = decodeBase64$1(base64, enableUnicode);
15563
+ var start = source.indexOf('\n', 10) + 1;
15564
+ var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
15565
+ return function WorkerFactory(options) {
15566
+ return new WorkerClass(body, Object.assign({}, options, { eval: true }));
15567
+ };
15568
+ }
15569
+
15570
+ function decodeBase64(base64, enableUnicode) {
15571
+ var binaryString = atob(base64);
15572
+ if (enableUnicode) {
15573
+ var binaryView = new Uint8Array(binaryString.length);
15574
+ for (var i = 0, n = binaryString.length; i < n; ++i) {
15575
+ binaryView[i] = binaryString.charCodeAt(i);
15576
+ }
15577
+ const decoder = new TextDecoder("utf-16le");
15578
+ return decoder.decode(new Uint16Array(binaryView.buffer));
15579
+ }
15580
+ return binaryString;
15581
+ }
15582
+
15583
+ function createURL(base64, sourcemapArg, enableUnicodeArg) {
15584
+ var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
15585
+ var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
15586
+ var source = decodeBase64(base64, enableUnicode);
15587
+ var start = source.indexOf('\n', 10) + 1;
15588
+ var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
15589
+ var blob = new Blob([body], { type: 'application/javascript' });
15590
+ return URL.createObjectURL(blob);
15591
+ }
15592
+
15593
+ function createBase64WorkerFactory$1(base64, sourcemapArg, enableUnicodeArg) {
15594
+ var url;
15595
+ return function WorkerFactory(options) {
15596
+ url = url || createURL(base64, sourcemapArg, enableUnicodeArg);
15597
+ return new Worker(url, options);
15598
+ };
15599
+ }
15600
+
15601
+ var kIsNodeJS = Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';
15602
+
15603
+ function isNodeJS() {
15604
+ return kIsNodeJS;
15605
+ }
15606
+
15607
+ function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
15608
+ if (isNodeJS()) {
15609
+ return createBase64WorkerFactory$2(base64, sourcemapArg, enableUnicodeArg);
15610
+ }
15611
+ return createBase64WorkerFactory$1(base64, sourcemapArg, enableUnicodeArg);
15612
+ }
15613
+
15614
+ var WorkerFactory = /*#__PURE__*/createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewogICAgJ3VzZSBzdHJpY3QnOwoKICAgIHZhciBjb21tb25qc0dsb2JhbCA9IHR5cGVvZiBnbG9iYWxUaGlzICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbFRoaXMgOiB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IHdpbmRvdyA6IHR5cGVvZiBnbG9iYWwgIT09ICd1bmRlZmluZWQnID8gZ2xvYmFsIDogdHlwZW9mIHNlbGYgIT09ICd1bmRlZmluZWQnID8gc2VsZiA6IHt9OwoKICAgIHZhciBsb2dnZXIgPSB7ZXhwb3J0czoge319OwoKICAgIC8qIQ0KICAgICAqIGpzLWxvZ2dlciAtIGh0dHA6Ly9naXRodWIuY29tL2pvbm55cmVldmVzL2pzLWxvZ2dlcg0KICAgICAqIEpvbm55IFJlZXZlcywgaHR0cDovL2pvbm55cmVldmVzLmNvLnVrLw0KICAgICAqIGpzLWxvZ2dlciBtYXkgYmUgZnJlZWx5IGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS4NCiAgICAgKi8KCiAgICAoZnVuY3Rpb24gKG1vZHVsZSkgewogICAgKGZ1bmN0aW9uIChnbG9iYWwpIHsNCg0KICAgIAkvLyBUb3AgbGV2ZWwgbW9kdWxlIGZvciB0aGUgZ2xvYmFsLCBzdGF0aWMgbG9nZ2VyIGluc3RhbmNlLg0KICAgIAl2YXIgTG9nZ2VyID0geyB9Ow0KDQogICAgCS8vIEZvciB0aG9zZSB0aGF0IGFyZSBhdCBob21lIHRoYXQgYXJlIGtlZXBpbmcgc2NvcmUuDQogICAgCUxvZ2dlci5WRVJTSU9OID0gIjEuNi4xIjsNCg0KICAgIAkvLyBGdW5jdGlvbiB3aGljaCBoYW5kbGVzIGFsbCBpbmNvbWluZyBsb2cgbWVzc2FnZXMuDQogICAgCXZhciBsb2dIYW5kbGVyOw0KDQogICAgCS8vIE1hcCBvZiBDb250ZXh0dWFsTG9nZ2VyIGluc3RhbmNlcyBieSBuYW1lOyB1c2VkIGJ5IExvZ2dlci5nZXQoKSB0byByZXR1cm4gdGhlIHNhbWUgbmFtZWQgaW5zdGFuY2UuDQogICAgCXZhciBjb250ZXh0dWFsTG9nZ2Vyc0J5TmFtZU1hcCA9IHt9Ow0KDQogICAgCS8vIFBvbHlmaWxsIGZvciBFUzUncyBGdW5jdGlvbi5iaW5kLg0KICAgIAl2YXIgYmluZCA9IGZ1bmN0aW9uKHNjb3BlLCBmdW5jKSB7DQogICAgCQlyZXR1cm4gZnVuY3Rpb24oKSB7DQogICAgCQkJcmV0dXJuIGZ1bmMuYXBwbHkoc2NvcGUsIGFyZ3VtZW50cyk7DQogICAgCQl9Ow0KICAgIAl9Ow0KDQogICAgCS8vIFN1cGVyIGV4Y2l0aW5nIG9iamVjdCBtZXJnZXItbWF0cm9uIDkwMDAgYWRkaW5nIGFub3RoZXIgMTAwIGJ5dGVzIHRvIHlvdXIgZG93bmxvYWQuDQogICAgCXZhciBtZXJnZSA9IGZ1bmN0aW9uICgpIHsNCiAgICAJCXZhciBhcmdzID0gYXJndW1lbnRzLCB0YXJnZXQgPSBhcmdzWzBdLCBrZXksIGk7DQogICAgCQlmb3IgKGkgPSAxOyBpIDwgYXJncy5sZW5ndGg7IGkrKykgew0KICAgIAkJCWZvciAoa2V5IGluIGFyZ3NbaV0pIHsNCiAgICAJCQkJaWYgKCEoa2V5IGluIHRhcmdldCkgJiYgYXJnc1tpXS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7DQogICAgCQkJCQl0YXJnZXRba2V5XSA9IGFyZ3NbaV1ba2V5XTsNCiAgICAJCQkJfQ0KICAgIAkJCX0NCiAgICAJCX0NCiAgICAJCXJldHVybiB0YXJnZXQ7DQogICAgCX07DQoNCiAgICAJLy8gSGVscGVyIHRvIGRlZmluZSBhIGxvZ2dpbmcgbGV2ZWwgb2JqZWN0OyBoZWxwcyB3aXRoIG9wdGltaXNhdGlvbi4NCiAgICAJdmFyIGRlZmluZUxvZ0xldmVsID0gZnVuY3Rpb24odmFsdWUsIG5hbWUpIHsNCiAgICAJCXJldHVybiB7IHZhbHVlOiB2YWx1ZSwgbmFtZTogbmFtZSB9Ow0KICAgIAl9Ow0KDQogICAgCS8vIFByZWRlZmluZWQgbG9nZ2luZyBsZXZlbHMuDQogICAgCUxvZ2dlci5UUkFDRSA9IGRlZmluZUxvZ0xldmVsKDEsICdUUkFDRScpOw0KICAgIAlMb2dnZXIuREVCVUcgPSBkZWZpbmVMb2dMZXZlbCgyLCAnREVCVUcnKTsNCiAgICAJTG9nZ2VyLklORk8gPSBkZWZpbmVMb2dMZXZlbCgzLCAnSU5GTycpOw0KICAgIAlMb2dnZXIuVElNRSA9IGRlZmluZUxvZ0xldmVsKDQsICdUSU1FJyk7DQogICAgCUxvZ2dlci5XQVJOID0gZGVmaW5lTG9nTGV2ZWwoNSwgJ1dBUk4nKTsNCiAgICAJTG9nZ2VyLkVSUk9SID0gZGVmaW5lTG9nTGV2ZWwoOCwgJ0VSUk9SJyk7DQogICAgCUxvZ2dlci5PRkYgPSBkZWZpbmVMb2dMZXZlbCg5OSwgJ09GRicpOw0KDQogICAgCS8vIElubmVyIGNsYXNzIHdoaWNoIHBlcmZvcm1zIHRoZSBidWxrIG9mIHRoZSB3b3JrOyBDb250ZXh0dWFsTG9nZ2VyIGluc3RhbmNlcyBjYW4gYmUgY29uZmlndXJlZCBpbmRlcGVuZGVudGx5DQogICAgCS8vIG9mIGVhY2ggb3RoZXIuDQogICAgCXZhciBDb250ZXh0dWFsTG9nZ2VyID0gZnVuY3Rpb24oZGVmYXVsdENvbnRleHQpIHsNCiAgICAJCXRoaXMuY29udGV4dCA9IGRlZmF1bHRDb250ZXh0Ow0KICAgIAkJdGhpcy5zZXRMZXZlbChkZWZhdWx0Q29udGV4dC5maWx0ZXJMZXZlbCk7DQogICAgCQl0aGlzLmxvZyA9IHRoaXMuaW5mbzsgIC8vIENvbnZlbmllbmNlIGFsaWFzLg0KICAgIAl9Ow0KDQogICAgCUNvbnRleHR1YWxMb2dnZXIucHJvdG90eXBlID0gew0KICAgIAkJLy8gQ2hhbmdlcyB0aGUgY3VycmVudCBsb2dnaW5nIGxldmVsIGZvciB0aGUgbG9nZ2luZyBpbnN0YW5jZS4NCiAgICAJCXNldExldmVsOiBmdW5jdGlvbiAobmV3TGV2ZWwpIHsNCiAgICAJCQkvLyBFbnN1cmUgdGhlIHN1cHBsaWVkIExldmVsIG9iamVjdCBsb29rcyB2YWxpZC4NCiAgICAJCQlpZiAobmV3TGV2ZWwgJiYgInZhbHVlIiBpbiBuZXdMZXZlbCkgew0KICAgIAkJCQl0aGlzLmNvbnRleHQuZmlsdGVyTGV2ZWwgPSBuZXdMZXZlbDsNCiAgICAJCQl9DQogICAgCQl9LA0KICAgIAkJDQogICAgCQkvLyBHZXRzIHRoZSBjdXJyZW50IGxvZ2dpbmcgbGV2ZWwgZm9yIHRoZSBsb2dnaW5nIGluc3RhbmNlDQogICAgCQlnZXRMZXZlbDogZnVuY3Rpb24gKCkgew0KICAgIAkJCXJldHVybiB0aGlzLmNvbnRleHQuZmlsdGVyTGV2ZWw7DQogICAgCQl9LA0KDQogICAgCQkvLyBJcyB0aGUgbG9nZ2VyIGNvbmZpZ3VyZWQgdG8gb3V0cHV0IG1lc3NhZ2VzIGF0IHRoZSBzdXBwbGllZCBsZXZlbD8NCiAgICAJCWVuYWJsZWRGb3I6IGZ1bmN0aW9uIChsdmwpIHsNCiAgICAJCQl2YXIgZmlsdGVyTGV2ZWwgPSB0aGlzLmNvbnRleHQuZmlsdGVyTGV2ZWw7DQogICAgCQkJcmV0dXJuIGx2bC52YWx1ZSA+PSBmaWx0ZXJMZXZlbC52YWx1ZTsNCiAgICAJCX0sDQoNCiAgICAJCXRyYWNlOiBmdW5jdGlvbiAoKSB7DQogICAgCQkJdGhpcy5pbnZva2UoTG9nZ2VyLlRSQUNFLCBhcmd1bWVudHMpOw0KICAgIAkJfSwNCg0KICAgIAkJZGVidWc6IGZ1bmN0aW9uICgpIHsNCiAgICAJCQl0aGlzLmludm9rZShMb2dnZXIuREVCVUcsIGFyZ3VtZW50cyk7DQogICAgCQl9LA0KDQogICAgCQlpbmZvOiBmdW5jdGlvbiAoKSB7DQogICAgCQkJdGhpcy5pbnZva2UoTG9nZ2VyLklORk8sIGFyZ3VtZW50cyk7DQogICAgCQl9LA0KDQogICAgCQl3YXJuOiBmdW5jdGlvbiAoKSB7DQogICAgCQkJdGhpcy5pbnZva2UoTG9nZ2VyLldBUk4sIGFyZ3VtZW50cyk7DQogICAgCQl9LA0KDQogICAgCQllcnJvcjogZnVuY3Rpb24gKCkgew0KICAgIAkJCXRoaXMuaW52b2tlKExvZ2dlci5FUlJPUiwgYXJndW1lbnRzKTsNCiAgICAJCX0sDQoNCiAgICAJCXRpbWU6IGZ1bmN0aW9uIChsYWJlbCkgew0KICAgIAkJCWlmICh0eXBlb2YgbGFiZWwgPT09ICdzdHJpbmcnICYmIGxhYmVsLmxlbmd0aCA+IDApIHsNCiAgICAJCQkJdGhpcy5pbnZva2UoTG9nZ2VyLlRJTUUsIFsgbGFiZWwsICdzdGFydCcgXSk7DQogICAgCQkJfQ0KICAgIAkJfSwNCg0KICAgIAkJdGltZUVuZDogZnVuY3Rpb24gKGxhYmVsKSB7DQogICAgCQkJaWYgKHR5cGVvZiBsYWJlbCA9PT0gJ3N0cmluZycgJiYgbGFiZWwubGVuZ3RoID4gMCkgew0KICAgIAkJCQl0aGlzLmludm9rZShMb2dnZXIuVElNRSwgWyBsYWJlbCwgJ2VuZCcgXSk7DQogICAgCQkJfQ0KICAgIAkJfSwNCg0KICAgIAkJLy8gSW52b2tlcyB0aGUgbG9nZ2VyIGNhbGxiYWNrIGlmIGl0J3Mgbm90IGJlaW5nIGZpbHRlcmVkLg0KICAgIAkJaW52b2tlOiBmdW5jdGlvbiAobGV2ZWwsIG1zZ0FyZ3MpIHsNCiAgICAJCQlpZiAobG9nSGFuZGxlciAmJiB0aGlzLmVuYWJsZWRGb3IobGV2ZWwpKSB7DQogICAgCQkJCWxvZ0hhbmRsZXIobXNnQXJncywgbWVyZ2UoeyBsZXZlbDogbGV2ZWwgfSwgdGhpcy5jb250ZXh0KSk7DQogICAgCQkJfQ0KICAgIAkJfQ0KICAgIAl9Ow0KDQogICAgCS8vIFByb3RlY3RlZCBpbnN0YW5jZSB3aGljaCBhbGwgY2FsbHMgdG8gdGhlIHRvIGxldmVsIGBMb2dnZXJgIG1vZHVsZSB3aWxsIGJlIHJvdXRlZCB0aHJvdWdoLg0KICAgIAl2YXIgZ2xvYmFsTG9nZ2VyID0gbmV3IENvbnRleHR1YWxMb2dnZXIoeyBmaWx0ZXJMZXZlbDogTG9nZ2VyLk9GRiB9KTsNCg0KICAgIAkvLyBDb25maWd1cmUgdGhlIGdsb2JhbCBMb2dnZXIgaW5zdGFuY2UuDQogICAgCShmdW5jdGlvbigpIHsNCiAgICAJCS8vIFNob3J0Y3V0IGZvciBvcHRpbWlzZXJzLg0KICAgIAkJdmFyIEwgPSBMb2dnZXI7DQoNCiAgICAJCUwuZW5hYmxlZEZvciA9IGJpbmQoZ2xvYmFsTG9nZ2VyLCBnbG9iYWxMb2dnZXIuZW5hYmxlZEZvcik7DQogICAgCQlMLnRyYWNlID0gYmluZChnbG9iYWxMb2dnZXIsIGdsb2JhbExvZ2dlci50cmFjZSk7DQogICAgCQlMLmRlYnVnID0gYmluZChnbG9iYWxMb2dnZXIsIGdsb2JhbExvZ2dlci5kZWJ1Zyk7DQogICAgCQlMLnRpbWUgPSBiaW5kKGdsb2JhbExvZ2dlciwgZ2xvYmFsTG9nZ2VyLnRpbWUpOw0KICAgIAkJTC50aW1lRW5kID0gYmluZChnbG9iYWxMb2dnZXIsIGdsb2JhbExvZ2dlci50aW1lRW5kKTsNCiAgICAJCUwuaW5mbyA9IGJpbmQoZ2xvYmFsTG9nZ2VyLCBnbG9iYWxMb2dnZXIuaW5mbyk7DQogICAgCQlMLndhcm4gPSBiaW5kKGdsb2JhbExvZ2dlciwgZ2xvYmFsTG9nZ2VyLndhcm4pOw0KICAgIAkJTC5lcnJvciA9IGJpbmQoZ2xvYmFsTG9nZ2VyLCBnbG9iYWxMb2dnZXIuZXJyb3IpOw0KDQogICAgCQkvLyBEb24ndCBmb3JnZXQgdGhlIGNvbnZlbmllbmNlIGFsaWFzIQ0KICAgIAkJTC5sb2cgPSBMLmluZm87DQogICAgCX0oKSk7DQoNCiAgICAJLy8gU2V0IHRoZSBnbG9iYWwgbG9nZ2luZyBoYW5kbGVyLiAgVGhlIHN1cHBsaWVkIGZ1bmN0aW9uIHNob3VsZCBleHBlY3QgdHdvIGFyZ3VtZW50cywgdGhlIGZpcnN0IGJlaW5nIGFuIGFyZ3VtZW50cw0KICAgIAkvLyBvYmplY3Qgd2l0aCB0aGUgc3VwcGxpZWQgbG9nIG1lc3NhZ2VzIGFuZCB0aGUgc2Vjb25kIGJlaW5nIGEgY29udGV4dCBvYmplY3Qgd2hpY2ggY29udGFpbnMgYSBoYXNoIG9mIHN0YXRlZnVsDQogICAgCS8vIHBhcmFtZXRlcnMgd2hpY2ggdGhlIGxvZ2dpbmcgZnVuY3Rpb24gY2FuIGNvbnN1bWUuDQogICAgCUxvZ2dlci5zZXRIYW5kbGVyID0gZnVuY3Rpb24gKGZ1bmMpIHsNCiAgICAJCWxvZ0hhbmRsZXIgPSBmdW5jOw0KICAgIAl9Ow0KDQogICAgCS8vIFNldHMgdGhlIGdsb2JhbCBsb2dnaW5nIGZpbHRlciBsZXZlbCB3aGljaCBhcHBsaWVzIHRvICphbGwqIHByZXZpb3VzbHkgcmVnaXN0ZXJlZCwgYW5kIGZ1dHVyZSBMb2dnZXIgaW5zdGFuY2VzLg0KICAgIAkvLyAobm90ZSB0aGF0IG5hbWVkIGxvZ2dlcnMgKHJldHJpZXZlZCB2aWEgYExvZ2dlci5nZXRgKSBjYW4gYmUgY29uZmlndXJlZCBpbmRlcGVuZGVudGx5IGlmIHJlcXVpcmVkKS4NCiAgICAJTG9nZ2VyLnNldExldmVsID0gZnVuY3Rpb24obGV2ZWwpIHsNCiAgICAJCS8vIFNldCB0aGUgZ2xvYmFsTG9nZ2VyJ3MgbGV2ZWwuDQogICAgCQlnbG9iYWxMb2dnZXIuc2V0TGV2ZWwobGV2ZWwpOw0KDQogICAgCQkvLyBBcHBseSB0aGlzIGxldmVsIHRvIGFsbCByZWdpc3RlcmVkIGNvbnRleHR1YWwgbG9nZ2Vycy4NCiAgICAJCWZvciAodmFyIGtleSBpbiBjb250ZXh0dWFsTG9nZ2Vyc0J5TmFtZU1hcCkgew0KICAgIAkJCWlmIChjb250ZXh0dWFsTG9nZ2Vyc0J5TmFtZU1hcC5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7DQogICAgCQkJCWNvbnRleHR1YWxMb2dnZXJzQnlOYW1lTWFwW2tleV0uc2V0TGV2ZWwobGV2ZWwpOw0KICAgIAkJCX0NCiAgICAJCX0NCiAgICAJfTsNCg0KICAgIAkvLyBHZXRzIHRoZSBnbG9iYWwgbG9nZ2luZyBmaWx0ZXIgbGV2ZWwNCiAgICAJTG9nZ2VyLmdldExldmVsID0gZnVuY3Rpb24oKSB7DQogICAgCQlyZXR1cm4gZ2xvYmFsTG9nZ2VyLmdldExldmVsKCk7DQogICAgCX07DQoNCiAgICAJLy8gUmV0cmlldmUgYSBDb250ZXh0dWFsTG9nZ2VyIGluc3RhbmNlLiAgTm90ZSB0aGF0IG5hbWVkIGxvZ2dlcnMgYXV0b21hdGljYWxseSBpbmhlcml0IHRoZSBnbG9iYWwgbG9nZ2VyJ3MgbGV2ZWwsDQogICAgCS8vIGRlZmF1bHQgY29udGV4dCBhbmQgbG9nIGhhbmRsZXIuDQogICAgCUxvZ2dlci5nZXQgPSBmdW5jdGlvbiAobmFtZSkgew0KICAgIAkJLy8gQWxsIGxvZ2dlciBpbnN0YW5jZXMgYXJlIGNhY2hlZCBzbyB0aGV5IGNhbiBiZSBjb25maWd1cmVkIGFoZWFkIG9mIHVzZS4NCiAgICAJCXJldHVybiBjb250ZXh0dWFsTG9nZ2Vyc0J5TmFtZU1hcFtuYW1lXSB8fA0KICAgIAkJCShjb250ZXh0dWFsTG9nZ2Vyc0J5TmFtZU1hcFtuYW1lXSA9IG5ldyBDb250ZXh0dWFsTG9nZ2VyKG1lcmdlKHsgbmFtZTogbmFtZSB9LCBnbG9iYWxMb2dnZXIuY29udGV4dCkpKTsNCiAgICAJfTsNCg0KICAgIAkvLyBDcmVhdGVEZWZhdWx0SGFuZGxlciByZXR1cm5zIGEgaGFuZGxlciBmdW5jdGlvbiB3aGljaCBjYW4gYmUgcGFzc2VkIHRvIGBMb2dnZXIuc2V0SGFuZGxlcigpYCB3aGljaCB3aWxsDQogICAgCS8vIHdyaXRlIHRvIHRoZSB3aW5kb3cncyBjb25zb2xlIG9iamVjdCAoaWYgcHJlc2VudCk7IHRoZSBvcHRpb25hbCBvcHRpb25zIG9iamVjdCBjYW4gYmUgdXNlZCB0byBjdXN0b21pc2UgdGhlDQogICAgCS8vIGZvcm1hdHRlciB1c2VkIHRvIGZvcm1hdCBlYWNoIGxvZyBtZXNzYWdlLg0KICAgIAlMb2dnZXIuY3JlYXRlRGVmYXVsdEhhbmRsZXIgPSBmdW5jdGlvbiAob3B0aW9ucykgew0KICAgIAkJb3B0aW9ucyA9IG9wdGlvbnMgfHwge307DQoNCiAgICAJCW9wdGlvbnMuZm9ybWF0dGVyID0gb3B0aW9ucy5mb3JtYXR0ZXIgfHwgZnVuY3Rpb24gZGVmYXVsdE1lc3NhZ2VGb3JtYXR0ZXIobWVzc2FnZXMsIGNvbnRleHQpIHsNCiAgICAJCQkvLyBQcmVwZW5kIHRoZSBsb2dnZXIncyBuYW1lIHRvIHRoZSBsb2cgbWVzc2FnZSBmb3IgZWFzeSBpZGVudGlmaWNhdGlvbi4NCiAgICAJCQlpZiAoY29udGV4dC5uYW1lKSB7DQogICAgCQkJCW1lc3NhZ2VzLnVuc2hpZnQoIlsiICsgY29udGV4dC5uYW1lICsgIl0iKTsNCiAgICAJCQl9DQogICAgCQl9Ow0KDQogICAgCQkvLyBNYXAgb2YgdGltZXN0YW1wcyBieSB0aW1lciBsYWJlbHMgdXNlZCB0byB0cmFjayBgI3RpbWVgIGFuZCBgI3RpbWVFbmQoKWAgaW52b2NhdGlvbnMgaW4gZW52aXJvbm1lbnRzDQogICAgCQkvLyB0aGF0IGRvbid0IG9mZmVyIGEgbmF0aXZlIGNvbnNvbGUgbWV0aG9kLg0KICAgIAkJdmFyIHRpbWVyU3RhcnRUaW1lQnlMYWJlbE1hcCA9IHt9Ow0KDQogICAgCQkvLyBTdXBwb3J0IGZvciBJRTgrIChhbmQgb3RoZXIsIHNsaWdodGx5IG1vcmUgc2FuZSBlbnZpcm9ubWVudHMpDQogICAgCQl2YXIgaW52b2tlQ29uc29sZU1ldGhvZCA9IGZ1bmN0aW9uIChoZGxyLCBtZXNzYWdlcykgew0KICAgIAkJCUZ1bmN0aW9uLnByb3RvdHlwZS5hcHBseS5jYWxsKGhkbHIsIGNvbnNvbGUsIG1lc3NhZ2VzKTsNCiAgICAJCX07DQoNCiAgICAJCS8vIENoZWNrIGZvciB0aGUgcHJlc2VuY2Ugb2YgYSBsb2dnZXIuDQogICAgCQlpZiAodHlwZW9mIGNvbnNvbGUgPT09ICJ1bmRlZmluZWQiKSB7DQogICAgCQkJcmV0dXJuIGZ1bmN0aW9uICgpIHsgLyogbm8gY29uc29sZSAqLyB9Ow0KICAgIAkJfQ0KDQogICAgCQlyZXR1cm4gZnVuY3Rpb24obWVzc2FnZXMsIGNvbnRleHQpIHsNCiAgICAJCQkvLyBDb252ZXJ0IGFyZ3VtZW50cyBvYmplY3QgdG8gQXJyYXkuDQogICAgCQkJbWVzc2FnZXMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChtZXNzYWdlcyk7DQoNCiAgICAJCQl2YXIgaGRsciA9IGNvbnNvbGUubG9nOw0KICAgIAkJCXZhciB0aW1lckxhYmVsOw0KDQogICAgCQkJaWYgKGNvbnRleHQubGV2ZWwgPT09IExvZ2dlci5USU1FKSB7DQogICAgCQkJCXRpbWVyTGFiZWwgPSAoY29udGV4dC5uYW1lID8gJ1snICsgY29udGV4dC5uYW1lICsgJ10gJyA6ICcnKSArIG1lc3NhZ2VzWzBdOw0KDQogICAgCQkJCWlmIChtZXNzYWdlc1sxXSA9PT0gJ3N0YXJ0Jykgew0KICAgIAkJCQkJaWYgKGNvbnNvbGUudGltZSkgew0KICAgIAkJCQkJCWNvbnNvbGUudGltZSh0aW1lckxhYmVsKTsNCiAgICAJCQkJCX0NCiAgICAJCQkJCWVsc2Ugew0KICAgIAkJCQkJCXRpbWVyU3RhcnRUaW1lQnlMYWJlbE1hcFt0aW1lckxhYmVsXSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpOw0KICAgIAkJCQkJfQ0KICAgIAkJCQl9DQogICAgCQkJCWVsc2Ugew0KICAgIAkJCQkJaWYgKGNvbnNvbGUudGltZUVuZCkgew0KICAgIAkJCQkJCWNvbnNvbGUudGltZUVuZCh0aW1lckxhYmVsKTsNCiAgICAJCQkJCX0NCiAgICAJCQkJCWVsc2Ugew0KICAgIAkJCQkJCWludm9rZUNvbnNvbGVNZXRob2QoaGRsciwgWyB0aW1lckxhYmVsICsgJzogJyArDQogICAgCQkJCQkJCShuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHRpbWVyU3RhcnRUaW1lQnlMYWJlbE1hcFt0aW1lckxhYmVsXSkgKyAnbXMnIF0pOw0KICAgIAkJCQkJfQ0KICAgIAkJCQl9DQogICAgCQkJfQ0KICAgIAkJCWVsc2Ugew0KICAgIAkJCQkvLyBEZWxlZ2F0ZSB0aHJvdWdoIHRvIGN1c3RvbSB3YXJuL2Vycm9yIGxvZ2dlcnMgaWYgcHJlc2VudCBvbiB0aGUgY29uc29sZS4NCiAgICAJCQkJaWYgKGNvbnRleHQubGV2ZWwgPT09IExvZ2dlci5XQVJOICYmIGNvbnNvbGUud2Fybikgew0KICAgIAkJCQkJaGRsciA9IGNvbnNvbGUud2FybjsNCiAgICAJCQkJfSBlbHNlIGlmIChjb250ZXh0LmxldmVsID09PSBMb2dnZXIuRVJST1IgJiYgY29uc29sZS5lcnJvcikgew0KICAgIAkJCQkJaGRsciA9IGNvbnNvbGUuZXJyb3I7DQogICAgCQkJCX0gZWxzZSBpZiAoY29udGV4dC5sZXZlbCA9PT0gTG9nZ2VyLklORk8gJiYgY29uc29sZS5pbmZvKSB7DQogICAgCQkJCQloZGxyID0gY29uc29sZS5pbmZvOw0KICAgIAkJCQl9IGVsc2UgaWYgKGNvbnRleHQubGV2ZWwgPT09IExvZ2dlci5ERUJVRyAmJiBjb25zb2xlLmRlYnVnKSB7DQogICAgCQkJCQloZGxyID0gY29uc29sZS5kZWJ1ZzsNCiAgICAJCQkJfSBlbHNlIGlmIChjb250ZXh0LmxldmVsID09PSBMb2dnZXIuVFJBQ0UgJiYgY29uc29sZS50cmFjZSkgew0KICAgIAkJCQkJaGRsciA9IGNvbnNvbGUudHJhY2U7DQogICAgCQkJCX0NCg0KICAgIAkJCQlvcHRpb25zLmZvcm1hdHRlcihtZXNzYWdlcywgY29udGV4dCk7DQogICAgCQkJCWludm9rZUNvbnNvbGVNZXRob2QoaGRsciwgbWVzc2FnZXMpOw0KICAgIAkJCX0NCiAgICAJCX07DQogICAgCX07DQoNCiAgICAJLy8gQ29uZmlndXJlIGFuZCBleGFtcGxlIGEgRGVmYXVsdCBpbXBsZW1lbnRhdGlvbiB3aGljaCB3cml0ZXMgdG8gdGhlIGB3aW5kb3cuY29uc29sZWAgKGlmIHByZXNlbnQpLiAgVGhlDQogICAgCS8vIGBvcHRpb25zYCBoYXNoIGNhbiBiZSB1c2VkIHRvIGNvbmZpZ3VyZSB0aGUgZGVmYXVsdCBsb2dMZXZlbCBhbmQgcHJvdmlkZSBhIGN1c3RvbSBtZXNzYWdlIGZvcm1hdHRlci4NCiAgICAJTG9nZ2VyLnVzZURlZmF1bHRzID0gZnVuY3Rpb24ob3B0aW9ucykgew0KICAgIAkJTG9nZ2VyLnNldExldmVsKG9wdGlvbnMgJiYgb3B0aW9ucy5kZWZhdWx0TGV2ZWwgfHwgTG9nZ2VyLkRFQlVHKTsNCiAgICAJCUxvZ2dlci5zZXRIYW5kbGVyKExvZ2dlci5jcmVhdGVEZWZhdWx0SGFuZGxlcihvcHRpb25zKSk7DQogICAgCX07DQoNCiAgICAJLy8gQ3JlYXRlYSBhbiBhbGlhcyB0byB1c2VEZWZhdWx0cyB0byBhdm9pZCByZWFraW5nIGEgcmVhY3QtaG9va3MgcnVsZS4NCiAgICAJTG9nZ2VyLnNldERlZmF1bHRzID0gTG9nZ2VyLnVzZURlZmF1bHRzOw0KDQogICAgCS8vIEV4cG9ydCB0byBwb3B1bGFyIGVudmlyb25tZW50cyBib2lsZXJwbGF0ZS4NCiAgICAJaWYgKG1vZHVsZS5leHBvcnRzKSB7DQogICAgCQltb2R1bGUuZXhwb3J0cyA9IExvZ2dlcjsNCiAgICAJfQ0KICAgIAllbHNlIHsNCiAgICAJCUxvZ2dlci5fcHJldkxvZ2dlciA9IGdsb2JhbC5Mb2dnZXI7DQoNCiAgICAJCUxvZ2dlci5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkgew0KICAgIAkJCWdsb2JhbC5Mb2dnZXIgPSBMb2dnZXIuX3ByZXZMb2dnZXI7DQogICAgCQkJcmV0dXJuIExvZ2dlcjsNCiAgICAJCX07DQoNCiAgICAJCWdsb2JhbC5Mb2dnZXIgPSBMb2dnZXI7DQogICAgCX0NCiAgICB9KGNvbW1vbmpzR2xvYmFsKSk7CiAgICB9KGxvZ2dlcikpOwoKICAgIHZhciBMb2dnZXIgPSBsb2dnZXIuZXhwb3J0czsKCiAgICBMb2dnZXIudXNlRGVmYXVsdHMoew0KICAgICAgICBkZWZhdWx0TGV2ZWw6IExvZ2dlci5ERUJVRywNCiAgICAgICAgZm9ybWF0dGVyOiAobWVzc2FnZXMsIGNvbnRleHQpID0+IHsNCiAgICAgICAgICAgIG1lc3NhZ2VzLnVuc2hpZnQoYFske2NvbnRleHQubmFtZX1dIGApOw0KICAgICAgICB9LA0KICAgIH0pOwoKICAgIHZhciBNZWRpYUZhbWlseTsNCiAgICAoZnVuY3Rpb24gKE1lZGlhRmFtaWx5KSB7DQogICAgICAgIE1lZGlhRmFtaWx5WyJBdWRpbyJdID0gIkFVRElPIjsNCiAgICAgICAgTWVkaWFGYW1pbHlbIlZpZGVvIl0gPSAiVklERU8iOw0KICAgIH0pKE1lZGlhRmFtaWx5IHx8IChNZWRpYUZhbWlseSA9IHt9KSk7DQogICAgdmFyIE1lZGlhQ29udGVudDsNCiAgICAoZnVuY3Rpb24gKE1lZGlhQ29udGVudCkgew0KICAgICAgICBNZWRpYUNvbnRlbnRbIk1haW4iXSA9ICJNQUlOIjsNCiAgICAgICAgTWVkaWFDb250ZW50WyJTbGlkZXMiXSA9ICJTTElERVMiOw0KICAgIH0pKE1lZGlhQ29udGVudCB8fCAoTWVkaWFDb250ZW50ID0ge30pKTsNCiAgICB2YXIgUG9saWN5Ow0KICAgIChmdW5jdGlvbiAoUG9saWN5KSB7DQogICAgICAgIFBvbGljeVsiQWN0aXZlU3BlYWtlciJdID0gImFjdGl2ZS1zcGVha2VyIjsNCiAgICAgICAgUG9saWN5WyJSZWNlaXZlclNlbGVjdGVkIl0gPSAicmVjZWl2ZXItc2VsZWN0ZWQiOw0KICAgIH0pKFBvbGljeSB8fCAoUG9saWN5ID0ge30pKTsNCiAgICB2YXIgTWVkaWFUeXBlOw0KICAgIChmdW5jdGlvbiAoTWVkaWFUeXBlKSB7DQogICAgICAgIE1lZGlhVHlwZVsiVmlkZW9NYWluIl0gPSAiVklERU8tTUFJTiI7DQogICAgICAgIE1lZGlhVHlwZVsiVmlkZW9TbGlkZXMiXSA9ICJWSURFTy1TTElERVMiOw0KICAgICAgICBNZWRpYVR5cGVbIkF1ZGlvTWFpbiJdID0gIkFVRElPLU1BSU4iOw0KICAgICAgICBNZWRpYVR5cGVbIkF1ZGlvU2xpZGVzIl0gPSAiQVVESU8tU0xJREVTIjsNCiAgICB9KShNZWRpYVR5cGUgfHwgKE1lZGlhVHlwZSA9IHt9KSk7CgogICAgdmFyIEptcE1zZ1R5cGU7DQogICAgKGZ1bmN0aW9uIChKbXBNc2dUeXBlKSB7DQogICAgICAgIEptcE1zZ1R5cGVbIk1lZGlhUmVxdWVzdCJdID0gIm1lZGlhUmVxdWVzdCI7DQogICAgICAgIEptcE1zZ1R5cGVbIk1lZGlhUmVxdWVzdEFjayJdID0gIm1lZGlhUmVxdWVzdEFjayI7DQogICAgICAgIEptcE1zZ1R5cGVbIk1lZGlhUmVxdWVzdFN0YXR1cyJdID0gIm1lZGlhUmVxdWVzdFN0YXR1cyI7DQogICAgICAgIEptcE1zZ1R5cGVbIk1lZGlhUmVxdWVzdFN0YXR1c0FjayJdID0gIm1lZGlhUmVxdWVzdFN0YXR1c0FjayI7DQogICAgICAgIEptcE1zZ1R5cGVbIlNvdXJjZUFkdmVydGlzZW1lbnQiXSA9ICJzb3VyY2VBZHZlcnRpc2VtZW50IjsNCiAgICAgICAgSm1wTXNnVHlwZVsiU291cmNlQWR2ZXJ0aXNlbWVudEFjayJdID0gInNvdXJjZUFkdmVydGlzZW1lbnRBY2siOw0KICAgICAgICBKbXBNc2dUeXBlWyJBY3RpdmVTcGVha2VyTm90aWZpY2F0aW9uIl0gPSAiYWN0aXZlU3BlYWtlck5vdGlmaWNhdGlvbiI7DQogICAgfSkoSm1wTXNnVHlwZSB8fCAoSm1wTXNnVHlwZSA9IHt9KSk7DQoKICAgIHZhciBKbXBTZXNzaW9uRXZlbnRzOw0KICAgIChmdW5jdGlvbiAoSm1wU2Vzc2lvbkV2ZW50cykgew0KICAgICAgICBKbXBTZXNzaW9uRXZlbnRzWyJBY3RpdmVTcGVha2VyIl0gPSAiYWN0aXZlLXNwZWFrZXIiOw0KICAgICAgICBKbXBTZXNzaW9uRXZlbnRzWyJNZWRpYVJlcXVlc3RSZWNlaXZlZCJdID0gIm1lZGlhLXJlcXVlc3QtcmVjZWl2ZWQiOw0KICAgICAgICBKbXBTZXNzaW9uRXZlbnRzWyJNZWRpYVJlcXVlc3RTdGF0dXNSZWNlaXZlZCJdID0gIm1lZGlhLXJlcXVlc3Qtc3RhdHVzLXJlY2VpdmVkIjsNCiAgICAgICAgSm1wU2Vzc2lvbkV2ZW50c1siU291cmNlQWR2ZXJ0aXNlbWVudFJlY2VpdmVkIl0gPSAic291cmNlLWFkdmVydGlzZW1lbnQtcmVjZWl2ZWQiOw0KICAgIH0pKEptcFNlc3Npb25FdmVudHMgfHwgKEptcFNlc3Npb25FdmVudHMgPSB7fSkpOwoKICAgIHZhciBFbmNvZGVkVHJhbnNmb3JtVHlwZTsNCiAgICAoZnVuY3Rpb24gKEVuY29kZWRUcmFuc2Zvcm1UeXBlKSB7DQogICAgICAgIEVuY29kZWRUcmFuc2Zvcm1UeXBlWyJBdWRpb0xldmVsTW9uaXRvciJdID0gImF1ZGlvLWxldmVsLW1vbml0b3IiOw0KICAgIH0pKEVuY29kZWRUcmFuc2Zvcm1UeXBlIHx8IChFbmNvZGVkVHJhbnNmb3JtVHlwZSA9IHt9KSk7DQogICAgdmFyIE1haW5Nc2dUeXBlOw0KICAgIChmdW5jdGlvbiAoTWFpbk1zZ1R5cGUpIHsNCiAgICAgICAgTWFpbk1zZ1R5cGVbIkdldE1ldGFkYXRhIl0gPSAiZ2V0LW1ldGFkYXRhIjsNCiAgICAgICAgTWFpbk1zZ1R5cGVbIkNsZWFyTWV0YWRhdGEiXSA9ICJjbGVhci1tZXRhZGF0YSI7DQogICAgfSkoTWFpbk1zZ1R5cGUgfHwgKE1haW5Nc2dUeXBlID0ge30pKTsNCiAgICB2YXIgV29ya2VyTXNnVHlwZTsNCiAgICAoZnVuY3Rpb24gKFdvcmtlck1zZ1R5cGUpIHsNCiAgICAgICAgV29ya2VyTXNnVHlwZVsiUmVzcG9uc2UiXSA9ICJyZXNwb25zZSI7DQogICAgICAgIFdvcmtlck1zZ1R5cGVbIkxvZyJdID0gImxvZyI7DQogICAgfSkoV29ya2VyTXNnVHlwZSB8fCAoV29ya2VyTXNnVHlwZSA9IHt9KSk7CgogICAgY29uc3Qgd29ya2VyTG9nZ2VyID0gew0KICAgICAgICBpbmZvOiAoLi4uYXJncykgPT4gew0KICAgICAgICAgICAgcG9zdE1lc3NhZ2UoeyB0eXBlOiBXb3JrZXJNc2dUeXBlLkxvZywgbGV2ZWw6ICdpbmZvJywgbWVzc2FnZUFyZ3M6IGFyZ3MgfSk7DQogICAgICAgIH0sDQogICAgICAgIHdhcm46ICguLi5hcmdzKSA9PiB7DQogICAgICAgICAgICBwb3N0TWVzc2FnZSh7IHR5cGU6IFdvcmtlck1zZ1R5cGUuTG9nLCBsZXZlbDogJ3dhcm4nLCBtZXNzYWdlQXJnczogYXJncyB9KTsNCiAgICAgICAgfSwNCiAgICAgICAgZXJyb3I6ICguLi5hcmdzKSA9PiB7DQogICAgICAgICAgICBwb3N0TWVzc2FnZSh7IHR5cGU6IFdvcmtlck1zZ1R5cGUuTG9nLCBsZXZlbDogJ2Vycm9yJywgbWVzc2FnZUFyZ3M6IGFyZ3MgfSk7DQogICAgICAgIH0sDQogICAgfTsNCiAgICBjb25zdCBjb2xsZWN0ZWRNZXRhZGF0YSA9IHt9Ow0KICAgIGNvbnN0IGNyZWF0ZUF1ZGlvTGV2ZWxNb25pdG9yVHJhbnNmb3JtID0gKG11bHRpc3RyZWFtQ29ubmVjdGlvbklkLCBlbmNvZGVkVHJhbnNmb3JtSWQpID0+IHsNCiAgICAgICAgaWYgKCEobXVsdGlzdHJlYW1Db25uZWN0aW9uSWQgaW4gY29sbGVjdGVkTWV0YWRhdGEpKSB7DQogICAgICAgICAgICBjb2xsZWN0ZWRNZXRhZGF0YVttdWx0aXN0cmVhbUNvbm5lY3Rpb25JZF0gPSB7DQogICAgICAgICAgICAgICAgW01lZGlhVHlwZS5BdWRpb01haW5dOiB7fSwNCiAgICAgICAgICAgICAgICBbTWVkaWFUeXBlLkF1ZGlvU2xpZGVzXToge30sDQogICAgICAgICAgICAgICAgW01lZGlhVHlwZS5WaWRlb01haW5dOiB7fSwNCiAgICAgICAgICAgICAgICBbTWVkaWFUeXBlLlZpZGVvU2xpZGVzXToge30sDQogICAgICAgICAgICB9Ow0KICAgICAgICB9DQogICAgICAgIGNvbGxlY3RlZE1ldGFkYXRhW211bHRpc3RyZWFtQ29ubmVjdGlvbklkXVtNZWRpYVR5cGUuQXVkaW9NYWluXVtlbmNvZGVkVHJhbnNmb3JtSWRdID0gew0KICAgICAgICAgICAgbWF4QXVkaW9MZXZlbDogdW5kZWZpbmVkLA0KICAgICAgICB9Ow0KICAgICAgICBjb25zdCBjb2xsZWN0ZWRTdHJlYW1NZXRhZGF0YSA9IGNvbGxlY3RlZE1ldGFkYXRhW211bHRpc3RyZWFtQ29ubmVjdGlvbklkXVtNZWRpYVR5cGUuQXVkaW9NYWluXVtlbmNvZGVkVHJhbnNmb3JtSWRdOw0KICAgICAgICB3b3JrZXJMb2dnZXIuaW5mbyhgY3JlYXRpbmcgZW5jb2RlZCB0cmFuc2Zvcm0gZm9yICR7bXVsdGlzdHJlYW1Db25uZWN0aW9uSWR9OiR7ZW5jb2RlZFRyYW5zZm9ybUlkfWApOw0KICAgICAgICByZXR1cm4gbmV3IFRyYW5zZm9ybVN0cmVhbSh7DQogICAgICAgICAgICB0cmFuc2Zvcm06IChlbmNvZGVkRnJhbWUsIGNvbnRyb2xsZXIpID0+IHsNCiAgICAgICAgICAgICAgICBjb25zdCBtZXRhZGF0YSA9IGVuY29kZWRGcmFtZS5nZXRNZXRhZGF0YSgpOw0KICAgICAgICAgICAgICAgIGlmICghY29sbGVjdGVkU3RyZWFtTWV0YWRhdGEubWF4QXVkaW9MZXZlbCB8fA0KICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YS5hdWRpb0xldmVsID4gY29sbGVjdGVkU3RyZWFtTWV0YWRhdGEubWF4QXVkaW9MZXZlbCkgew0KICAgICAgICAgICAgICAgICAgICBjb2xsZWN0ZWRTdHJlYW1NZXRhZGF0YS5tYXhBdWRpb0xldmVsID0gbWV0YWRhdGEuYXVkaW9MZXZlbDsNCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgY29udHJvbGxlci5lbnF1ZXVlKGVuY29kZWRGcmFtZSk7DQogICAgICAgICAgICB9LA0KICAgICAgICB9KTsNCiAgICB9Ow0KICAgIGFkZEV2ZW50TGlzdGVuZXIoJ3J0Y3RyYW5zZm9ybScsIChldmVudCkgPT4gew0KICAgICAgICBsZXQgdHJhbnNmb3JtOw0KICAgICAgICBpZiAoIWV2ZW50LnRyYW5zZm9ybWVyLm9wdGlvbnMgfHwgIWV2ZW50LnRyYW5zZm9ybWVyLm9wdGlvbnMudHlwZSkgew0KICAgICAgICAgICAgd29ya2VyTG9nZ2VyLndhcm4oJ21pc3Npbmcgb3IgaW52YWxpZCB0cmFuc2Zvcm1lciBvcHRpb25zPScsIGV2ZW50LnRyYW5zZm9ybWVyLm9wdGlvbnMpOw0KICAgICAgICAgICAgcmV0dXJuOw0KICAgICAgICB9DQogICAgICAgIGNvbnN0IG9wdGlvbnMgPSBldmVudC50cmFuc2Zvcm1lci5vcHRpb25zOw0KICAgICAgICBjb25zdCB7IGVuY29kZWRUcmFuc2Zvcm1JZCwgbXVsdGlzdHJlYW1Db25uZWN0aW9uSWQsIHR5cGUgfSA9IG9wdGlvbnM7DQogICAgICAgIHN3aXRjaCAodHlwZSkgew0KICAgICAgICAgICAgY2FzZSBFbmNvZGVkVHJhbnNmb3JtVHlwZS5BdWRpb0xldmVsTW9uaXRvcjoNCiAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSBjcmVhdGVBdWRpb0xldmVsTW9uaXRvclRyYW5zZm9ybShtdWx0aXN0cmVhbUNvbm5lY3Rpb25JZCwgZW5jb2RlZFRyYW5zZm9ybUlkKTsNCiAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgIGRlZmF1bHQ6DQogICAgICAgICAgICAgICAgd29ya2VyTG9nZ2VyLndhcm4oJ3VuZXhwZWN0ZWQgdHJhbnNmb3JtZXIgdHlwZT0nLCB0eXBlKTsNCiAgICAgICAgfQ0KICAgICAgICBpZiAodHJhbnNmb3JtKSB7DQogICAgICAgICAgICBldmVudC50cmFuc2Zvcm1lci5yZWFkYWJsZS5waXBlVGhyb3VnaCh0cmFuc2Zvcm0pLnBpcGVUbyhldmVudC50cmFuc2Zvcm1lci53cml0YWJsZSk7DQogICAgICAgIH0NCiAgICB9KTsNCiAgICBhZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgKGV2ZW50KSA9PiB7DQogICAgICAgIHZhciBfYSwgX2I7DQogICAgICAgIGNvbnN0IHsgcmVxdWVzdElkIH0gPSBldmVudC5kYXRhOw0KICAgICAgICBjb25zdCB7IHR5cGUgfSA9IGV2ZW50LmRhdGEucGF5bG9hZDsNCiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YTsNCiAgICAgICAgc3dpdGNoICh0eXBlKSB7DQogICAgICAgICAgICBjYXNlIE1haW5Nc2dUeXBlLkdldE1ldGFkYXRhOiB7DQogICAgICAgICAgICAgICAgY29uc3QgeyBtdWx0aXN0cmVhbUNvbm5lY3Rpb25JZCwgbWVkaWFUeXBlLCBlbmNvZGVkVHJhbnNmb3JtSWQgfSA9IGV2ZW50LmRhdGEucGF5bG9hZDsNCiAgICAgICAgICAgICAgICByZXNwb25zZURhdGEgPSAoX2IgPSAoX2EgPSBjb2xsZWN0ZWRNZXRhZGF0YVttdWx0aXN0cmVhbUNvbm5lY3Rpb25JZF0pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYVttZWRpYVR5cGVdKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2JbZW5jb2RlZFRyYW5zZm9ybUlkXTsNCiAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGNhc2UgTWFpbk1zZ1R5cGUuQ2xlYXJNZXRhZGF0YTogew0KICAgICAgICAgICAgICAgIGNvbnN0IHsgbXVsdGlzdHJlYW1Db25uZWN0aW9uSWQgfSA9IGV2ZW50LmRhdGEucGF5bG9hZDsNCiAgICAgICAgICAgICAgICBkZWxldGUgY29sbGVjdGVkTWV0YWRhdGFbbXVsdGlzdHJlYW1Db25uZWN0aW9uSWRdOw0KICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgZGVmYXVsdDoNCiAgICAgICAgICAgICAgICB3b3JrZXJMb2dnZXIud2FybigndW5leHBlY3RlZCBtZXNzYWdlIHR5cGU9JywgdHlwZSk7DQogICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgIH0NCiAgICAgICAgcG9zdE1lc3NhZ2Uoew0KICAgICAgICAgICAgdHlwZTogV29ya2VyTXNnVHlwZS5SZXNwb25zZSwNCiAgICAgICAgICAgIHJlcXVlc3RJZCwNCiAgICAgICAgICAgIHJlc3BvbnNlRGF0YSwNCiAgICAgICAgfSk7DQogICAgfSk7DQogICAgd29ya2VyTG9nZ2VyLmluZm8oJ1dvcmtlciBmdWxseSBzdGFydGVkLicpOwoKfSkoKTsKCg==', null, false);
15615
+ /* eslint-enable */
15616
+
15617
+ class WorkerManager {
15618
+ constructor() {
15619
+ this.requestsInProgress = new Map();
15620
+ this.lastRequestId = 0;
15621
+ }
15622
+ startWorker() {
15623
+ if (this.worker) {
15624
+ logger.info('Worker is already started');
15625
+ return;
15626
+ }
15627
+ logger.info('Starting worker...');
15628
+ this.worker = new WorkerFactory();
15629
+ this.worker.onmessage = this.messageHandler.bind(this);
15630
+ }
15631
+ stopWorker() {
15632
+ }
15633
+ getWorker() {
15634
+ return this.worker;
15635
+ }
15636
+ messageHandler(event) {
15637
+ const { type } = event.data;
15638
+ switch (type) {
15639
+ case WorkerMsgType.Response: {
15640
+ const { requestId, responseData } = event.data;
15641
+ const request = this.requestsInProgress.get(requestId);
15642
+ if (request) {
15643
+ request.resolve(responseData);
15644
+ this.requestsInProgress.delete(requestId);
15645
+ }
15646
+ else {
15647
+ logger.warn(`received response for unknown requestId: ${requestId}`);
15648
+ }
15649
+ break;
15650
+ }
15651
+ case WorkerMsgType.Log: {
15652
+ const { messageArgs, level } = event.data;
15653
+ switch (level) {
15654
+ case 'info':
15655
+ logger.log(`worker: `, ...messageArgs);
15656
+ break;
15657
+ case 'warn':
15658
+ logger.warn(`worker: `, ...messageArgs);
15659
+ break;
15660
+ case 'error':
15661
+ logger.error(`worker: `, ...messageArgs);
15662
+ break;
15663
+ default:
15664
+ logger.log(`worker (unsupported log level ${level}): `, ...messageArgs);
15665
+ break;
15666
+ }
15667
+ break;
15668
+ }
15669
+ default:
15670
+ logger.warn(`received unknown message type from worker: ${type}`);
15671
+ }
15672
+ }
15673
+ sendRequestToWorker(payload) {
15674
+ return new Promise((resolve, reject) => {
15675
+ if (!this.worker) {
15676
+ reject(new Error('Worker is not started'));
15677
+ return;
15678
+ }
15679
+ const requestId = this.lastRequestId++;
15680
+ this.requestsInProgress.set(requestId, { resolve, reject });
15681
+ this.worker.postMessage({
15682
+ requestId,
15683
+ payload,
15684
+ });
15685
+ });
15686
+ }
15687
+ }
15688
+ WorkerManager.workerManagerInstance = new WorkerManager();
15689
+ function getWorkerManager() {
15690
+ return WorkerManager.workerManagerInstance;
15691
+ }
15692
+
15461
15693
  function toMediaStreamTrackKind(mediaType) {
15462
15694
  return [exports.MediaType.VideoMain, exports.MediaType.VideoSlides].includes(mediaType)
15463
15695
  ? exports.MediaStreamTrackKind.Video
@@ -15500,7 +15732,9 @@ const defaultMultistreamConnectionOptions = {
15500
15732
  disableAudioMainDtx: true,
15501
15733
  preferredStartingBitrateKbps: defaultStartBitrateKbps,
15502
15734
  metricsCallback: () => { },
15735
+ enableInboundAudioLevelMonitoring: false,
15503
15736
  };
15737
+ let staticIdCounter = 0;
15504
15738
  class MultistreamConnection extends EventEmitter$2 {
15505
15739
  constructor(userOptions = {}) {
15506
15740
  super();
@@ -15513,9 +15747,11 @@ class MultistreamConnection extends EventEmitter$2 {
15513
15747
  this.offerAnswerQueue = new AsyncQueue();
15514
15748
  this.currentCreateOfferId = 0;
15515
15749
  this.metadata = { isMediaBypassEdge: false };
15750
+ this.id = `mc-${staticIdCounter++}`;
15516
15751
  this.options = Object.assign(Object.assign({}, defaultMultistreamConnectionOptions), userOptions);
15517
15752
  logger.info(`Creating multistream connection with options ${JSON.stringify(this.options)}`);
15518
15753
  this.metricsCallback = this.options.metricsCallback;
15754
+ this.startWorkerIfNeeded();
15519
15755
  this.initializePeerConnection();
15520
15756
  this.overuseStateManager = new OveruseStateManager((overuseState) => this.overuseUpdateCallback(overuseState));
15521
15757
  this.overuseStateManager.start();
@@ -15529,6 +15765,15 @@ class MultistreamConnection extends EventEmitter$2 {
15529
15765
  this.createSendTransceiver(exports.MediaType.VideoSlides, slidesSceneId, videoSlidesEncodingOptions);
15530
15766
  this.createSendTransceiver(exports.MediaType.AudioSlides, slidesSceneId);
15531
15767
  }
15768
+ startWorkerIfNeeded() {
15769
+ if (this.options.enableInboundAudioLevelMonitoring) {
15770
+ if (WebCapabilities.supportsEncodedStreamTransforms() !== CapabilityState.CAPABLE) {
15771
+ logger.warn('RTCRtpScriptTransform is not supported in this browser, skipping inbound audio level monitoring.');
15772
+ return;
15773
+ }
15774
+ getWorkerManager().startWorker();
15775
+ }
15776
+ }
15532
15777
  initializePeerConnection() {
15533
15778
  this.pc = new PeerConnection({
15534
15779
  iceServers: this.options.iceServers,
@@ -15852,6 +16097,10 @@ SCTP Max Message Size: ${maxMessageSize}`);
15852
16097
  });
15853
16098
  this.jmpSessions.forEach((jmpSession) => jmpSession.close());
15854
16099
  this.pc.close();
16100
+ getWorkerManager().sendRequestToWorker({
16101
+ type: MainMsgType.ClearMetadata,
16102
+ multistreamConnectionId: this.id,
16103
+ });
15855
16104
  }
15856
16105
  sendMediaRequestStatus(mediaType) {
15857
16106
  var _a;
@@ -15923,6 +16172,7 @@ SCTP Max Message Size: ${maxMessageSize}`);
15923
16172
  direction: 'recvonly',
15924
16173
  });
15925
16174
  const mid = this.midPredictor.getNextMid(mediaType);
16175
+ const doAudioLevelMonitoring = this.options.enableInboundAudioLevelMonitoring && mediaType === exports.MediaType.AudioMain;
15926
16176
  const munger = new IngressSdpMunger();
15927
16177
  const recvOnlyTransceiver = new ReceiveOnlyTransceiver({
15928
16178
  rtcRtpTransceiver,
@@ -15930,6 +16180,23 @@ SCTP Max Message Size: ${maxMessageSize}`);
15930
16180
  mediaType,
15931
16181
  munger,
15932
16182
  });
16183
+ if (doAudioLevelMonitoring) {
16184
+ const encodedTransformId = `INBOUND-${mediaType}-${mid}`;
16185
+ try {
16186
+ this.setupEncodedTransform(rtcRtpTransceiver.receiver, encodedTransformId, EncodedTransformType.AudioLevelMonitor);
16187
+ recvOnlyTransceiver.setEncodedStreamMetadataCallback(() => __awaiter(this, void 0, void 0, function* () {
16188
+ return getWorkerManager().sendRequestToWorker({
16189
+ type: MainMsgType.GetMetadata,
16190
+ mediaType,
16191
+ encodedTransformId,
16192
+ multistreamConnectionId: this.id,
16193
+ });
16194
+ }));
16195
+ }
16196
+ catch (e) {
16197
+ logger.warn(`Failed to setup encoded transform for ${encodedTransformId} audio level monitoring: ${e}`);
16198
+ }
16199
+ }
15933
16200
  if (getMediaFamily(mediaType) === exports.MediaFamily.Video) {
15934
16201
  recvOnlyTransceiver.setCodecParameters({
15935
16202
  'sps-pps-idr-in-keyframe': '1',
@@ -16418,6 +16685,21 @@ SCTP Max Message Size: ${maxMessageSize}`);
16418
16685
  videoSlides: this.getCsiByMediaType(exports.MediaType.VideoSlides),
16419
16686
  };
16420
16687
  }
16688
+ setupEncodedTransform(receiverOrSender, id, type) {
16689
+ if (WebCapabilities.supportsEncodedStreamTransforms() !== CapabilityState.CAPABLE) {
16690
+ throw new Error('encoded stream transport is not supported in this browser.');
16691
+ }
16692
+ if (!getWorkerManager().getWorker()) {
16693
+ throw new Error('no worker available for encoded stream transforms.');
16694
+ }
16695
+ const options = {
16696
+ type,
16697
+ encodedTransformId: id,
16698
+ multistreamConnectionId: this.id,
16699
+ };
16700
+ receiverOrSender.transform = new window.RTCRtpScriptTransform(getWorkerManager().getWorker(), options);
16701
+ logger.log(`started "${type}" transform with id=${id} on connection ${this.id}`);
16702
+ }
16421
16703
  }
16422
16704
 
16423
16705
  class StreamRequest {