@webex/web-client-media-engine 2.0.3 → 2.0.5

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
@@ -5134,41 +5134,6 @@ class PeerConnection extends EventEmitter$2 {
5134
5134
  }
5135
5135
  PeerConnection.Events = PeerConnectionEvents;
5136
5136
 
5137
- /**
5138
- * Wait until the given peer connection has finished gathering ICE candidates and, when it has,
5139
- * return the local description with the candidates.
5140
- *
5141
- * @param peerConnection - The PeerConnection to use.
5142
- * @returns A Promise that resolves with the local description with the ICE candidates in it.
5143
- */
5144
- function getLocalDescriptionWithIceCandidates(peerConnection) {
5145
- return new Promise((resolve, reject) => {
5146
- /**
5147
- * A helper method to retrieve the local description and resolve, if one is found, or reject
5148
- * with an error if it's not.
5149
- */
5150
- const getLocalDescAndResolve = () => {
5151
- const localDesc = peerConnection.getLocalDescription();
5152
- if (localDesc) {
5153
- resolve(localDesc);
5154
- }
5155
- else {
5156
- reject(new Error('Local description was null'));
5157
- }
5158
- };
5159
- peerConnection.on(PeerConnection.Events.IceGatheringStateChange, (e) => {
5160
- if (e.target.iceGatheringState === 'complete') {
5161
- getLocalDescAndResolve();
5162
- }
5163
- // TODO(brian): throw an error if we see an error iceGatheringState
5164
- });
5165
- // It's possible ICE gathering is already done
5166
- if (peerConnection.iceGatheringState === 'complete') {
5167
- getLocalDescAndResolve();
5168
- }
5169
- });
5170
- }
5171
-
5172
5137
  exports.MediaCodecMimeType = void 0;
5173
5138
  (function (MediaCodecMimeType) {
5174
5139
  MediaCodecMimeType["H264"] = "video/H264";
@@ -9007,6 +8972,59 @@ class ReceiveOnlyTransceiver extends Transceiver {
9007
8972
  }
9008
8973
  ReceiveOnlyTransceiver.rid = '1';
9009
8974
 
8975
+ function deepCopy(source) {
8976
+ return Array.isArray(source)
8977
+ ? source.map((item) => deepCopy(item))
8978
+ : source instanceof Map
8979
+ ? new Map(source)
8980
+ : source instanceof Date
8981
+ ? new Date(source.getTime())
8982
+ : source && typeof source === 'object'
8983
+ ? Object.getOwnPropertyNames(source).reduce((o, prop) => {
8984
+ Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop));
8985
+ o[prop] = deepCopy(source[prop]);
8986
+ return o;
8987
+ }, Object.create(Object.getPrototypeOf(source)))
8988
+ : source;
8989
+ }
8990
+
8991
+ function matchMlinesInAnswer(parsedOffer, parsedAnswer, streamSignalerManager) {
8992
+ parsedAnswer.session.groups = parsedOffer.session.groups;
8993
+ parsedAnswer.media = parsedOffer.media.map((offerMline) => {
8994
+ if (!offerMline.mid) {
8995
+ throw new Error(`Offer mline is missing MID`);
8996
+ }
8997
+ const answerMline = parsedAnswer.media.find((m) => m.mid === offerMline.mid);
8998
+ if (answerMline) {
8999
+ if (answerMline instanceof AvMediaDescription) {
9000
+ [...answerMline.codecs.values()].forEach((ci) => {
9001
+ ci.fmtParams.set('x-google-start-bitrate', '60000');
9002
+ });
9003
+ }
9004
+ return answerMline;
9005
+ }
9006
+ if (!(offerMline instanceof AvMediaDescription)) {
9007
+ throw new Error(`Answer is missing a non-media mline: ${offerMline.mid}`);
9008
+ }
9009
+ const startingMline = parsedAnswer.avMedia.find((m) => m.type === offerMline.type);
9010
+ if (!startingMline) {
9011
+ throw new Error(`Answer has no mline of type ${offerMline.type}, can't generate synthetic answer mline for mid ${offerMline.mid}`);
9012
+ }
9013
+ const fakeCorrespondingMline = deepCopy(startingMline);
9014
+ fakeCorrespondingMline.mid = offerMline.mid;
9015
+ fakeCorrespondingMline.simulcast = undefined;
9016
+ if (offerMline.direction === 'sendrecv' || offerMline.direction === 'sendonly') {
9017
+ fakeCorrespondingMline.direction = 'recvonly';
9018
+ }
9019
+ if (offerMline.direction === 'recvonly') {
9020
+ fakeCorrespondingMline.direction = 'sendonly';
9021
+ const ingressSignaler = streamSignalerManager.getIngressStreamSignalerOrThrow(offerMline.mid);
9022
+ ingressSignaler.signalRemoteStreams(fakeCorrespondingMline);
9023
+ }
9024
+ return fakeCorrespondingMline;
9025
+ });
9026
+ }
9027
+
9010
9028
  class JmpLine extends Line {
9011
9029
  constructor(versions) {
9012
9030
  super();
@@ -9071,22 +9089,6 @@ DefaultSdpGrammar.addParser('a', JmpLine.fromSdpLine);
9071
9089
  DefaultSdpGrammar.addParser('a', JmpSourceLine.fromSdpLine);
9072
9090
  DefaultSdpGrammar.addParser('a', JmpStreamIdModeLine.fromSdpLine);
9073
9091
 
9074
- function deepCopy(source) {
9075
- return Array.isArray(source)
9076
- ? source.map((item) => deepCopy(item))
9077
- : source instanceof Map
9078
- ? new Map(source)
9079
- : source instanceof Date
9080
- ? new Date(source.getTime())
9081
- : source && typeof source === 'object'
9082
- ? Object.getOwnPropertyNames(source).reduce((o, prop) => {
9083
- Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop));
9084
- o[prop] = deepCopy(source[prop]);
9085
- return o;
9086
- }, Object.create(Object.getPrototypeOf(source)))
9087
- : source;
9088
- }
9089
-
9090
9092
  function getMediaTypeForMline(mLine) {
9091
9093
  var _a, _b;
9092
9094
  let mediaFamily;
@@ -9156,42 +9158,6 @@ function filterRecvOnlyMlines(parsedSdp) {
9156
9158
  g.mids = g.mids.filter((m) => filteredMids.includes(m));
9157
9159
  });
9158
9160
  }
9159
- function matchMlinesInAnswer(parsedOffer, parsedAnswer, streamSignalerManager) {
9160
- parsedAnswer.session.groups = parsedOffer.session.groups;
9161
- parsedAnswer.media = parsedOffer.media.map((offerMline) => {
9162
- if (!offerMline.mid) {
9163
- throw new Error(`Offer mline is missing MID`);
9164
- }
9165
- const answerMline = parsedAnswer.media.find((m) => m.mid === offerMline.mid);
9166
- if (answerMline) {
9167
- if (answerMline instanceof AvMediaDescription) {
9168
- [...answerMline.codecs.values()].forEach((ci) => {
9169
- ci.fmtParams.set('x-google-start-bitrate', '60000');
9170
- });
9171
- }
9172
- return answerMline;
9173
- }
9174
- if (!(offerMline instanceof AvMediaDescription)) {
9175
- throw new Error(`Answer is missing a non-media mline: ${offerMline.mid}`);
9176
- }
9177
- const startingMline = parsedAnswer.avMedia.find((m) => m.type === offerMline.type);
9178
- if (!startingMline) {
9179
- throw new Error(`Answer has no mline of type ${offerMline.type}, can't generate synthetic answer mline for mid ${offerMline.mid}`);
9180
- }
9181
- const fakeCorrespondingMline = deepCopy(startingMline);
9182
- fakeCorrespondingMline.mid = offerMline.mid;
9183
- fakeCorrespondingMline.simulcast = undefined;
9184
- if (offerMline.direction === 'sendrecv' || offerMline.direction === 'sendonly') {
9185
- fakeCorrespondingMline.direction = 'recvonly';
9186
- }
9187
- if (offerMline.direction === 'recvonly') {
9188
- fakeCorrespondingMline.direction = 'sendonly';
9189
- const ingressSignaler = streamSignalerManager.getIngressStreamSignalerOrThrow(offerMline.mid);
9190
- ingressSignaler.signalRemoteStreams(fakeCorrespondingMline);
9191
- }
9192
- return fakeCorrespondingMline;
9193
- });
9194
- }
9195
9161
  function injectContentTypes(sdp, contentTypeMap) {
9196
9162
  contentTypeMap.forEach((mediaContent, mid) => {
9197
9163
  const mline = sdp.media.find((m) => m.mid === mid);
@@ -9223,8 +9189,23 @@ function injectJmpAttributes(parsedSdp, csiMap, streamSignalingMode) {
9223
9189
  }
9224
9190
  });
9225
9191
  }
9192
+ function injectDummyCandidates(parsedSdp) {
9193
+ parsedSdp.media.forEach((mLine) => {
9194
+ if (mLine.iceInfo.candidates.length === 0) {
9195
+ mLine.addLine(new CandidateLine('dummy', 1, 'udp', 1, '0.0.0.0', 1, 'host'));
9196
+ }
9197
+ });
9198
+ }
9226
9199
  function hasSimulcast(av) {
9227
9200
  return !!av.simulcast || av.ssrcGroups.map((sg) => sg.semantics).some((sem) => sem === 'SIM');
9201
+ }
9202
+ function addVlaExtension(mLine) {
9203
+ const vlaUri = 'http://www.webrtc.org/experiments/rtp-hdrext/video-layers-allocation00';
9204
+ if (mLine.extMaps.findIndex((extMapLine) => extMapLine.uri === vlaUri) === -1) {
9205
+ const maxIdValue = Math.max(...mLine.extMaps.map((extMapLine) => extMapLine.id), 0);
9206
+ const videoLayersAllocationLine = new ExtMapLine(maxIdValue + 1, vlaUri, undefined);
9207
+ mLine.extMaps.push(videoLayersAllocationLine);
9208
+ }
9228
9209
  }
9229
9210
 
9230
9211
  class SendOnlyTransceiver extends Transceiver {
@@ -9386,6 +9367,7 @@ class RidEgressStreamSignaler {
9386
9367
  if (simulcastEnabled) {
9387
9368
  mLine.rids = this.streamIds.map((streamId, index) => new RidLine(streamId.rid, 'send', `max-fs=${simulcastMaxFrameSizes[index]}`));
9388
9369
  mLine.simulcast = new SimulcastLine(SimulcastLayerList.fromString('low;medium;high'), new SimulcastLayerList());
9370
+ addVlaExtension(mLine);
9389
9371
  }
9390
9372
  }
9391
9373
  getSenderIds() {
@@ -9492,6 +9474,7 @@ class SsrcEgressStreamSignaler {
9492
9474
  });
9493
9475
  if (simulcastEnabled) {
9494
9476
  mLine.addLine(new SsrcGroupLine('SIM', this.streamIds.map((streamId) => streamId.ssrc)));
9477
+ addVlaExtension(mLine);
9495
9478
  }
9496
9479
  }
9497
9480
  getSenderIds() {
@@ -13233,7 +13216,7 @@ class MultistreamConnection extends EventEmitter {
13233
13216
  (_a = this.pc) === null || _a === void 0 ? void 0 : _a.close();
13234
13217
  this.pc = new PeerConnection({
13235
13218
  iceServers: this.options.iceServers,
13236
- bundlePolicy: getBrowserDetails().name === 'Firefox' ? 'max-compat' : this.options.bundlePolicy,
13219
+ bundlePolicy: this.options.bundlePolicy,
13237
13220
  });
13238
13221
  this.pc.on(PeerConnection.Events.ConnectionStateChange, (state) => this.emit(exports.MultistreamConnectionEventNames.ConnectionStateUpdate, state));
13239
13222
  this.attachMetricsObserver();
@@ -13617,6 +13600,7 @@ class MultistreamConnection extends EventEmitter {
13617
13600
  }
13618
13601
  return new Promise((createOfferResolve) => {
13619
13602
  this.offerAnswerQueue.push(() => __awaiter(this, void 0, void 0, function* () {
13603
+ var _a;
13620
13604
  if (this.setAnswerResolve !== undefined) {
13621
13605
  throw new Error(`Tried to start a new createOffer flow before the old one had finished`);
13622
13606
  }
@@ -13629,12 +13613,8 @@ class MultistreamConnection extends EventEmitter {
13629
13613
  }
13630
13614
  offer.sdp = this.preProcessLocalOffer(offer.sdp);
13631
13615
  yield this.pc.setLocalDescription(offer);
13632
- const offerWithCandidates = yield getLocalDescriptionWithIceCandidates(this.pc);
13633
- const sdpToSend = this.prepareLocalOfferForRemoteServer(offerWithCandidates.sdp);
13634
- createOfferResolve({
13635
- sdp: sdpToSend,
13636
- type: offerWithCandidates.type,
13637
- });
13616
+ const sdpToSend = this.prepareLocalOfferForRemoteServer((_a = this.pc.getLocalDescription()) === null || _a === void 0 ? void 0 : _a.sdp);
13617
+ createOfferResolve({ type: 'offer', sdp: sdpToSend });
13638
13618
  yield setAnswerPromise;
13639
13619
  }));
13640
13620
  });
@@ -13743,6 +13723,7 @@ class MultistreamConnection extends EventEmitter {
13743
13723
  });
13744
13724
  injectJmpAttributes(parsed, csiMap, this.options.streamSignalingMode);
13745
13725
  filterRecvOnlyMlines(parsed);
13726
+ injectDummyCandidates(parsed);
13746
13727
  parsed.avMedia
13747
13728
  .filter((av) => av.direction === 'sendrecv' && av.type === 'video')
13748
13729
  .forEach((av) => {
@@ -13755,6 +13736,13 @@ class MultistreamConnection extends EventEmitter {
13755
13736
  });
13756
13737
  if (getBrowserDetails().name === 'Firefox') {
13757
13738
  setupBundle(parsed, this.options.bundlePolicy, this.midMap);
13739
+ if (this.options.bundlePolicy === 'max-bundle') {
13740
+ parsed.media.forEach((mline, index) => {
13741
+ if (index > 0) {
13742
+ mline.port = parsed.media[0].port;
13743
+ }
13744
+ });
13745
+ }
13758
13746
  }
13759
13747
  return parsed.toString();
13760
13748
  }
@@ -13765,6 +13753,15 @@ class MultistreamConnection extends EventEmitter {
13765
13753
  matchMlinesInAnswer(parsedOffer, parsedAnswer, this.streamSignalerManager);
13766
13754
  if (getBrowserDetails().name === 'Firefox') {
13767
13755
  setupBundle(parsedAnswer, this.options.bundlePolicy, this.midMap);
13756
+ if (this.options.bundlePolicy === 'max-bundle') {
13757
+ const { ufrag, pwd } = parsedAnswer.media[0].iceInfo;
13758
+ parsedAnswer.media.forEach((mline, index) => {
13759
+ if (index > 0) {
13760
+ mline.iceInfo.ufrag = ufrag;
13761
+ mline.iceInfo.pwd = pwd;
13762
+ }
13763
+ });
13764
+ }
13768
13765
  }
13769
13766
  return parsedAnswer.toString();
13770
13767
  }