livekit-client 2.5.0 → 2.5.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 (42) hide show
  1. package/README.md +4 -0
  2. package/dist/livekit-client.esm.mjs +268 -71
  3. package/dist/livekit-client.esm.mjs.map +1 -1
  4. package/dist/livekit-client.umd.js +1 -1
  5. package/dist/livekit-client.umd.js.map +1 -1
  6. package/dist/src/room/PCTransport.d.ts.map +1 -1
  7. package/dist/src/room/Room.d.ts +5 -0
  8. package/dist/src/room/Room.d.ts.map +1 -1
  9. package/dist/src/room/events.d.ts +10 -2
  10. package/dist/src/room/events.d.ts.map +1 -1
  11. package/dist/src/room/participant/LocalParticipant.d.ts +4 -1
  12. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  13. package/dist/src/room/participant/Participant.d.ts +1 -0
  14. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  15. package/dist/src/room/timers.d.ts +4 -4
  16. package/dist/src/room/timers.d.ts.map +1 -1
  17. package/dist/src/room/track/options.d.ts +1 -1
  18. package/dist/src/room/types.d.ts +2 -0
  19. package/dist/src/room/types.d.ts.map +1 -1
  20. package/dist/src/room/utils.d.ts +1 -1
  21. package/dist/src/room/utils.d.ts.map +1 -1
  22. package/dist/ts4.2/src/room/Room.d.ts +5 -0
  23. package/dist/ts4.2/src/room/events.d.ts +10 -2
  24. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +4 -1
  25. package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -0
  26. package/dist/ts4.2/src/room/timers.d.ts +4 -4
  27. package/dist/ts4.2/src/room/track/options.d.ts +1 -1
  28. package/dist/ts4.2/src/room/types.d.ts +2 -0
  29. package/dist/ts4.2/src/room/utils.d.ts +1 -1
  30. package/package.json +2 -2
  31. package/src/room/PCTransport.ts +3 -1
  32. package/src/room/RTCEngine.ts +1 -1
  33. package/src/room/Room.ts +28 -1
  34. package/src/room/events.ts +10 -0
  35. package/src/room/participant/LocalParticipant.ts +112 -76
  36. package/src/room/participant/Participant.ts +1 -0
  37. package/src/room/timers.ts +15 -6
  38. package/src/room/track/LocalVideoTrack.test.ts +60 -0
  39. package/src/room/track/LocalVideoTrack.ts +1 -1
  40. package/src/room/track/options.ts +1 -1
  41. package/src/room/types.ts +2 -0
  42. package/src/room/utils.ts +10 -0
package/README.md CHANGED
@@ -75,6 +75,10 @@ import {
75
75
  RemoteTrackPublication,
76
76
  Room,
77
77
  RoomEvent,
78
+ VideoPresets,
79
+ Track,
80
+ LocalTrackPublication,
81
+ LocalParticipant
78
82
  } from 'livekit-client';
79
83
 
80
84
  // creates a new room with options
@@ -3397,6 +3397,122 @@ target => {
3397
3397
  }
3398
3398
  });
3399
3399
 
3400
+ // @generated by protoc-gen-es v1.10.0 with parameter "target=js+dts"
3401
+ // @generated from file livekit_metrics.proto (package livekit, syntax proto3)
3402
+ /* eslint-disable */
3403
+ // @ts-nocheck
3404
+
3405
+
3406
+ /**
3407
+ * @generated from message livekit.MetricsBatch
3408
+ */
3409
+ const MetricsBatch = /*@__PURE__*/proto3.makeMessageType("livekit.MetricsBatch", () => [{
3410
+ no: 1,
3411
+ name: "str_data",
3412
+ kind: "scalar",
3413
+ T: 9 /* ScalarType.STRING */,
3414
+ repeated: true
3415
+ }, {
3416
+ no: 2,
3417
+ name: "time_series",
3418
+ kind: "message",
3419
+ T: TimeSeriesMetric,
3420
+ repeated: true
3421
+ }, {
3422
+ no: 3,
3423
+ name: "events",
3424
+ kind: "message",
3425
+ T: EventMetric,
3426
+ repeated: true
3427
+ }]);
3428
+
3429
+ /**
3430
+ * @generated from message livekit.TimeSeriesMetric
3431
+ */
3432
+ const TimeSeriesMetric = /*@__PURE__*/proto3.makeMessageType("livekit.TimeSeriesMetric", () => [{
3433
+ no: 1,
3434
+ name: "label",
3435
+ kind: "scalar",
3436
+ T: 13 /* ScalarType.UINT32 */
3437
+ }, {
3438
+ no: 2,
3439
+ name: "participant_identity",
3440
+ kind: "scalar",
3441
+ T: 13 /* ScalarType.UINT32 */
3442
+ }, {
3443
+ no: 3,
3444
+ name: "track_sid",
3445
+ kind: "scalar",
3446
+ T: 13 /* ScalarType.UINT32 */
3447
+ }, {
3448
+ no: 4,
3449
+ name: "start_timestamp",
3450
+ kind: "scalar",
3451
+ T: 3 /* ScalarType.INT64 */
3452
+ }, {
3453
+ no: 5,
3454
+ name: "end_timestamp",
3455
+ kind: "scalar",
3456
+ T: 3 /* ScalarType.INT64 */
3457
+ }, {
3458
+ no: 6,
3459
+ name: "samples",
3460
+ kind: "message",
3461
+ T: MetricSample,
3462
+ repeated: true
3463
+ }]);
3464
+
3465
+ /**
3466
+ * @generated from message livekit.MetricSample
3467
+ */
3468
+ const MetricSample = /*@__PURE__*/proto3.makeMessageType("livekit.MetricSample", () => [{
3469
+ no: 1,
3470
+ name: "timestamp",
3471
+ kind: "scalar",
3472
+ T: 3 /* ScalarType.INT64 */
3473
+ }, {
3474
+ no: 2,
3475
+ name: "value",
3476
+ kind: "scalar",
3477
+ T: 2 /* ScalarType.FLOAT */
3478
+ }]);
3479
+
3480
+ /**
3481
+ * @generated from message livekit.EventMetric
3482
+ */
3483
+ const EventMetric = /*@__PURE__*/proto3.makeMessageType("livekit.EventMetric", () => [{
3484
+ no: 1,
3485
+ name: "label",
3486
+ kind: "scalar",
3487
+ T: 13 /* ScalarType.UINT32 */
3488
+ }, {
3489
+ no: 2,
3490
+ name: "participant_identity",
3491
+ kind: "scalar",
3492
+ T: 13 /* ScalarType.UINT32 */
3493
+ }, {
3494
+ no: 3,
3495
+ name: "track_sid",
3496
+ kind: "scalar",
3497
+ T: 13 /* ScalarType.UINT32 */
3498
+ }, {
3499
+ no: 4,
3500
+ name: "start_timestamp",
3501
+ kind: "scalar",
3502
+ T: 3 /* ScalarType.INT64 */
3503
+ }, {
3504
+ no: 5,
3505
+ name: "end_timestamp",
3506
+ kind: "scalar",
3507
+ T: 3 /* ScalarType.INT64 */,
3508
+ opt: true
3509
+ }, {
3510
+ no: 6,
3511
+ name: "metadata",
3512
+ kind: "scalar",
3513
+ T: 9 /* ScalarType.STRING */
3514
+ }]);
3515
+
3400
3516
  // Copyright 2023 LiveKit, Inc.
3401
3517
  //
3402
3518
  // Licensed under the Apache License, Version 2.0 (the "License");
@@ -3719,6 +3835,11 @@ const ParticipantPermission = /*@__PURE__*/proto3.makeMessageType("livekit.Parti
3719
3835
  name: "agent",
3720
3836
  kind: "scalar",
3721
3837
  T: 8 /* ScalarType.BOOL */
3838
+ }, {
3839
+ no: 12,
3840
+ name: "can_subscribe_metrics",
3841
+ kind: "scalar",
3842
+ T: 8 /* ScalarType.BOOL */
3722
3843
  }]);
3723
3844
 
3724
3845
  /**
@@ -4058,6 +4179,12 @@ const DataPacket = /*@__PURE__*/proto3.makeMessageType("livekit.DataPacket", ()
4058
4179
  kind: "message",
4059
4180
  T: Transcription,
4060
4181
  oneof: "value"
4182
+ }, {
4183
+ no: 8,
4184
+ name: "metrics",
4185
+ kind: "message",
4186
+ T: MetricsBatch,
4187
+ oneof: "value"
4061
4188
  }]);
4062
4189
 
4063
4190
  /**
@@ -4964,6 +5091,17 @@ const JoinResponse = /*@__PURE__*/proto3.makeMessageType("livekit.JoinResponse",
4964
5091
  name: "sif_trailer",
4965
5092
  kind: "scalar",
4966
5093
  T: 12 /* ScalarType.BYTES */
5094
+ }, {
5095
+ no: 14,
5096
+ name: "enabled_publish_codecs",
5097
+ kind: "message",
5098
+ T: Codec,
5099
+ repeated: true
5100
+ }, {
5101
+ no: 15,
5102
+ name: "fast_publish",
5103
+ kind: "scalar",
5104
+ T: 8 /* ScalarType.BOOL */
4967
5105
  }]);
4968
5106
 
4969
5107
  /**
@@ -10182,6 +10320,10 @@ var RoomEvent;
10182
10320
  * args: (kind: MediaDeviceKind, deviceId: string)
10183
10321
  */
10184
10322
  RoomEvent["ActiveDeviceChanged"] = "activeDeviceChanged";
10323
+ /**
10324
+ * fired when the first remote participant has subscribed to the localParticipant's track
10325
+ */
10326
+ RoomEvent["LocalTrackSubscribed"] = "localTrackSubscribed";
10185
10327
  })(RoomEvent || (RoomEvent = {}));
10186
10328
  var ParticipantEvent;
10187
10329
  (function (ParticipantEvent) {
@@ -10345,6 +10487,10 @@ var ParticipantEvent;
10345
10487
  * When a participant's attributes changed, this event will be emitted with the changed attributes
10346
10488
  */
10347
10489
  ParticipantEvent["AttributesChanged"] = "attributesChanged";
10490
+ /**
10491
+ * fired on local participant only, when the first remote participant has subscribed to the track specified in the payload
10492
+ */
10493
+ ParticipantEvent["LocalTrackSubscribed"] = "localTrackSubscribed";
10348
10494
  })(ParticipantEvent || (ParticipantEvent = {}));
10349
10495
  /** @internal */
10350
10496
  var EngineEvent;
@@ -10568,7 +10714,7 @@ function getOSVersion(ua) {
10568
10714
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
10569
10715
  }
10570
10716
 
10571
- var version$1 = "2.5.0";
10717
+ var version$1 = "2.5.1";
10572
10718
 
10573
10719
  const version = version$1;
10574
10720
  const protocolVersion = 15;
@@ -10579,12 +10725,12 @@ const protocolVersion = 15;
10579
10725
  * that the timer fires on time.
10580
10726
  */
10581
10727
  class CriticalTimers {}
10582
- // eslint-disable-next-line @typescript-eslint/no-implied-eval
10583
10728
  CriticalTimers.setTimeout = function () {
10584
10729
  return setTimeout(...arguments);
10585
10730
  };
10731
+ CriticalTimers.setInterval =
10586
10732
  // eslint-disable-next-line @typescript-eslint/no-implied-eval
10587
- CriticalTimers.setInterval = function () {
10733
+ function () {
10588
10734
  return setInterval(...arguments);
10589
10735
  };
10590
10736
  CriticalTimers.clearTimeout = function () {
@@ -11696,7 +11842,7 @@ function toHttpUrl(url) {
11696
11842
  }
11697
11843
  return url;
11698
11844
  }
11699
- function extractTranscriptionSegments(transcription) {
11845
+ function extractTranscriptionSegments(transcription, firstReceivedTimesMap) {
11700
11846
  return transcription.segments.map(_ref => {
11701
11847
  let {
11702
11848
  id,
@@ -11706,13 +11852,23 @@ function extractTranscriptionSegments(transcription) {
11706
11852
  endTime,
11707
11853
  final
11708
11854
  } = _ref;
11855
+ var _a;
11856
+ const firstReceivedTime = (_a = firstReceivedTimesMap.get(id)) !== null && _a !== void 0 ? _a : Date.now();
11857
+ const lastReceivedTime = Date.now();
11858
+ if (final) {
11859
+ firstReceivedTimesMap.delete(id);
11860
+ } else {
11861
+ firstReceivedTimesMap.set(id, firstReceivedTime);
11862
+ }
11709
11863
  return {
11710
11864
  id,
11711
11865
  text,
11712
11866
  startTime: Number.parseInt(startTime.toString()),
11713
11867
  endTime: Number.parseInt(endTime.toString()),
11714
11868
  final,
11715
- language
11869
+ language,
11870
+ firstReceivedTime,
11871
+ lastReceivedTime
11716
11872
  };
11717
11873
  });
11718
11874
  }
@@ -14013,6 +14169,7 @@ the first few seconds. So we use a 70% of target bitrate here as the start bitra
14013
14169
  eliminate this issue.
14014
14170
  */
14015
14171
  const startBitrateForSVC = 0.7;
14172
+ const debounceInterval = 20;
14016
14173
  const PCEvents = {
14017
14174
  NegotiationStarted: 'negotiationStarted',
14018
14175
  NegotiationComplete: 'negotiationComplete',
@@ -14049,7 +14206,7 @@ class PCTransport extends eventsExports.EventEmitter {
14049
14206
  throw e;
14050
14207
  }
14051
14208
  }
14052
- }), 100);
14209
+ }), debounceInterval);
14053
14210
  this.close = () => {
14054
14211
  if (!this._pc) {
14055
14212
  return;
@@ -16017,7 +16174,7 @@ function videoLayersFromEncodings(width, height, encodings, svc) {
16017
16174
  const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
16018
16175
  for (let i = 0; i < sm.spatial; i += 1) {
16019
16176
  layers.push(new VideoLayer({
16020
- quality: VideoQuality.HIGH - i,
16177
+ quality: Math.min(VideoQuality.HIGH, sm.spatial - 1) - i,
16021
16178
  width: Math.ceil(width / Math.pow(resRatio, i)),
16022
16179
  height: Math.ceil(height / Math.pow(resRatio, i)),
16023
16180
  bitrate: encodings[0].maxBitrate ? Math.ceil(encodings[0].maxBitrate / Math.pow(bitratesRatio, i)) : 0,
@@ -16276,7 +16433,7 @@ class RTCEngine extends eventsExports.EventEmitter {
16276
16433
  yield this.configure(joinResponse);
16277
16434
  }
16278
16435
  // create offer
16279
- if (!this.subscriberPrimary) {
16436
+ if (!this.subscriberPrimary || joinResponse.fastPublish) {
16280
16437
  this.negotiate();
16281
16438
  }
16282
16439
  this.clientConfiguration = joinResponse.clientConfiguration;
@@ -18315,6 +18472,7 @@ class LocalParticipant extends Participant {
18315
18472
  this.participantTrackPermissions = [];
18316
18473
  this.allParticipantsAllowedToSubscribe = true;
18317
18474
  this.encryptionType = Encryption_Type.NONE;
18475
+ this.enabledPublishVideoCodecs = [];
18318
18476
  this.handleReconnecting = () => {
18319
18477
  if (!this.reconnectFuture) {
18320
18478
  this.reconnectFuture = new Future();
@@ -18979,7 +19137,7 @@ class LocalParticipant extends Participant {
18979
19137
  }
18980
19138
  publish(track, opts, isStereo) {
18981
19139
  return __awaiter(this, void 0, void 0, function* () {
18982
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
19140
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
18983
19141
  const existingTrackOfSource = Array.from(this.trackPublications.values()).find(publishedTrack => track instanceof LocalTrack && publishedTrack.source === track.source);
18984
19142
  if (existingTrackOfSource && track.source !== Track.Source.Unknown) {
18985
19143
  this.log.info("publishing a second track with the same source: ".concat(track.source), Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)));
@@ -19002,6 +19160,12 @@ class LocalParticipant extends Participant {
19002
19160
  if (opts.videoCodec === undefined) {
19003
19161
  opts.videoCodec = defaultVideoCodec;
19004
19162
  }
19163
+ if (this.enabledPublishVideoCodecs.length > 0) {
19164
+ // fallback to a supported codec if it is not supported
19165
+ if (!this.enabledPublishVideoCodecs.some(c => opts.videoCodec === mimeTypeToVideoCodecString(c.mime))) {
19166
+ opts.videoCodec = mimeTypeToVideoCodecString(this.enabledPublishVideoCodecs[0].mime);
19167
+ }
19168
+ }
19005
19169
  const videoCodec = opts.videoCodec;
19006
19170
  // handle track actions
19007
19171
  track.on(TrackEvent.Muted, this.onTrackMuted);
@@ -19104,25 +19268,75 @@ class LocalParticipant extends Participant {
19104
19268
  if (!this.engine || this.engine.isClosed) {
19105
19269
  throw new UnexpectedConnectionState('cannot publish track when not connected');
19106
19270
  }
19107
- const ti = yield this.engine.addTrack(req);
19108
- // server might not support the codec the client has requested, in that case, fallback
19109
- // to a supported codec
19110
- let primaryCodecMime;
19111
- ti.codecs.forEach(codec => {
19112
- if (primaryCodecMime === undefined) {
19113
- primaryCodecMime = codec.mimeType;
19271
+ const negotiate = () => __awaiter(this, void 0, void 0, function* () {
19272
+ var _a, _b, _c;
19273
+ if (!this.engine.pcManager) {
19274
+ throw new UnexpectedConnectionState('pcManager is not ready');
19275
+ }
19276
+ track.sender = yield this.engine.createSender(track, opts, encodings);
19277
+ if (track instanceof LocalVideoTrack) {
19278
+ (_a = opts.degradationPreference) !== null && _a !== void 0 ? _a : opts.degradationPreference = getDefaultDegradationPreference(track);
19279
+ track.setDegradationPreference(opts.degradationPreference);
19280
+ }
19281
+ if (encodings) {
19282
+ if (isFireFox() && track.kind === Track.Kind.Audio) {
19283
+ /* Refer to RFC https://datatracker.ietf.org/doc/html/rfc7587#section-6.1,
19284
+ livekit-server uses maxaveragebitrate=510000 in the answer sdp to permit client to
19285
+ publish high quality audio track. But firefox always uses this value as the actual
19286
+ bitrates, causing the audio bitrates to rise to 510Kbps in any stereo case unexpectedly.
19287
+ So the client need to modify maxaverragebitrates in answer sdp to user provided value to
19288
+ fix the issue.
19289
+ */
19290
+ let trackTransceiver = undefined;
19291
+ for (const transceiver of this.engine.pcManager.publisher.getTransceivers()) {
19292
+ if (transceiver.sender === track.sender) {
19293
+ trackTransceiver = transceiver;
19294
+ break;
19295
+ }
19296
+ }
19297
+ if (trackTransceiver) {
19298
+ this.engine.pcManager.publisher.setTrackCodecBitrate({
19299
+ transceiver: trackTransceiver,
19300
+ codec: 'opus',
19301
+ maxbr: ((_b = encodings[0]) === null || _b === void 0 ? void 0 : _b.maxBitrate) ? encodings[0].maxBitrate / 1000 : 0
19302
+ });
19303
+ }
19304
+ } else if (track.codec && isSVCCodec(track.codec) && ((_c = encodings[0]) === null || _c === void 0 ? void 0 : _c.maxBitrate)) {
19305
+ this.engine.pcManager.publisher.setTrackCodecBitrate({
19306
+ cid: req.cid,
19307
+ codec: track.codec,
19308
+ maxbr: encodings[0].maxBitrate / 1000
19309
+ });
19310
+ }
19114
19311
  }
19312
+ yield this.engine.negotiate();
19115
19313
  });
19116
- if (primaryCodecMime && track.kind === Track.Kind.Video) {
19117
- const updatedCodec = mimeTypeToVideoCodecString(primaryCodecMime);
19118
- if (updatedCodec !== videoCodec) {
19119
- this.log.debug('falling back to server selected codec', Object.assign(Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)), {
19120
- codec: updatedCodec
19121
- }));
19122
- opts.videoCodec = updatedCodec;
19123
- // recompute encodings since bitrates/etc could have changed
19124
- encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, req.width, req.height, opts);
19314
+ let ti;
19315
+ if (this.enabledPublishVideoCodecs.length > 0) {
19316
+ const rets = yield Promise.all([this.engine.addTrack(req), negotiate()]);
19317
+ ti = rets[0];
19318
+ } else {
19319
+ ti = yield this.engine.addTrack(req);
19320
+ // server might not support the codec the client has requested, in that case, fallback
19321
+ // to a supported codec
19322
+ let primaryCodecMime;
19323
+ ti.codecs.forEach(codec => {
19324
+ if (primaryCodecMime === undefined) {
19325
+ primaryCodecMime = codec.mimeType;
19326
+ }
19327
+ });
19328
+ if (primaryCodecMime && track.kind === Track.Kind.Video) {
19329
+ const updatedCodec = mimeTypeToVideoCodecString(primaryCodecMime);
19330
+ if (updatedCodec !== videoCodec) {
19331
+ this.log.debug('falling back to server selected codec', Object.assign(Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(track)), {
19332
+ codec: updatedCodec
19333
+ }));
19334
+ opts.videoCodec = updatedCodec;
19335
+ // recompute encodings since bitrates/etc could have changed
19336
+ encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, req.width, req.height, opts);
19337
+ }
19125
19338
  }
19339
+ yield negotiate();
19126
19340
  }
19127
19341
  const publication = new LocalTrackPublication(track.kind, ti, track, {
19128
19342
  loggerName: this.roomOptions.loggerName,
@@ -19131,50 +19345,10 @@ class LocalParticipant extends Participant {
19131
19345
  // save options for when it needs to be republished again
19132
19346
  publication.options = opts;
19133
19347
  track.sid = ti.sid;
19134
- if (!this.engine.pcManager) {
19135
- throw new UnexpectedConnectionState('pcManager is not ready');
19136
- }
19137
19348
  this.log.debug("publishing ".concat(track.kind, " with encodings"), Object.assign(Object.assign({}, this.logContext), {
19138
19349
  encodings,
19139
19350
  trackInfo: ti
19140
19351
  }));
19141
- track.sender = yield this.engine.createSender(track, opts, encodings);
19142
- if (track instanceof LocalVideoTrack) {
19143
- (_l = opts.degradationPreference) !== null && _l !== void 0 ? _l : opts.degradationPreference = getDefaultDegradationPreference(track);
19144
- track.setDegradationPreference(opts.degradationPreference);
19145
- }
19146
- if (encodings) {
19147
- if (isFireFox() && track.kind === Track.Kind.Audio) {
19148
- /* Refer to RFC https://datatracker.ietf.org/doc/html/rfc7587#section-6.1,
19149
- livekit-server uses maxaveragebitrate=510000 in the answer sdp to permit client to
19150
- publish high quality audio track. But firefox always uses this value as the actual
19151
- bitrates, causing the audio bitrates to rise to 510Kbps in any stereo case unexpectedly.
19152
- So the client need to modify maxaverragebitrates in answer sdp to user provided value to
19153
- fix the issue.
19154
- */
19155
- let trackTransceiver = undefined;
19156
- for (const transceiver of this.engine.pcManager.publisher.getTransceivers()) {
19157
- if (transceiver.sender === track.sender) {
19158
- trackTransceiver = transceiver;
19159
- break;
19160
- }
19161
- }
19162
- if (trackTransceiver) {
19163
- this.engine.pcManager.publisher.setTrackCodecBitrate({
19164
- transceiver: trackTransceiver,
19165
- codec: 'opus',
19166
- maxbr: ((_m = encodings[0]) === null || _m === void 0 ? void 0 : _m.maxBitrate) ? encodings[0].maxBitrate / 1000 : 0
19167
- });
19168
- }
19169
- } else if (track.codec && isSVCCodec(track.codec) && ((_o = encodings[0]) === null || _o === void 0 ? void 0 : _o.maxBitrate)) {
19170
- this.engine.pcManager.publisher.setTrackCodecBitrate({
19171
- cid: req.cid,
19172
- codec: track.codec,
19173
- maxbr: encodings[0].maxBitrate / 1000
19174
- });
19175
- }
19176
- }
19177
- yield this.engine.negotiate();
19178
19352
  if (track instanceof LocalVideoTrack) {
19179
19353
  track.startMonitor(this.engine.client);
19180
19354
  } else if (track instanceof LocalAudioTrack) {
@@ -19240,9 +19414,12 @@ class LocalParticipant extends Participant {
19240
19414
  if (!this.engine || this.engine.isClosed) {
19241
19415
  throw new UnexpectedConnectionState('cannot publish track when not connected');
19242
19416
  }
19243
- const ti = yield this.engine.addTrack(req);
19244
- yield this.engine.createSimulcastSender(track, simulcastTrack, opts, encodings);
19245
- yield this.engine.negotiate();
19417
+ const negotiate = () => __awaiter(this, void 0, void 0, function* () {
19418
+ yield this.engine.createSimulcastSender(track, simulcastTrack, opts, encodings);
19419
+ yield this.engine.negotiate();
19420
+ });
19421
+ const rets = yield Promise.all([this.engine.addTrack(req), negotiate()]);
19422
+ const ti = rets[0];
19246
19423
  this.log.debug("published ".concat(videoCodec, " for track ").concat(track.sid), Object.assign(Object.assign({}, this.logContext), {
19247
19424
  encodings,
19248
19425
  trackInfo: ti
@@ -19426,6 +19603,10 @@ class LocalParticipant extends Participant {
19426
19603
  }
19427
19604
  }
19428
19605
  /** @internal */
19606
+ setEnabledPublishCodecs(codecs) {
19607
+ this.enabledPublishVideoCodecs = codecs.filter(c => c.mime.split('/')[0].toLowerCase() === 'video');
19608
+ }
19609
+ /** @internal */
19429
19610
  updateInfo(info) {
19430
19611
  if (info.sid !== this.sid) {
19431
19612
  // drop updates that specify a wrong sid.
@@ -20147,6 +20328,7 @@ class Room extends eventsExports.EventEmitter {
20147
20328
  const pi = joinResponse.participant;
20148
20329
  this.localParticipant.sid = pi.sid;
20149
20330
  this.localParticipant.identity = pi.identity;
20331
+ this.localParticipant.setEnabledPublishCodecs(joinResponse.enabledPublishCodecs);
20150
20332
  if (this.options.e2ee && this.e2eeManager) {
20151
20333
  try {
20152
20334
  this.e2eeManager.setSifTrailer(joinResponse.sifTrailer);
@@ -20559,7 +20741,7 @@ class Room extends eventsExports.EventEmitter {
20559
20741
  // find the participant
20560
20742
  const participant = transcription.transcribedParticipantIdentity === this.localParticipant.identity ? this.localParticipant : this.getParticipantByIdentity(transcription.transcribedParticipantIdentity);
20561
20743
  const publication = participant === null || participant === void 0 ? void 0 : participant.trackPublications.get(transcription.trackId);
20562
- const segments = extractTranscriptionSegments(transcription);
20744
+ const segments = extractTranscriptionSegments(transcription, this.transcriptionReceivedTimes);
20563
20745
  publication === null || publication === void 0 ? void 0 : publication.emit(TrackEvent.TranscriptionReceived, segments);
20564
20746
  participant === null || participant === void 0 ? void 0 : participant.emit(ParticipantEvent.TranscriptionReceived, segments, publication);
20565
20747
  this.emit(RoomEvent.TranscriptionReceived, segments, participant, publication);
@@ -20674,6 +20856,7 @@ class Room extends eventsExports.EventEmitter {
20674
20856
  this.sidToIdentity = new Map();
20675
20857
  this.options = Object.assign(Object.assign({}, roomOptionDefaults), options);
20676
20858
  this.log = getLogger((_a = this.options.loggerName) !== null && _a !== void 0 ? _a : LoggerNames.Room);
20859
+ this.transcriptionReceivedTimes = new Map();
20677
20860
  this.options.audioCaptureDefaults = Object.assign(Object.assign({}, audioDefaults), options === null || options === void 0 ? void 0 : options.audioCaptureDefaults);
20678
20861
  this.options.videoCaptureDefaults = Object.assign(Object.assign({}, videoDefaults), options === null || options === void 0 ? void 0 : options.videoCaptureDefaults);
20679
20862
  this.options.publishDefaults = Object.assign(Object.assign({}, publishDefaults), options === null || options === void 0 ? void 0 : options.publishDefaults);
@@ -20819,6 +21002,19 @@ class Room extends eventsExports.EventEmitter {
20819
21002
  }
20820
21003
  }).on(EngineEvent.DCBufferStatusChanged, (status, kind) => {
20821
21004
  this.emit(RoomEvent.DCBufferStatusChanged, status, kind);
21005
+ }).on(EngineEvent.LocalTrackSubscribed, subscribedSid => {
21006
+ const trackPublication = this.localParticipant.getTrackPublications().find(_ref2 => {
21007
+ let {
21008
+ trackSid
21009
+ } = _ref2;
21010
+ return trackSid === subscribedSid;
21011
+ });
21012
+ if (!trackPublication) {
21013
+ this.log.warn('could not find local track subscription for subscribed event', this.logContext);
21014
+ return;
21015
+ }
21016
+ this.localParticipant.emit(ParticipantEvent.LocalTrackSubscribed, trackPublication);
21017
+ this.emitWhenConnected(RoomEvent.LocalTrackSubscribed, trackPublication, this.localParticipant);
20822
21018
  });
20823
21019
  if (this.localParticipant) {
20824
21020
  this.localParticipant.setupEngine(this.engine);
@@ -21188,6 +21384,7 @@ class Room extends eventsExports.EventEmitter {
21188
21384
  this.clearConnectionReconcile();
21189
21385
  this.isResuming = false;
21190
21386
  this.bufferedEvents = [];
21387
+ this.transcriptionReceivedTimes.clear();
21191
21388
  if (this.state === ConnectionState.Disconnected) {
21192
21389
  return;
21193
21390
  }
@@ -21431,8 +21628,8 @@ class Room extends eventsExports.EventEmitter {
21431
21628
  return true;
21432
21629
  }
21433
21630
  emitBufferedEvents() {
21434
- this.bufferedEvents.forEach(_ref2 => {
21435
- let [ev, args] = _ref2;
21631
+ this.bufferedEvents.forEach(_ref3 => {
21632
+ let [ev, args] = _ref3;
21436
21633
  this.emit(ev, ...args);
21437
21634
  });
21438
21635
  this.bufferedEvents = [];