@webex/web-client-media-engine 3.22.1 → 3.22.3

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/esm/index.js CHANGED
@@ -9411,30 +9411,26 @@ function disableRtcpFbValue(sdpOrAv, rtcpFbValue) {
9411
9411
  function disableTwcc(sdpOrAv) {
9412
9412
  disableRtcpFbValue(sdpOrAv, 'transport-cc');
9413
9413
  }
9414
- function removeCodec(sdpOrAv, codecName) {
9415
- const mediaDescriptions = sdpOrAv instanceof Sdp ? sdpOrAv.avMedia : [sdpOrAv];
9416
- mediaDescriptions.forEach((media) => {
9417
- const codecInfos = [...media.codecs.entries()].filter(([, ci]) => { var _a; return ((_a = ci.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === codecName.toLowerCase(); });
9418
- codecInfos.forEach(([pt]) => media.removePt(pt));
9414
+ function retainCodecs(av, predicate) {
9415
+ let filtered = false;
9416
+ av.codecs.forEach((codecInfo) => {
9417
+ if (!predicate(codecInfo)) {
9418
+ av.removePt(codecInfo.pt);
9419
+ filtered = true;
9420
+ }
9419
9421
  });
9422
+ return filtered;
9420
9423
  }
9421
- function retainCodecs(sdpOrAv, allowedCodecNames) {
9422
- const avMediaDescriptions = sdpOrAv instanceof Sdp ? sdpOrAv.avMedia : [sdpOrAv];
9424
+ function retainCodecsByCodecName(av, allowedCodecNames) {
9423
9425
  const allowedLowerCase = allowedCodecNames.map((s) => s.toLowerCase());
9424
- avMediaDescriptions
9425
- .map((av) => {
9426
- return [...av.codecs.values()].map((c) => c.name);
9427
- })
9428
- .flat()
9429
- .filter((codecName) => !allowedLowerCase.includes(codecName.toLowerCase()))
9430
- .forEach((unwantedCodec) => removeCodec(sdpOrAv, unwantedCodec));
9426
+ return retainCodecs(av, (codecInfo) => !!codecInfo.name && allowedLowerCase.includes(codecInfo.name.toLowerCase()));
9431
9427
  }
9432
- function retainCandidates(sdpOrMedia, allowedTransportTypes) {
9428
+ function retainCandidates(sdpOrMedia, predicate) {
9433
9429
  const mediaDescriptions = sdpOrMedia instanceof Sdp ? sdpOrMedia.media : [sdpOrMedia];
9434
9430
  let filtered = false;
9435
9431
  mediaDescriptions.forEach((media) => {
9436
9432
  media.iceInfo.candidates = media.iceInfo.candidates.filter((candidate) => {
9437
- if (allowedTransportTypes.includes(candidate.transport.toLowerCase())) {
9433
+ if (predicate(candidate)) {
9438
9434
  return true;
9439
9435
  }
9440
9436
  filtered = true;
@@ -9442,6 +9438,10 @@ function retainCandidates(sdpOrMedia, allowedTransportTypes) {
9442
9438
  });
9443
9439
  });
9444
9440
  return filtered;
9441
+ }
9442
+ function retainCandidatesByTransportType(sdpOrMedia, allowedTransportTypes) {
9443
+ const allowedLowerCase = allowedTransportTypes.map((s) => s.toLowerCase());
9444
+ return retainCandidates(sdpOrMedia, (candidate) => allowedLowerCase.includes(candidate.transport.toLowerCase()));
9445
9445
  }
9446
9446
 
9447
9447
  function hasCodec(codecName, mLine) {
@@ -9469,6 +9469,12 @@ var BrowserName;
9469
9469
  BrowserName["EDGE"] = "Microsoft Edge";
9470
9470
  BrowserName["SAFARI"] = "Safari";
9471
9471
  })(BrowserName || (BrowserName = {}));
9472
+ var OSName;
9473
+ (function (OSName) {
9474
+ OSName["WINDOWS"] = "Windows";
9475
+ OSName["MAC"] = "macOS";
9476
+ OSName["LINUX"] = "Linux";
9477
+ })(OSName || (OSName = {}));
9472
9478
  class BrowserInfo {
9473
9479
  static getBrowserDetails() {
9474
9480
  return this.browser.getBrowser();
@@ -9494,6 +9500,15 @@ class BrowserInfo {
9494
9500
  static isSafari() {
9495
9501
  return this.browser.getBrowserName() === BrowserName.SAFARI;
9496
9502
  }
9503
+ static isWindows() {
9504
+ return this.browser.getOSName() === OSName.WINDOWS;
9505
+ }
9506
+ static isMac() {
9507
+ return this.browser.getOSName() === OSName.MAC;
9508
+ }
9509
+ static isLinux() {
9510
+ return this.browser.getOSName() === OSName.LINUX;
9511
+ }
9497
9512
  static isVersionGreaterThan(version) {
9498
9513
  const browserName = this.browser.getBrowserName();
9499
9514
  const checkTree = { [browserName]: `>${version}` };
@@ -9747,16 +9762,33 @@ function generateSsrc() {
9747
9762
  }
9748
9763
 
9749
9764
  class EgressSdpMunger {
9750
- constructor() {
9765
+ constructor(options) {
9751
9766
  this.streamIds = [];
9752
9767
  this.customCodecParameters = new Map();
9768
+ this.egressMungerOptions = options;
9753
9769
  }
9754
9770
  reset() {
9755
9771
  this.streamIds = [];
9756
9772
  }
9757
9773
  mungeLocalDescription(mediaDescription, options) {
9758
9774
  var _a;
9759
- retainCodecs(mediaDescription, ['h264', 'opus', 'rtx']);
9775
+ retainCodecsByCodecName(mediaDescription, ['h264', 'opus', 'rtx']);
9776
+ if (options.forceSoftwareEncoder) {
9777
+ const isH264Cbp = (codecInfo) => {
9778
+ var _a;
9779
+ if (((_a = codecInfo.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'h264') {
9780
+ const profileLevelId = codecInfo.fmtParams.get('profile-level-id');
9781
+ return !!profileLevelId && /^42[^0]/.test(profileLevelId);
9782
+ }
9783
+ return false;
9784
+ };
9785
+ if ([...mediaDescription.codecs.values()].some(isH264Cbp)) {
9786
+ retainCodecs(mediaDescription, (codecInfo) => { var _a; return ((_a = codecInfo.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== 'h264' || isH264Cbp(codecInfo); });
9787
+ }
9788
+ else {
9789
+ logger.log(`No H.264 CBP present in m-line with MID ${mediaDescription.mid}, so all H.264 codecs have been retained.`);
9790
+ }
9791
+ }
9760
9792
  if (mediaDescription.codecs.size === 0) {
9761
9793
  logErrorAndThrow(WcmeErrorType.SDP_MUNGE_MISSING_CODECS, `No codecs present in m-line with MID ${mediaDescription.mid} after filtering.`);
9762
9794
  }
@@ -9838,7 +9870,9 @@ class EgressSdpMunger {
9838
9870
  mungeLocalDescriptionForRemoteServer(mediaDescription, mediaContent, csi) {
9839
9871
  injectContentType(mediaDescription, mediaContent);
9840
9872
  injectJmpAttributes(mediaDescription, csi, 'SSRC');
9841
- injectDummyCandidates(mediaDescription);
9873
+ if (!this.egressMungerOptions.doFullIce) {
9874
+ injectDummyCandidates(mediaDescription);
9875
+ }
9842
9876
  if (mediaDescription.type === 'video') {
9843
9877
  const ssrcGroup = mediaDescription.ssrcGroups.find((sg) => sg.semantics === 'SIM');
9844
9878
  if (ssrcGroup) {
@@ -9849,7 +9883,7 @@ class EgressSdpMunger {
9849
9883
  }
9850
9884
  }
9851
9885
  mungeRemoteDescription(mediaDescription) {
9852
- if (retainCandidates(mediaDescription, ['udp', 'tcp'])) {
9886
+ if (retainCandidatesByTransportType(mediaDescription, ['udp', 'tcp'])) {
9853
9887
  logger.log(`Some unsupported remote candidates have been removed from mid ${mediaDescription.mid}`);
9854
9888
  }
9855
9889
  mediaDescription.bandwidth = undefined;
@@ -10362,7 +10396,7 @@ class IngressSdpMunger {
10362
10396
  return Object.assign({ ssrc: this.ssrc }, (this.rtxSsrc ? { rtxSsrc: this.rtxSsrc } : {}));
10363
10397
  }
10364
10398
  mungeLocalDescription(mediaDescription, options) {
10365
- retainCodecs(mediaDescription, ['h264', 'opus', 'rtx']);
10399
+ retainCodecsByCodecName(mediaDescription, ['h264', 'opus', 'rtx']);
10366
10400
  if (mediaDescription.codecs.size === 0) {
10367
10401
  logErrorAndThrow(WcmeErrorType.SDP_MUNGE_MISSING_CODECS, `No codecs present in m-line with MID ${mediaDescription.mid} after filtering.`);
10368
10402
  }
@@ -10384,7 +10418,7 @@ class IngressSdpMunger {
10384
10418
  mediaDescription.addLine(new SsrcGroupLine('FID', [this.ssrc, this.rtxSsrc]));
10385
10419
  }
10386
10420
  }
10387
- if (retainCandidates(mediaDescription, ['udp', 'tcp'])) {
10421
+ if (retainCandidatesByTransportType(mediaDescription, ['udp', 'tcp'])) {
10388
10422
  logger.log(`Some unsupported remote candidates have been removed from mid ${mediaDescription.mid}`);
10389
10423
  }
10390
10424
  [...mediaDescription.codecs.values()].forEach((ci) => {
@@ -14572,6 +14606,9 @@ class SendOnlyTransceiver extends Transceiver {
14572
14606
  simulcastEnabled: this.isSimulcastEnabled(),
14573
14607
  rtxEnabled: this.rtxEnabled,
14574
14608
  twccDisabled: this.twccDisabled,
14609
+ forceSoftwareEncoder: this.mediaType === MediaType.VideoSlides &&
14610
+ (BrowserInfo.isWindows() || BrowserInfo.isMac()) &&
14611
+ (BrowserInfo.isChrome() || BrowserInfo.isEdge()),
14575
14612
  });
14576
14613
  }
14577
14614
  mungeLocalDescriptionForRemoteServer(mediaDescription) {
@@ -14753,6 +14790,7 @@ const defaultMultistreamConnectionOptions = {
14753
14790
  iceServers: undefined,
14754
14791
  disableContentSimulcast: true,
14755
14792
  disableAudioTwcc: true,
14793
+ doFullIce: BrowserInfo.isFirefox(),
14756
14794
  };
14757
14795
  class MultistreamConnection extends EventEmitter$2 {
14758
14796
  constructor(userOptions = {}) {
@@ -14859,7 +14897,9 @@ class MultistreamConnection extends EventEmitter$2 {
14859
14897
  }
14860
14898
  const mid = this.midPredictor.getNextMid(mediaType);
14861
14899
  const csi = generateCsi(getMediaFamily(mediaType), sceneId);
14862
- const munger = new EgressSdpMunger();
14900
+ const munger = new EgressSdpMunger({
14901
+ doFullIce: this.options.doFullIce,
14902
+ });
14863
14903
  const transceiver = new SendOnlyTransceiver(rtcTransceiver, mid, csi, munger, mediaType);
14864
14904
  if (getMediaFamily(mediaType) === MediaFamily.Video) {
14865
14905
  transceiver.rtxEnabled = true;
@@ -15217,6 +15257,22 @@ SCTP Max Message Size: ${maxMessageSize}`);
15217
15257
  }
15218
15258
  return targetCodec.pt;
15219
15259
  }
15260
+ waitForIceGatheringComplete() {
15261
+ return __awaiter$1(this, void 0, void 0, function* () {
15262
+ return new Promise((resolve) => {
15263
+ if (this.pc.iceGatheringState === 'complete') {
15264
+ resolve();
15265
+ }
15266
+ else {
15267
+ this.pc.on(PeerConnection.Events.IceGatheringStateChange, () => {
15268
+ if (this.pc.iceGatheringState === 'complete') {
15269
+ resolve();
15270
+ }
15271
+ });
15272
+ }
15273
+ });
15274
+ });
15275
+ }
15220
15276
  createOffer() {
15221
15277
  return __awaiter$1(this, void 0, void 0, function* () {
15222
15278
  if (!this.pc.getLocalDescription()) {
@@ -15246,6 +15302,9 @@ SCTP Max Message Size: ${maxMessageSize}`);
15246
15302
  var _a;
15247
15303
  logErrorAndThrow(WcmeErrorType.CREATE_OFFER_FAILED, `Error: ${error}. SDP: ${maskIp((_a = offer.sdp) !== null && _a !== void 0 ? _a : '')}`);
15248
15304
  });
15305
+ if (this.options.doFullIce) {
15306
+ yield this.waitForIceGatheringComplete();
15307
+ }
15249
15308
  const sdpToSend = this.prepareLocalOfferForRemoteServer((_a = this.pc.getLocalDescription()) === null || _a === void 0 ? void 0 : _a.sdp);
15250
15309
  createOfferResolve({ type: 'offer', sdp: sdpToSend });
15251
15310
  if (this.currentCreateOfferId > createOfferId) {
@@ -15350,11 +15409,13 @@ SCTP Max Message Size: ${maxMessageSize}`);
15350
15409
  const sendTransceiver = this.getSendTransceiverByMidOrThrow(av.mid);
15351
15410
  sendTransceiver.mungeLocalDescriptionForRemoteServer(av);
15352
15411
  });
15353
- parsedOffer.media
15354
- .filter((media) => media instanceof ApplicationMediaDescription)
15355
- .forEach((media) => {
15356
- injectDummyCandidates(media);
15357
- });
15412
+ if (!this.options.doFullIce) {
15413
+ parsedOffer.media
15414
+ .filter((media) => media instanceof ApplicationMediaDescription)
15415
+ .forEach((media) => {
15416
+ injectDummyCandidates(media);
15417
+ });
15418
+ }
15358
15419
  if (BrowserInfo.isFirefox()) {
15359
15420
  setupBundle(parsedOffer, this.options.bundlePolicy, this.midPredictor.getMidMap());
15360
15421
  if (this.options.bundlePolicy === 'max-bundle') {
@@ -15388,7 +15449,7 @@ SCTP Max Message Size: ${maxMessageSize}`);
15388
15449
  parsedAnswer.media
15389
15450
  .filter((media) => media instanceof ApplicationMediaDescription)
15390
15451
  .forEach((media) => {
15391
- if (retainCandidates(media, ['udp', 'tcp'])) {
15452
+ if (retainCandidatesByTransportType(media, ['udp', 'tcp'])) {
15392
15453
  logger.log(`Some unsupported remote candidates have been removed from mid ${media.mid}`);
15393
15454
  }
15394
15455
  });