livekit-client 2.12.0 → 2.13.1

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.
Files changed (41) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +1 -0
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +145 -56
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  10. package/dist/src/room/Room.d.ts +2 -1
  11. package/dist/src/room/Room.d.ts.map +1 -1
  12. package/dist/src/room/errors.d.ts +2 -1
  13. package/dist/src/room/errors.d.ts.map +1 -1
  14. package/dist/src/room/events.d.ts +11 -1
  15. package/dist/src/room/events.d.ts.map +1 -1
  16. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  17. package/dist/src/room/participant/Participant.d.ts +14 -1
  18. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  19. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  20. package/dist/src/room/track/LocalVideoTrack.d.ts +1 -1
  21. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  22. package/dist/src/room/track/create.d.ts.map +1 -1
  23. package/dist/src/room/utils.d.ts +3 -0
  24. package/dist/src/room/utils.d.ts.map +1 -1
  25. package/dist/ts4.2/src/room/Room.d.ts +2 -1
  26. package/dist/ts4.2/src/room/errors.d.ts +2 -1
  27. package/dist/ts4.2/src/room/events.d.ts +11 -1
  28. package/dist/ts4.2/src/room/participant/Participant.d.ts +14 -1
  29. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +1 -1
  30. package/dist/ts4.2/src/room/utils.d.ts +3 -0
  31. package/package.json +11 -11
  32. package/src/room/RTCEngine.ts +6 -4
  33. package/src/room/Room.ts +14 -6
  34. package/src/room/errors.ts +1 -0
  35. package/src/room/events.ts +12 -0
  36. package/src/room/participant/LocalParticipant.ts +37 -18
  37. package/src/room/participant/Participant.ts +48 -3
  38. package/src/room/participant/publishUtils.ts +4 -0
  39. package/src/room/track/LocalVideoTrack.ts +14 -5
  40. package/src/room/track/create.ts +3 -5
  41. package/src/room/utils.ts +14 -1
@@ -7182,7 +7182,7 @@ let deprecationWarnings_ = true;
7182
7182
  */
7183
7183
  function extractVersion(uastring, expr, pos) {
7184
7184
  const match = uastring.match(expr);
7185
- return match && match.length >= pos && parseInt(match[pos], 10);
7185
+ return match && match.length >= pos && parseFloat(match[pos], 10);
7186
7186
  }
7187
7187
 
7188
7188
  // Wraps the peerconnection event eventNameToWrap in a function
@@ -7327,19 +7327,21 @@ function detectBrowser(window) {
7327
7327
  if (navigator.mozGetUserMedia) {
7328
7328
  // Firefox.
7329
7329
  result.browser = 'firefox';
7330
- result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1);
7330
+ result.version = parseInt(extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1));
7331
7331
  } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection) {
7332
7332
  // Chrome, Chromium, Webview, Opera.
7333
7333
  // Version matches Chrome/WebRTC version.
7334
7334
  // Chrome 74 removed webkitGetUserMedia on http as well so we need the
7335
7335
  // more complicated fallback to webkitRTCPeerConnection.
7336
7336
  result.browser = 'chrome';
7337
- result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2);
7337
+ result.version = parseInt(extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2));
7338
7338
  } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) {
7339
7339
  // Safari.
7340
7340
  result.browser = 'safari';
7341
- result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1);
7341
+ result.version = parseInt(extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1));
7342
7342
  result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype;
7343
+ // Only for internal usage.
7344
+ result._safariVersion = extractVersion(navigator.userAgent, /Version\/(\d+(\.?\d+))/, 1);
7343
7345
  } else {
7344
7346
  // Default fallthrough: not supported.
7345
7347
  result.browser = 'Not a supported browser.';
@@ -9940,7 +9942,7 @@ function removeExtmapAllowMixed(window, browserDetails) {
9940
9942
  if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) {
9941
9943
  return;
9942
9944
  }
9943
- if (browserDetails.browser === 'safari' && browserDetails.version >= 605) {
9945
+ if (browserDetails.browser === 'safari' && browserDetails._safariVersion >= 13.1) {
9944
9946
  return;
9945
9947
  }
9946
9948
  const nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription;
@@ -10477,6 +10479,7 @@ var ConnectionErrorReason;
10477
10479
  ConnectionErrorReason[ConnectionErrorReason["InternalError"] = 2] = "InternalError";
10478
10480
  ConnectionErrorReason[ConnectionErrorReason["Cancelled"] = 3] = "Cancelled";
10479
10481
  ConnectionErrorReason[ConnectionErrorReason["LeaveRequest"] = 4] = "LeaveRequest";
10482
+ ConnectionErrorReason[ConnectionErrorReason["Timeout"] = 5] = "Timeout";
10480
10483
  })(ConnectionErrorReason || (ConnectionErrorReason = {}));
10481
10484
  class ConnectionError extends LivekitError {
10482
10485
  constructor(message, reason, status, context) {
@@ -10763,6 +10766,12 @@ var RoomEvent;
10763
10766
  * args: (changedAttributes: [[Record<string, string]], participant: [[Participant]])
10764
10767
  */
10765
10768
  RoomEvent["ParticipantAttributesChanged"] = "participantAttributesChanged";
10769
+ /**
10770
+ * Emitted when the participant's state changes to ACTIVE and is ready to send/receive data messages
10771
+ *
10772
+ * args: (participant: [[Participant]])
10773
+ */
10774
+ RoomEvent["ParticipantActive"] = "participantActive";
10766
10775
  /**
10767
10776
  * Room metadata is a simple way for app-specific state to be pushed to
10768
10777
  * all users.
@@ -11057,6 +11066,10 @@ var ParticipantEvent;
11057
11066
  ParticipantEvent["LocalTrackSubscribed"] = "localTrackSubscribed";
11058
11067
  /** only emitted on local participant */
11059
11068
  ParticipantEvent["ChatMessage"] = "chatMessage";
11069
+ /**
11070
+ * Emitted when the participant's state changes to ACTIVE and is ready to send/receive data messages
11071
+ */
11072
+ ParticipantEvent["Active"] = "active";
11060
11073
  })(ParticipantEvent || (ParticipantEvent = {}));
11061
11074
  /** @internal */
11062
11075
  var EngineEvent;
@@ -11249,7 +11262,7 @@ function getOSVersion(ua) {
11249
11262
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
11250
11263
  }
11251
11264
 
11252
- var version$1 = "2.12.0";
11265
+ var version$1 = "2.13.1";
11253
11266
 
11254
11267
  const version = version$1;
11255
11268
  const protocolVersion = 16;
@@ -11859,10 +11872,21 @@ function isSafari() {
11859
11872
  var _a;
11860
11873
  return ((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.name) === 'Safari';
11861
11874
  }
11875
+ function isSafariBased() {
11876
+ const b = getBrowser();
11877
+ return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' || (b === null || b === void 0 ? void 0 : b.os) === 'iOS';
11878
+ }
11862
11879
  function isSafari17() {
11863
11880
  const b = getBrowser();
11864
11881
  return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' && b.version.startsWith('17.');
11865
11882
  }
11883
+ function isSafariSvcApi(browser) {
11884
+ if (!browser) {
11885
+ browser = getBrowser();
11886
+ }
11887
+ // Safari 18.4 requires legacy svc api and scaleResolutionDown to be set
11888
+ return (browser === null || browser === void 0 ? void 0 : browser.name) === 'Safari' && compareVersions(browser.version, '18.3') > 0;
11889
+ }
11866
11890
  function isMobile() {
11867
11891
  var _a, _b;
11868
11892
  if (!isWeb()) return false;
@@ -16339,12 +16363,15 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
16339
16363
  // TODO: when we upstream libwebrtc, this will need additional verification
16340
16364
  isReactNative() || (browser === null || browser === void 0 ? void 0 : browser.name) === 'Chrome' && compareVersions(browser === null || browser === void 0 ? void 0 : browser.version, '113') < 0) {
16341
16365
  const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
16366
+ // safari 18.4 uses a different svc API that requires scaleResolutionDownBy to be set.
16367
+ const requireScale = isSafariSvcApi(browser);
16342
16368
  for (let i = 0; i < sm.spatial; i += 1) {
16343
16369
  // in legacy SVC, scaleResolutionDownBy cannot be set
16344
16370
  encodings.push({
16345
16371
  rid: videoRids[2 - i],
16346
16372
  maxBitrate: videoEncoding.maxBitrate / Math.pow(bitratesRatio, i),
16347
- maxFramerate: original.encoding.maxFramerate
16373
+ maxFramerate: original.encoding.maxFramerate,
16374
+ scaleResolutionDownBy: requireScale ? Math.pow(2, i) : undefined
16348
16375
  });
16349
16376
  }
16350
16377
  // legacy SVC, scalabilityMode is set only on the first encoding
@@ -16851,7 +16878,7 @@ class LocalVideoTrack extends LocalTrack {
16851
16878
  }));
16852
16879
  }
16853
16880
  this.log.debug("setting publishing quality. max quality ".concat(maxQuality), this.logContext);
16854
- this.setPublishingLayers(qualities);
16881
+ this.setPublishingLayers(isSVCCodec(this.codec), qualities);
16855
16882
  }
16856
16883
  restartTrack(options) {
16857
16884
  return __awaiter(this, void 0, void 0, function* () {
@@ -16986,7 +17013,7 @@ class LocalVideoTrack extends LocalTrack {
16986
17013
  }));
16987
17014
  // only enable simulcast codec for preference codec setted
16988
17015
  if (!this.codec && codecs.length > 0) {
16989
- yield this.setPublishingLayers(codecs[0].qualities);
17016
+ yield this.setPublishingLayers(isSVCCodec(codecs[0].codec), codecs[0].qualities);
16990
17017
  return [];
16991
17018
  }
16992
17019
  this.subscribedCodecs = codecs;
@@ -16997,7 +17024,7 @@ class LocalVideoTrack extends LocalTrack {
16997
17024
  _a = false;
16998
17025
  const codec = _d;
16999
17026
  if (!this.codec || this.codec === codec.codec) {
17000
- yield this.setPublishingLayers(codec.qualities);
17027
+ yield this.setPublishingLayers(isSVCCodec(codec.codec), codec.qualities);
17001
17028
  } else {
17002
17029
  const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec);
17003
17030
  this.log.debug("try setPublishingCodec for ".concat(codec.codec), Object.assign(Object.assign({}, this.logContext), {
@@ -17012,7 +17039,7 @@ class LocalVideoTrack extends LocalTrack {
17012
17039
  }
17013
17040
  } else if (simulcastCodecInfo.encodings) {
17014
17041
  this.log.debug("try setPublishingLayersForSender ".concat(codec.codec), this.logContext);
17015
- yield setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock, this.log, this.logContext);
17042
+ yield setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock, isSVCCodec(codec.codec), this.log, this.logContext);
17016
17043
  }
17017
17044
  }
17018
17045
  }
@@ -17034,7 +17061,7 @@ class LocalVideoTrack extends LocalTrack {
17034
17061
  * @internal
17035
17062
  * Sets layers that should be publishing
17036
17063
  */
17037
- setPublishingLayers(qualities) {
17064
+ setPublishingLayers(isSvc, qualities) {
17038
17065
  return __awaiter(this, void 0, void 0, function* () {
17039
17066
  this.log.debug('setting publishing layers', Object.assign(Object.assign({}, this.logContext), {
17040
17067
  qualities
@@ -17042,7 +17069,7 @@ class LocalVideoTrack extends LocalTrack {
17042
17069
  if (!this.sender || !this.encodings) {
17043
17070
  return;
17044
17071
  }
17045
- yield setPublishingLayersForSender(this.sender, this.encodings, qualities, this.senderLock, this.log, this.logContext);
17072
+ yield setPublishingLayersForSender(this.sender, this.encodings, qualities, this.senderLock, isSvc, this.log, this.logContext);
17046
17073
  });
17047
17074
  }
17048
17075
  handleAppVisibilityChanged() {
@@ -17060,7 +17087,7 @@ class LocalVideoTrack extends LocalTrack {
17060
17087
  });
17061
17088
  }
17062
17089
  }
17063
- function setPublishingLayersForSender(sender, senderEncodings, qualities, senderLock, log, logContext) {
17090
+ function setPublishingLayersForSender(sender, senderEncodings, qualities, senderLock, isSVC, log, logContext) {
17064
17091
  return __awaiter(this, void 0, void 0, function* () {
17065
17092
  const unlock = yield senderLock.lock();
17066
17093
  log.debug('setPublishingLayersForSender', Object.assign(Object.assign({}, logContext), {
@@ -17122,6 +17149,12 @@ function setPublishingLayersForSender(sender, senderEncodings, qualities, sender
17122
17149
  }
17123
17150
  }
17124
17151
  } else {
17152
+ if (isSVC) {
17153
+ const hasEnabledEncoding = qualities.some(q => q.enabled);
17154
+ if (hasEnabledEncoding) {
17155
+ qualities.forEach(q => q.enabled = true);
17156
+ }
17157
+ }
17125
17158
  // simulcast dynacast encodings
17126
17159
  encodings.forEach((encoding, idx) => {
17127
17160
  var _a;
@@ -17435,12 +17468,12 @@ class RTCEngine extends eventsExports.EventEmitter {
17435
17468
  }
17436
17469
  /** @internal */
17437
17470
  get logContext() {
17438
- var _a, _b, _c, _d, _e, _f, _g, _h;
17471
+ var _a, _b, _c, _d, _e, _f;
17439
17472
  return {
17440
17473
  room: (_b = (_a = this.latestJoinResponse) === null || _a === void 0 ? void 0 : _a.room) === null || _b === void 0 ? void 0 : _b.name,
17441
17474
  roomID: (_d = (_c = this.latestJoinResponse) === null || _c === void 0 ? void 0 : _c.room) === null || _d === void 0 ? void 0 : _d.sid,
17442
17475
  participant: (_f = (_e = this.latestJoinResponse) === null || _e === void 0 ? void 0 : _e.participant) === null || _f === void 0 ? void 0 : _f.identity,
17443
- pID: (_h = (_g = this.latestJoinResponse) === null || _g === void 0 ? void 0 : _g.participant) === null || _h === void 0 ? void 0 : _h.sid
17476
+ pID: this.participantSid
17444
17477
  };
17445
17478
  }
17446
17479
  join(url, token, opts, abortSignal) {
@@ -17541,7 +17574,7 @@ class RTCEngine extends eventsExports.EventEmitter {
17541
17574
  return new Promise((resolve, reject) => {
17542
17575
  const publicationTimeout = setTimeout(() => {
17543
17576
  delete this.pendingTrackResolvers[req.cid];
17544
- reject(new ConnectionError('publication of local track timed out, no response from server', ConnectionErrorReason.InternalError));
17577
+ reject(new ConnectionError('publication of local track timed out, no response from server', ConnectionErrorReason.Timeout));
17545
17578
  }, 10000);
17546
17579
  this.pendingTrackResolvers[req.cid] = {
17547
17580
  resolve: info => {
@@ -17717,6 +17750,9 @@ class RTCEngine extends eventsExports.EventEmitter {
17717
17750
  this.client.onRoomMoved = res => {
17718
17751
  var _a;
17719
17752
  this.participantSid = (_a = res.participant) === null || _a === void 0 ? void 0 : _a.sid;
17753
+ if (this.latestJoinResponse) {
17754
+ this.latestJoinResponse.room = res.room;
17755
+ }
17720
17756
  this.emit(EngineEvent.RoomMoved, res);
17721
17757
  };
17722
17758
  this.client.onClose = () => {
@@ -17794,8 +17830,7 @@ class RTCEngine extends eventsExports.EventEmitter {
17794
17830
  }
17795
17831
  // create data channels
17796
17832
  this.lossyDC = this.pcManager.createPublisherDataChannel(lossyDataChannel, {
17797
- // will drop older packets that arrive
17798
- ordered: true,
17833
+ ordered: false,
17799
17834
  maxRetransmits: 0
17800
17835
  });
17801
17836
  this.reliableDC = this.pcManager.createPublisherDataChannel(reliableDataChannel, {
@@ -19576,16 +19611,17 @@ function createLocalTracks(options, loggerOptions) {
19576
19611
  }
19577
19612
  });
19578
19613
  }
19579
- // TODO if internal options don't have device Id specified, set it to 'default'
19580
19614
  if (internalOptions.audio === true || typeof internalOptions.audio === 'object' && !internalOptions.audio.deviceId) {
19581
19615
  internalOptions.audio = {
19582
19616
  deviceId: 'default'
19583
19617
  };
19584
19618
  }
19585
- if (internalOptions.video === true || typeof internalOptions.video === 'object' && !internalOptions.video.deviceId) {
19619
+ if (internalOptions.video === true) {
19586
19620
  internalOptions.video = {
19587
19621
  deviceId: 'default'
19588
19622
  };
19623
+ } else if (typeof internalOptions.video === 'object' && !internalOptions.video.deviceId) {
19624
+ internalOptions.video.deviceId = 'default';
19589
19625
  }
19590
19626
  const opts = mergeDefaultOptions(internalOptions, audioDefaults, videoDefaults);
19591
19627
  const constraints = constraintsForOptions(opts);
@@ -19742,6 +19778,10 @@ class Participant extends eventsExports.EventEmitter {
19742
19778
  var _a;
19743
19779
  return ((_a = this.permissions) === null || _a === void 0 ? void 0 : _a.agent) || this.kind === ParticipantInfo_Kind.AGENT;
19744
19780
  }
19781
+ get isActive() {
19782
+ var _a;
19783
+ return ((_a = this.participantInfo) === null || _a === void 0 ? void 0 : _a.state) === ParticipantInfo_State.ACTIVE;
19784
+ }
19745
19785
  get kind() {
19746
19786
  return this._kind;
19747
19787
  }
@@ -19797,6 +19837,25 @@ class Participant extends eventsExports.EventEmitter {
19797
19837
  }
19798
19838
  }
19799
19839
  }
19840
+ /**
19841
+ * Waits until the participant is active and ready to receive data messages
19842
+ * @returns a promise that resolves when the participant is active
19843
+ */
19844
+ waitUntilActive() {
19845
+ if (this.isActive) {
19846
+ return Promise.resolve();
19847
+ }
19848
+ if (this.activeFuture) {
19849
+ return this.activeFuture.promise;
19850
+ }
19851
+ this.activeFuture = new Future();
19852
+ this.once(ParticipantEvent.Active, () => {
19853
+ var _a, _b;
19854
+ (_b = (_a = this.activeFuture) === null || _a === void 0 ? void 0 : _a.resolve) === null || _b === void 0 ? void 0 : _b.call(_a);
19855
+ this.activeFuture = undefined;
19856
+ });
19857
+ return this.activeFuture.promise;
19858
+ }
19800
19859
  get connectionQuality() {
19801
19860
  return this._connectionQuality;
19802
19861
  }
@@ -19826,6 +19885,7 @@ class Participant extends eventsExports.EventEmitter {
19826
19885
  }
19827
19886
  /** @internal */
19828
19887
  updateInfo(info) {
19888
+ var _a;
19829
19889
  // it's possible the update could be applied out of order due to await
19830
19890
  // during reconnect sequences. when that happens, it's possible for server
19831
19891
  // to have sent more recent version of participant info while JS is waiting
@@ -19840,14 +19900,14 @@ class Participant extends eventsExports.EventEmitter {
19840
19900
  this._setName(info.name);
19841
19901
  this._setMetadata(info.metadata);
19842
19902
  this._setAttributes(info.attributes);
19903
+ if (info.state === ParticipantInfo_State.ACTIVE && ((_a = this.participantInfo) === null || _a === void 0 ? void 0 : _a.state) !== ParticipantInfo_State.ACTIVE) {
19904
+ this.emit(ParticipantEvent.Active);
19905
+ }
19843
19906
  if (info.permission) {
19844
19907
  this.setPermissions(info.permission);
19845
19908
  }
19846
19909
  // set this last so setMetadata can detect changes
19847
19910
  this.participantInfo = info;
19848
- this.log.trace('update participant info', Object.assign(Object.assign({}, this.logContext), {
19849
- info
19850
- }));
19851
19911
  return true;
19852
19912
  }
19853
19913
  /**
@@ -19911,6 +19971,16 @@ class Participant extends eventsExports.EventEmitter {
19911
19971
  this.emit(ParticipantEvent.ConnectionQualityChanged, this._connectionQuality);
19912
19972
  }
19913
19973
  }
19974
+ /**
19975
+ * @internal
19976
+ */
19977
+ setDisconnected() {
19978
+ var _a, _b;
19979
+ if (this.activeFuture) {
19980
+ (_b = (_a = this.activeFuture).reject) === null || _b === void 0 ? void 0 : _b.call(_a, new Error('Participant disconnected'));
19981
+ this.activeFuture = undefined;
19982
+ }
19983
+ }
19914
19984
  /**
19915
19985
  * @internal
19916
19986
  */
@@ -20064,7 +20134,7 @@ class LocalParticipant extends Participant {
20064
20134
  };
20065
20135
  this.handleSubscribedQualityUpdate = update => __awaiter(this, void 0, void 0, function* () {
20066
20136
  var _a, e_1, _b, _c;
20067
- var _d, _e;
20137
+ var _d;
20068
20138
  if (!((_d = this.roomOptions) === null || _d === void 0 ? void 0 : _d.dynacast)) {
20069
20139
  return;
20070
20140
  }
@@ -20075,34 +20145,30 @@ class LocalParticipant extends Participant {
20075
20145
  }));
20076
20146
  return;
20077
20147
  }
20078
- if (update.subscribedCodecs.length > 0) {
20079
- if (!pub.videoTrack) {
20080
- return;
20148
+ if (!pub.videoTrack) {
20149
+ return;
20150
+ }
20151
+ const newCodecs = yield pub.videoTrack.setPublishingCodecs(update.subscribedCodecs);
20152
+ try {
20153
+ for (var _e = true, newCodecs_1 = __asyncValues(newCodecs), newCodecs_1_1; newCodecs_1_1 = yield newCodecs_1.next(), _a = newCodecs_1_1.done, !_a; _e = true) {
20154
+ _c = newCodecs_1_1.value;
20155
+ _e = false;
20156
+ const codec = _c;
20157
+ if (isBackupCodec(codec)) {
20158
+ this.log.debug("publish ".concat(codec, " for ").concat(pub.videoTrack.sid), Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(pub)));
20159
+ yield this.publishAdditionalCodecForTrack(pub.videoTrack, codec, pub.options);
20160
+ }
20081
20161
  }
20082
- const newCodecs = yield pub.videoTrack.setPublishingCodecs(update.subscribedCodecs);
20162
+ } catch (e_1_1) {
20163
+ e_1 = {
20164
+ error: e_1_1
20165
+ };
20166
+ } finally {
20083
20167
  try {
20084
- for (var _f = true, newCodecs_1 = __asyncValues(newCodecs), newCodecs_1_1; newCodecs_1_1 = yield newCodecs_1.next(), _a = newCodecs_1_1.done, !_a; _f = true) {
20085
- _c = newCodecs_1_1.value;
20086
- _f = false;
20087
- const codec = _c;
20088
- if (isBackupCodec(codec)) {
20089
- this.log.debug("publish ".concat(codec, " for ").concat(pub.videoTrack.sid), Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(pub)));
20090
- yield this.publishAdditionalCodecForTrack(pub.videoTrack, codec, pub.options);
20091
- }
20092
- }
20093
- } catch (e_1_1) {
20094
- e_1 = {
20095
- error: e_1_1
20096
- };
20168
+ if (!_e && !_a && (_b = newCodecs_1.return)) yield _b.call(newCodecs_1);
20097
20169
  } finally {
20098
- try {
20099
- if (!_f && !_a && (_b = newCodecs_1.return)) yield _b.call(newCodecs_1);
20100
- } finally {
20101
- if (e_1) throw e_1.error;
20102
- }
20170
+ if (e_1) throw e_1.error;
20103
20171
  }
20104
- } else if (update.subscribedQualities.length > 0) {
20105
- yield (_e = pub.videoTrack) === null || _e === void 0 ? void 0 : _e.setPublishingLayers(update.subscribedQualities);
20106
20172
  }
20107
20173
  });
20108
20174
  this.handleLocalTrackUnpublished = unpublished => {
@@ -20389,7 +20455,7 @@ class LocalParticipant extends Participant {
20389
20455
  tr.stop();
20390
20456
  });
20391
20457
  if (e instanceof Error) {
20392
- this.emit(ParticipantEvent.MediaDevicesError, e);
20458
+ this.emit(ParticipantEvent.MediaDevicesError, e, sourceToKind(source));
20393
20459
  }
20394
20460
  this.pendingPublishing.delete(source);
20395
20461
  throw e;
@@ -20905,11 +20971,28 @@ class LocalParticipant extends Participant {
20905
20971
  yield this.engine.negotiate();
20906
20972
  });
20907
20973
  let ti;
20974
+ const addTrackPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
20975
+ var _a;
20976
+ try {
20977
+ ti = yield this.engine.addTrack(req);
20978
+ resolve(ti);
20979
+ } catch (err) {
20980
+ if (track.sender && ((_a = this.engine.pcManager) === null || _a === void 0 ? void 0 : _a.publisher)) {
20981
+ this.engine.pcManager.publisher.removeTrack(track.sender);
20982
+ yield this.engine.negotiate().catch(negotiateErr => {
20983
+ this.log.error('failed to negotiate after removing track due to failed add track request', Object.assign(Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)), {
20984
+ error: negotiateErr
20985
+ }));
20986
+ });
20987
+ }
20988
+ reject(err);
20989
+ }
20990
+ }));
20908
20991
  if (this.enabledPublishVideoCodecs.length > 0) {
20909
- const rets = yield Promise.all([this.engine.addTrack(req), negotiate()]);
20992
+ const rets = yield Promise.all([addTrackPromise, negotiate()]);
20910
20993
  ti = rets[0];
20911
20994
  } else {
20912
- ti = yield this.engine.addTrack(req);
20995
+ ti = yield addTrackPromise;
20913
20996
  // server might not support the codec the client has requested, in that case, fallback
20914
20997
  // to a supported codec
20915
20998
  let primaryCodecMime;
@@ -21437,6 +21520,7 @@ class LocalParticipant extends Participant {
21437
21520
  streamId,
21438
21521
  topic: info.topic,
21439
21522
  timestamp: numberToBigInt(Date.now()),
21523
+ attributes: info.attributes,
21440
21524
  contentHeader: {
21441
21525
  case: 'byteHeader',
21442
21526
  value: new DataStream_ByteHeader({
@@ -22925,12 +23009,14 @@ class Room extends eventsExports.EventEmitter {
22925
23009
  continue;
22926
23010
  }
22927
23011
  }
22928
- if (kind === 'audioinput' && !isSafari() || kind === 'videoinput') {
23012
+ if (kind === 'audioinput' && !isSafariBased() || kind === 'videoinput') {
22929
23013
  // airpods on Safari need special handling for audioinput as the track doesn't end as soon as you take them out
22930
23014
  continue;
22931
23015
  }
22932
23016
  // switch to first available device if previously active device is not available any more
22933
- if (devicesOfKind.length > 0 && !devicesOfKind.find(deviceInfo => deviceInfo.deviceId === this.getActiveDevice(kind))) {
23017
+ if (devicesOfKind.length > 0 && !devicesOfKind.find(deviceInfo => deviceInfo.deviceId === this.getActiveDevice(kind)) && (
23018
+ // avoid switching audio output on safari without explicit user action as it leads to slowed down audio playback
23019
+ kind !== 'audiooutput' || !isSafariBased())) {
22934
23020
  yield this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
22935
23021
  }
22936
23022
  }
@@ -23014,8 +23100,8 @@ class Room extends eventsExports.EventEmitter {
23014
23100
  this.onLocalConnectionQualityChanged = quality => {
23015
23101
  this.emit(RoomEvent.ConnectionQualityChanged, quality, this.localParticipant);
23016
23102
  };
23017
- this.onMediaDevicesError = e => {
23018
- this.emit(RoomEvent.MediaDevicesError, e);
23103
+ this.onMediaDevicesError = (e, kind) => {
23104
+ this.emit(RoomEvent.MediaDevicesError, e, kind);
23019
23105
  };
23020
23106
  this.onLocalParticipantPermissionsChanged = prevPermissions => {
23021
23107
  this.emit(RoomEvent.ParticipantPermissionsChanged, prevPermissions, this.localParticipant);
@@ -23741,6 +23827,7 @@ class Room extends eventsExports.EventEmitter {
23741
23827
  participant.unpublishTrack(publication.trackSid, true);
23742
23828
  });
23743
23829
  this.emit(RoomEvent.ParticipantDisconnected, participant);
23830
+ participant.setDisconnected();
23744
23831
  (_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.handleParticipantDisconnected(participant.identity);
23745
23832
  }
23746
23833
  handleStreamHeader(streamHeader, participantIdentity) {
@@ -23947,6 +24034,8 @@ class Room extends eventsExports.EventEmitter {
23947
24034
  this.emit(RoomEvent.TrackSubscriptionFailed, trackSid, participant, error);
23948
24035
  }).on(ParticipantEvent.TrackSubscriptionPermissionChanged, (pub, status) => {
23949
24036
  this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, status, participant);
24037
+ }).on(ParticipantEvent.Active, () => {
24038
+ this.emitWhenConnected(RoomEvent.ParticipantActive, participant);
23950
24039
  });
23951
24040
  // update info at the end after callbacks have been set up
23952
24041
  if (info) {