livekit-client 1.1.8 → 1.2.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 (54) hide show
  1. package/README.md +1 -0
  2. package/dist/livekit-client.esm.mjs +677 -187
  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/api/SignalClient.d.ts +4 -1
  7. package/dist/src/api/SignalClient.d.ts.map +1 -1
  8. package/dist/src/index.d.ts +4 -3
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/options.d.ts +1 -0
  11. package/dist/src/options.d.ts.map +1 -1
  12. package/dist/src/proto/livekit_models.d.ts +234 -0
  13. package/dist/src/proto/livekit_models.d.ts.map +1 -1
  14. package/dist/src/proto/livekit_rtc.d.ts +944 -6
  15. package/dist/src/proto/livekit_rtc.d.ts.map +1 -1
  16. package/dist/src/room/PCTransport.d.ts +9 -0
  17. package/dist/src/room/PCTransport.d.ts.map +1 -1
  18. package/dist/src/room/RTCEngine.d.ts +3 -2
  19. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  20. package/dist/src/room/Room.d.ts +3 -3
  21. package/dist/src/room/Room.d.ts.map +1 -1
  22. package/dist/src/room/events.d.ts +8 -1
  23. package/dist/src/room/events.d.ts.map +1 -1
  24. package/dist/src/room/participant/LocalParticipant.d.ts +3 -3
  25. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  26. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  27. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  28. package/dist/src/room/track/LocalTrack.d.ts +2 -0
  29. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  30. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  31. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
  32. package/dist/src/room/track/RemoteTrackPublication.d.ts +4 -1
  33. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  34. package/package.json +3 -1
  35. package/src/api/SignalClient.ts +21 -6
  36. package/src/index.ts +6 -2
  37. package/src/options.ts +1 -0
  38. package/src/proto/livekit_models.ts +179 -4
  39. package/src/proto/livekit_rtc.ts +14 -1
  40. package/src/room/PCTransport.ts +39 -0
  41. package/src/room/RTCEngine.ts +44 -18
  42. package/src/room/Room.ts +30 -24
  43. package/src/room/events.ts +7 -0
  44. package/src/room/participant/LocalParticipant.ts +70 -10
  45. package/src/room/participant/RemoteParticipant.ts +12 -10
  46. package/src/room/participant/publishUtils.ts +1 -1
  47. package/src/room/track/LocalAudioTrack.ts +16 -12
  48. package/src/room/track/LocalTrack.ts +41 -25
  49. package/src/room/track/LocalVideoTrack.ts +15 -11
  50. package/src/room/track/RemoteTrack.ts +1 -0
  51. package/src/room/track/RemoteTrackPublication.ts +37 -11
  52. package/dist/src/api/RequestQueue.d.ts +0 -13
  53. package/dist/src/api/RequestQueue.d.ts.map +0 -1
  54. package/src/api/RequestQueue.ts +0 -53
@@ -4484,6 +4484,82 @@ function clientConfigSettingToJSON(object) {
4484
4484
  return 'UNKNOWN';
4485
4485
  }
4486
4486
  }
4487
+ var DisconnectReason;
4488
+
4489
+ (function (DisconnectReason) {
4490
+ DisconnectReason[DisconnectReason["UNKNOWN_REASON"] = 0] = "UNKNOWN_REASON";
4491
+ DisconnectReason[DisconnectReason["CLIENT_INITIATED"] = 1] = "CLIENT_INITIATED";
4492
+ DisconnectReason[DisconnectReason["DUPLICATE_IDENTITY"] = 2] = "DUPLICATE_IDENTITY";
4493
+ DisconnectReason[DisconnectReason["SERVER_SHUTDOWN"] = 3] = "SERVER_SHUTDOWN";
4494
+ DisconnectReason[DisconnectReason["PARTICIPANT_REMOVED"] = 4] = "PARTICIPANT_REMOVED";
4495
+ DisconnectReason[DisconnectReason["ROOM_DELETED"] = 5] = "ROOM_DELETED";
4496
+ DisconnectReason[DisconnectReason["STATE_MISMATCH"] = 6] = "STATE_MISMATCH";
4497
+ DisconnectReason[DisconnectReason["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
4498
+ })(DisconnectReason || (DisconnectReason = {}));
4499
+
4500
+ function disconnectReasonFromJSON(object) {
4501
+ switch (object) {
4502
+ case 0:
4503
+ case 'UNKNOWN_REASON':
4504
+ return DisconnectReason.UNKNOWN_REASON;
4505
+
4506
+ case 1:
4507
+ case 'CLIENT_INITIATED':
4508
+ return DisconnectReason.CLIENT_INITIATED;
4509
+
4510
+ case 2:
4511
+ case 'DUPLICATE_IDENTITY':
4512
+ return DisconnectReason.DUPLICATE_IDENTITY;
4513
+
4514
+ case 3:
4515
+ case 'SERVER_SHUTDOWN':
4516
+ return DisconnectReason.SERVER_SHUTDOWN;
4517
+
4518
+ case 4:
4519
+ case 'PARTICIPANT_REMOVED':
4520
+ return DisconnectReason.PARTICIPANT_REMOVED;
4521
+
4522
+ case 5:
4523
+ case 'ROOM_DELETED':
4524
+ return DisconnectReason.ROOM_DELETED;
4525
+
4526
+ case 6:
4527
+ case 'STATE_MISMATCH':
4528
+ return DisconnectReason.STATE_MISMATCH;
4529
+
4530
+ case -1:
4531
+ case 'UNRECOGNIZED':
4532
+ default:
4533
+ return DisconnectReason.UNRECOGNIZED;
4534
+ }
4535
+ }
4536
+ function disconnectReasonToJSON(object) {
4537
+ switch (object) {
4538
+ case DisconnectReason.UNKNOWN_REASON:
4539
+ return 'UNKNOWN_REASON';
4540
+
4541
+ case DisconnectReason.CLIENT_INITIATED:
4542
+ return 'CLIENT_INITIATED';
4543
+
4544
+ case DisconnectReason.DUPLICATE_IDENTITY:
4545
+ return 'DUPLICATE_IDENTITY';
4546
+
4547
+ case DisconnectReason.SERVER_SHUTDOWN:
4548
+ return 'SERVER_SHUTDOWN';
4549
+
4550
+ case DisconnectReason.PARTICIPANT_REMOVED:
4551
+ return 'PARTICIPANT_REMOVED';
4552
+
4553
+ case DisconnectReason.ROOM_DELETED:
4554
+ return 'ROOM_DELETED';
4555
+
4556
+ case DisconnectReason.STATE_MISMATCH:
4557
+ return 'STATE_MISMATCH';
4558
+
4559
+ default:
4560
+ return 'UNKNOWN';
4561
+ }
4562
+ }
4487
4563
  var ParticipantInfo_State;
4488
4564
 
4489
4565
  (function (ParticipantInfo_State) {
@@ -5204,7 +5280,8 @@ function createBaseSimulcastCodecInfo() {
5204
5280
  return {
5205
5281
  mimeType: '',
5206
5282
  mid: '',
5207
- cid: ''
5283
+ cid: '',
5284
+ layers: []
5208
5285
  };
5209
5286
  }
5210
5287
 
@@ -5224,6 +5301,10 @@ const SimulcastCodecInfo = {
5224
5301
  writer.uint32(26).string(message.cid);
5225
5302
  }
5226
5303
 
5304
+ for (const v of message.layers) {
5305
+ VideoLayer.encode(v, writer.uint32(34).fork()).ldelim();
5306
+ }
5307
+
5227
5308
  return writer;
5228
5309
  },
5229
5310
 
@@ -5248,6 +5329,10 @@ const SimulcastCodecInfo = {
5248
5329
  message.cid = reader.string();
5249
5330
  break;
5250
5331
 
5332
+ case 4:
5333
+ message.layers.push(VideoLayer.decode(reader, reader.uint32()));
5334
+ break;
5335
+
5251
5336
  default:
5252
5337
  reader.skipType(tag & 7);
5253
5338
  break;
@@ -5261,7 +5346,8 @@ const SimulcastCodecInfo = {
5261
5346
  return {
5262
5347
  mimeType: isSet$1(object.mimeType) ? String(object.mimeType) : '',
5263
5348
  mid: isSet$1(object.mid) ? String(object.mid) : '',
5264
- cid: isSet$1(object.cid) ? String(object.cid) : ''
5349
+ cid: isSet$1(object.cid) ? String(object.cid) : '',
5350
+ layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : []
5265
5351
  };
5266
5352
  },
5267
5353
 
@@ -5270,16 +5356,24 @@ const SimulcastCodecInfo = {
5270
5356
  message.mimeType !== undefined && (obj.mimeType = message.mimeType);
5271
5357
  message.mid !== undefined && (obj.mid = message.mid);
5272
5358
  message.cid !== undefined && (obj.cid = message.cid);
5359
+
5360
+ if (message.layers) {
5361
+ obj.layers = message.layers.map(e => e ? VideoLayer.toJSON(e) : undefined);
5362
+ } else {
5363
+ obj.layers = [];
5364
+ }
5365
+
5273
5366
  return obj;
5274
5367
  },
5275
5368
 
5276
5369
  fromPartial(object) {
5277
- var _a, _b, _c;
5370
+ var _a, _b, _c, _d;
5278
5371
 
5279
5372
  const message = createBaseSimulcastCodecInfo();
5280
5373
  message.mimeType = (_a = object.mimeType) !== null && _a !== void 0 ? _a : '';
5281
5374
  message.mid = (_b = object.mid) !== null && _b !== void 0 ? _b : '';
5282
5375
  message.cid = (_c = object.cid) !== null && _c !== void 0 ? _c : '';
5376
+ message.layers = ((_d = object.layers) === null || _d === void 0 ? void 0 : _d.map(e => VideoLayer.fromPartial(e))) || [];
5283
5377
  return message;
5284
5378
  }
5285
5379
 
@@ -6179,7 +6273,8 @@ function createBaseClientConfiguration() {
6179
6273
  return {
6180
6274
  video: undefined,
6181
6275
  screen: undefined,
6182
- resumeConnection: 0
6276
+ resumeConnection: 0,
6277
+ disabledCodecs: undefined
6183
6278
  };
6184
6279
  }
6185
6280
 
@@ -6199,6 +6294,10 @@ const ClientConfiguration = {
6199
6294
  writer.uint32(24).int32(message.resumeConnection);
6200
6295
  }
6201
6296
 
6297
+ if (message.disabledCodecs !== undefined) {
6298
+ DisabledCodecs.encode(message.disabledCodecs, writer.uint32(34).fork()).ldelim();
6299
+ }
6300
+
6202
6301
  return writer;
6203
6302
  },
6204
6303
 
@@ -6223,6 +6322,10 @@ const ClientConfiguration = {
6223
6322
  message.resumeConnection = reader.int32();
6224
6323
  break;
6225
6324
 
6325
+ case 4:
6326
+ message.disabledCodecs = DisabledCodecs.decode(reader, reader.uint32());
6327
+ break;
6328
+
6226
6329
  default:
6227
6330
  reader.skipType(tag & 7);
6228
6331
  break;
@@ -6236,7 +6339,8 @@ const ClientConfiguration = {
6236
6339
  return {
6237
6340
  video: isSet$1(object.video) ? VideoConfiguration.fromJSON(object.video) : undefined,
6238
6341
  screen: isSet$1(object.screen) ? VideoConfiguration.fromJSON(object.screen) : undefined,
6239
- resumeConnection: isSet$1(object.resumeConnection) ? clientConfigSettingFromJSON(object.resumeConnection) : 0
6342
+ resumeConnection: isSet$1(object.resumeConnection) ? clientConfigSettingFromJSON(object.resumeConnection) : 0,
6343
+ disabledCodecs: isSet$1(object.disabledCodecs) ? DisabledCodecs.fromJSON(object.disabledCodecs) : undefined
6240
6344
  };
6241
6345
  },
6242
6346
 
@@ -6245,6 +6349,7 @@ const ClientConfiguration = {
6245
6349
  message.video !== undefined && (obj.video = message.video ? VideoConfiguration.toJSON(message.video) : undefined);
6246
6350
  message.screen !== undefined && (obj.screen = message.screen ? VideoConfiguration.toJSON(message.screen) : undefined);
6247
6351
  message.resumeConnection !== undefined && (obj.resumeConnection = clientConfigSettingToJSON(message.resumeConnection));
6352
+ message.disabledCodecs !== undefined && (obj.disabledCodecs = message.disabledCodecs ? DisabledCodecs.toJSON(message.disabledCodecs) : undefined);
6248
6353
  return obj;
6249
6354
  },
6250
6355
 
@@ -6255,6 +6360,7 @@ const ClientConfiguration = {
6255
6360
  message.video = object.video !== undefined && object.video !== null ? VideoConfiguration.fromPartial(object.video) : undefined;
6256
6361
  message.screen = object.screen !== undefined && object.screen !== null ? VideoConfiguration.fromPartial(object.screen) : undefined;
6257
6362
  message.resumeConnection = (_a = object.resumeConnection) !== null && _a !== void 0 ? _a : 0;
6363
+ message.disabledCodecs = object.disabledCodecs !== undefined && object.disabledCodecs !== null ? DisabledCodecs.fromPartial(object.disabledCodecs) : undefined;
6258
6364
  return message;
6259
6365
  }
6260
6366
 
@@ -6321,6 +6427,73 @@ const VideoConfiguration = {
6321
6427
 
6322
6428
  };
6323
6429
 
6430
+ function createBaseDisabledCodecs() {
6431
+ return {
6432
+ codecs: []
6433
+ };
6434
+ }
6435
+
6436
+ const DisabledCodecs = {
6437
+ encode(message) {
6438
+ let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : minimal.Writer.create();
6439
+
6440
+ for (const v of message.codecs) {
6441
+ Codec.encode(v, writer.uint32(10).fork()).ldelim();
6442
+ }
6443
+
6444
+ return writer;
6445
+ },
6446
+
6447
+ decode(input, length) {
6448
+ const reader = input instanceof minimal.Reader ? input : new minimal.Reader(input);
6449
+ let end = length === undefined ? reader.len : reader.pos + length;
6450
+ const message = createBaseDisabledCodecs();
6451
+
6452
+ while (reader.pos < end) {
6453
+ const tag = reader.uint32();
6454
+
6455
+ switch (tag >>> 3) {
6456
+ case 1:
6457
+ message.codecs.push(Codec.decode(reader, reader.uint32()));
6458
+ break;
6459
+
6460
+ default:
6461
+ reader.skipType(tag & 7);
6462
+ break;
6463
+ }
6464
+ }
6465
+
6466
+ return message;
6467
+ },
6468
+
6469
+ fromJSON(object) {
6470
+ return {
6471
+ codecs: Array.isArray(object === null || object === void 0 ? void 0 : object.codecs) ? object.codecs.map(e => Codec.fromJSON(e)) : []
6472
+ };
6473
+ },
6474
+
6475
+ toJSON(message) {
6476
+ const obj = {};
6477
+
6478
+ if (message.codecs) {
6479
+ obj.codecs = message.codecs.map(e => e ? Codec.toJSON(e) : undefined);
6480
+ } else {
6481
+ obj.codecs = [];
6482
+ }
6483
+
6484
+ return obj;
6485
+ },
6486
+
6487
+ fromPartial(object) {
6488
+ var _a;
6489
+
6490
+ const message = createBaseDisabledCodecs();
6491
+ message.codecs = ((_a = object.codecs) === null || _a === void 0 ? void 0 : _a.map(e => Codec.fromPartial(e))) || [];
6492
+ return message;
6493
+ }
6494
+
6495
+ };
6496
+
6324
6497
  var globalThis$1 = (() => {
6325
6498
  if (typeof globalThis$1 !== 'undefined') return globalThis$1;
6326
6499
  if (typeof self !== 'undefined') return self;
@@ -6346,9 +6519,11 @@ const btoa = globalThis$1.btoa || (bin => globalThis$1.Buffer.from(bin, 'binary'
6346
6519
 
6347
6520
  function base64FromBytes(arr) {
6348
6521
  const bin = [];
6349
- arr.forEach(byte => {
6522
+
6523
+ for (const byte of arr) {
6350
6524
  bin.push(String.fromCharCode(byte));
6351
- });
6525
+ }
6526
+
6352
6527
  return btoa(bin.join(''));
6353
6528
  }
6354
6529
 
@@ -8033,7 +8208,8 @@ const UpdateTrackSettings = {
8033
8208
 
8034
8209
  function createBaseLeaveRequest() {
8035
8210
  return {
8036
- canReconnect: false
8211
+ canReconnect: false,
8212
+ reason: 0
8037
8213
  };
8038
8214
  }
8039
8215
 
@@ -8045,6 +8221,10 @@ const LeaveRequest = {
8045
8221
  writer.uint32(8).bool(message.canReconnect);
8046
8222
  }
8047
8223
 
8224
+ if (message.reason !== 0) {
8225
+ writer.uint32(16).int32(message.reason);
8226
+ }
8227
+
8048
8228
  return writer;
8049
8229
  },
8050
8230
 
@@ -8061,6 +8241,10 @@ const LeaveRequest = {
8061
8241
  message.canReconnect = reader.bool();
8062
8242
  break;
8063
8243
 
8244
+ case 2:
8245
+ message.reason = reader.int32();
8246
+ break;
8247
+
8064
8248
  default:
8065
8249
  reader.skipType(tag & 7);
8066
8250
  break;
@@ -8072,21 +8256,24 @@ const LeaveRequest = {
8072
8256
 
8073
8257
  fromJSON(object) {
8074
8258
  return {
8075
- canReconnect: isSet(object.canReconnect) ? Boolean(object.canReconnect) : false
8259
+ canReconnect: isSet(object.canReconnect) ? Boolean(object.canReconnect) : false,
8260
+ reason: isSet(object.reason) ? disconnectReasonFromJSON(object.reason) : 0
8076
8261
  };
8077
8262
  },
8078
8263
 
8079
8264
  toJSON(message) {
8080
8265
  const obj = {};
8081
8266
  message.canReconnect !== undefined && (obj.canReconnect = message.canReconnect);
8267
+ message.reason !== undefined && (obj.reason = disconnectReasonToJSON(message.reason));
8082
8268
  return obj;
8083
8269
  },
8084
8270
 
8085
8271
  fromPartial(object) {
8086
- var _a;
8272
+ var _a, _b;
8087
8273
 
8088
8274
  const message = createBaseLeaveRequest();
8089
8275
  message.canReconnect = (_a = object.canReconnect) !== null && _a !== void 0 ? _a : false;
8276
+ message.reason = (_b = object.reason) !== null && _b !== void 0 ? _b : 0;
8090
8277
  return message;
8091
8278
  }
8092
8279
 
@@ -10002,6 +10189,8 @@ var TrackEvent;
10002
10189
  TrackEvent["Muted"] = "muted";
10003
10190
  TrackEvent["Unmuted"] = "unmuted";
10004
10191
  TrackEvent["Ended"] = "ended";
10192
+ TrackEvent["Subscribed"] = "subscribed";
10193
+ TrackEvent["Unsubscribed"] = "unsubscribed";
10005
10194
  /** @internal */
10006
10195
 
10007
10196
  TrackEvent["UpdateSettings"] = "updateSettings";
@@ -10044,6 +10233,12 @@ var TrackEvent;
10044
10233
  */
10045
10234
 
10046
10235
  TrackEvent["UpstreamResumed"] = "upstreamResumed";
10236
+ /**
10237
+ * @internal
10238
+ * Fires on RemoteTrackPublication
10239
+ */
10240
+
10241
+ TrackEvent["SubscriptionPermissionChanged"] = "subscriptionPermissionChanged";
10047
10242
  })(TrackEvent || (TrackEvent = {}));
10048
10243
 
10049
10244
  const monitorFrequency = 2000;
@@ -10070,7 +10265,7 @@ function computeBitrate(currentStats, prevStats) {
10070
10265
  return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp);
10071
10266
  }
10072
10267
 
10073
- var version$1 = "1.1.8";
10268
+ var version$1 = "1.2.1";
10074
10269
 
10075
10270
  const version = version$1;
10076
10271
  const protocolVersion = 8;
@@ -10190,6 +10385,178 @@ class Future {
10190
10385
 
10191
10386
  }
10192
10387
 
10388
+ class Queue {
10389
+ /**
10390
+ * @class Queue
10391
+ *
10392
+ * Priority queue with rate limiting<br>
10393
+ * See the medium article:<br>
10394
+ * https://mmomtchev.medium.com/parallelizing-download-loops-in-js-with-async-await-queue-670420880cd6
10395
+ *
10396
+ * @param {number} [_maxConcurrent=1] Number of tasks allowed to run simultaneously
10397
+ * @param {number} [_minCycle=0] Minimum number of milliseconds between two consecutive tasks
10398
+ */
10399
+ constructor(_maxConcurrent, _minCycle) {
10400
+ this.maxConcurrent = _maxConcurrent || 1;
10401
+ this.minCycle = _minCycle || 0;
10402
+ this.queueRunning = [];
10403
+ this.queueWaiting = {};
10404
+ this.lastRun = 0;
10405
+ }
10406
+ /** @private */
10407
+
10408
+
10409
+ dequeue(hash) {
10410
+ const q = this.queueRunning;
10411
+ const idx = q.findIndex(x => x.hash === hash);
10412
+ if (idx == -1) throw 'queue desync';
10413
+ const o = q[idx];
10414
+ q.splice(idx, 1);
10415
+ return o;
10416
+ }
10417
+ /** @private */
10418
+
10419
+
10420
+ getFirstWaiting() {
10421
+ for (let p of Object.keys(this.queueWaiting).sort((a, b) => a - b)) if (this.queueWaiting[p] !== undefined && this.queueWaiting[p].length > 0) return this.queueWaiting[p];
10422
+
10423
+ return undefined;
10424
+ }
10425
+ /**
10426
+ * Signal that the task `hash` has finished.<br>
10427
+ * Frees its slot in the queue
10428
+ *
10429
+ * @method end
10430
+ * @param {any} hash Unique hash identifying the task, Symbol() works very well
10431
+ */
10432
+
10433
+
10434
+ end(hash) {
10435
+ const me = this.dequeue(hash);
10436
+ me.resolve();
10437
+ /* Choose the next task to run and unblock its promise */
10438
+
10439
+ const q = this.getFirstWaiting();
10440
+
10441
+ if (q !== undefined) {
10442
+ const next = q.shift();
10443
+ next.resolve();
10444
+ }
10445
+ }
10446
+ /**
10447
+ * Wait for a slot in the queue
10448
+ *
10449
+ * @method wait
10450
+ * @param {any} hash Unique hash identifying the task
10451
+ * @param {number} [priority=0] Optional priority, -1 is higher priority than 1
10452
+ * @return {Promise<void>} Resolved when the task is ready to run
10453
+ */
10454
+
10455
+
10456
+ async wait(hash, _priority) {
10457
+ const priority = _priority === undefined ? 0 : _priority;
10458
+ /* Us on the queue */
10459
+
10460
+ let me = {
10461
+ hash,
10462
+ priority
10463
+ };
10464
+ /* Create priorities on the fly */
10465
+
10466
+ if (this.queueWaiting[priority] == undefined) this.queueWaiting[priority] = [];
10467
+ /* Are we allowed to run? */
10468
+
10469
+ if (this.queueRunning.length >= this.maxConcurrent) {
10470
+ /* This promise will be unlocked from the outside */
10471
+
10472
+ /* and it cannot reject */
10473
+ me.promise = new Promise(resolve => {
10474
+ me.resolve = resolve;
10475
+ });
10476
+ /* Get in the line */
10477
+
10478
+ this.queueWaiting[priority].push(me);
10479
+ await me.promise;
10480
+ }
10481
+
10482
+ this.queueRunning.push(me);
10483
+ me.promise = new Promise(resolve => {
10484
+ me.resolve = resolve;
10485
+ });
10486
+ /* Wait if it is too soon */
10487
+
10488
+ while (Date.now() - this.lastRun < this.minCycle) {
10489
+ await new Promise(resolve => setTimeout(resolve, this.minCycle - Date.now() + this.lastRun));
10490
+ }
10491
+
10492
+ this.lastRun = Date.now();
10493
+ }
10494
+ /**
10495
+ * Run a job (equivalent to calling Queue.wait(), fn() and then Queue.end())<br>
10496
+ * fn can be both synchronous or asynchronous function
10497
+ *
10498
+ * @method run
10499
+ * @param {Function} fn The job
10500
+ * @param {number} [priority=0] Optional priority, -1 is higher priority than 1
10501
+ * @return {Promise<any>} Resolved when the task has finished with the return value of fn
10502
+ */
10503
+
10504
+
10505
+ run(job, _priority) {
10506
+ const priority = _priority === undefined ? 0 : _priority;
10507
+ const id = Symbol();
10508
+ return this.wait(id, priority).then(() => job()).finally(() => {
10509
+ this.end(id);
10510
+ });
10511
+ }
10512
+ /**
10513
+ * @interface QueueStats {running: number, waiting: number, last: number}
10514
+ */
10515
+
10516
+ /**
10517
+ * Return the number of running and waiting jobs
10518
+ *
10519
+ * @method stat
10520
+ * @return {QueueStats} running, waiting, last
10521
+ */
10522
+
10523
+
10524
+ stat() {
10525
+ return {
10526
+ running: this.queueRunning.length,
10527
+ waiting: Object.keys(this.queueWaiting).reduce((t, x) => t += this.queueWaiting[x].length, 0),
10528
+ last: this.lastRun
10529
+ };
10530
+ }
10531
+ /**
10532
+ * Returns a promise that resolves when the queue is empty
10533
+ *
10534
+ * @method flush
10535
+ * @return {Promise<void>}
10536
+ */
10537
+
10538
+
10539
+ async flush() {
10540
+ /* Aways wait on the lowest priority in the queue */
10541
+ while (this.stat().waiting > 0) {
10542
+ for (let p of Object.keys(this.queueWaiting).sort((a, b) => b - a)) {
10543
+ const qp = this.queueWaiting[p];
10544
+
10545
+ if (qp !== undefined && qp.length > 0) {
10546
+ await qp[qp.length - 1].promise;
10547
+ }
10548
+ }
10549
+ }
10550
+ /* And then finish on the running queue */
10551
+
10552
+
10553
+ while (this.queueRunning.length > 0) {
10554
+ await Promise.allSettled(this.queueRunning.map(x => x.promise));
10555
+ }
10556
+ }
10557
+
10558
+ }
10559
+
10193
10560
  const defaultId = 'default';
10194
10561
  class DeviceManager {
10195
10562
  static getInstance() {
@@ -11098,6 +11465,7 @@ class LocalTrack extends Track {
11098
11465
  this.reacquireTrack = false;
11099
11466
  this.wasMuted = false;
11100
11467
  this.providedByUser = userProvidedTrack;
11468
+ this.muteQueue = new Queue();
11101
11469
  }
11102
11470
 
11103
11471
  get id() {
@@ -11178,7 +11546,9 @@ class LocalTrack extends Track {
11178
11546
  // 'A MediaStreamTrack ended due to a capture failure`
11179
11547
 
11180
11548
 
11181
- this._mediaStreamTrack.stop();
11549
+ if (!this.providedByUser) {
11550
+ this._mediaStreamTrack.stop();
11551
+ }
11182
11552
 
11183
11553
  track.addEventListener('ended', this.handleEnded);
11184
11554
  livekitLogger.debug('replace MediaStreamTrack');
@@ -11188,6 +11558,7 @@ class LocalTrack extends Track {
11188
11558
  }
11189
11559
 
11190
11560
  this._mediaStreamTrack = track;
11561
+ await this.resumeUpstream();
11191
11562
  this.attachedElements.forEach(el => {
11192
11563
  attachToElement(track, el);
11193
11564
  });
@@ -11237,6 +11608,7 @@ class LocalTrack extends Track {
11237
11608
  }
11238
11609
 
11239
11610
  this._mediaStreamTrack = newTrack;
11611
+ await this.resumeUpstream();
11240
11612
  this.attachedElements.forEach(el => {
11241
11613
  attachToElement(newTrack, el);
11242
11614
  });
@@ -11246,6 +11618,8 @@ class LocalTrack extends Track {
11246
11618
  }
11247
11619
 
11248
11620
  setTrackMuted(muted) {
11621
+ livekitLogger.debug("setting ".concat(this.kind, " track ").concat(muted ? 'muted' : 'unmuted'));
11622
+
11249
11623
  if (this.isMuted === muted) {
11250
11624
  return;
11251
11625
  }
@@ -11279,34 +11653,38 @@ class LocalTrack extends Track {
11279
11653
  }
11280
11654
 
11281
11655
  async pauseUpstream() {
11282
- if (this._isUpstreamPaused === true) {
11283
- return;
11284
- }
11656
+ this.muteQueue.run(async () => {
11657
+ if (this._isUpstreamPaused === true) {
11658
+ return;
11659
+ }
11285
11660
 
11286
- if (!this.sender) {
11287
- livekitLogger.warn('unable to pause upstream for an unpublished track');
11288
- return;
11289
- }
11661
+ if (!this.sender) {
11662
+ livekitLogger.warn('unable to pause upstream for an unpublished track');
11663
+ return;
11664
+ }
11290
11665
 
11291
- this._isUpstreamPaused = true;
11292
- this.emit(TrackEvent.UpstreamPaused, this);
11293
- const emptyTrack = this.kind === Track.Kind.Audio ? getEmptyAudioStreamTrack() : getEmptyVideoStreamTrack();
11294
- await this.sender.replaceTrack(emptyTrack);
11666
+ this._isUpstreamPaused = true;
11667
+ this.emit(TrackEvent.UpstreamPaused, this);
11668
+ const emptyTrack = this.kind === Track.Kind.Audio ? getEmptyAudioStreamTrack() : getEmptyVideoStreamTrack();
11669
+ await this.sender.replaceTrack(emptyTrack);
11670
+ });
11295
11671
  }
11296
11672
 
11297
11673
  async resumeUpstream() {
11298
- if (this._isUpstreamPaused === false) {
11299
- return;
11300
- }
11674
+ this.muteQueue.run(async () => {
11675
+ if (this._isUpstreamPaused === false) {
11676
+ return;
11677
+ }
11301
11678
 
11302
- if (!this.sender) {
11303
- livekitLogger.warn('unable to resume upstream for an unpublished track');
11304
- return;
11305
- }
11679
+ if (!this.sender) {
11680
+ livekitLogger.warn('unable to resume upstream for an unpublished track');
11681
+ return;
11682
+ }
11306
11683
 
11307
- this._isUpstreamPaused = false;
11308
- this.emit(TrackEvent.UpstreamResumed, this);
11309
- await this.sender.replaceTrack(this._mediaStreamTrack);
11684
+ this._isUpstreamPaused = false;
11685
+ this.emit(TrackEvent.UpstreamResumed, this);
11686
+ await this.sender.replaceTrack(this._mediaStreamTrack);
11687
+ });
11310
11688
  }
11311
11689
 
11312
11690
  }
@@ -11464,24 +11842,28 @@ class LocalAudioTrack extends LocalTrack {
11464
11842
  }
11465
11843
 
11466
11844
  async mute() {
11467
- // disabled special handling as it will cause BT headsets to switch communication modes
11468
- if (this.source === Track.Source.Microphone && this.stopOnMute) {
11469
- livekitLogger.debug('stopping mic track'); // also stop the track, so that microphone indicator is turned off
11845
+ await this.muteQueue.run(async () => {
11846
+ // disabled special handling as it will cause BT headsets to switch communication modes
11847
+ if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
11848
+ livekitLogger.debug('stopping mic track'); // also stop the track, so that microphone indicator is turned off
11470
11849
 
11471
- this._mediaStreamTrack.stop();
11472
- }
11850
+ this._mediaStreamTrack.stop();
11851
+ }
11473
11852
 
11474
- await super.mute();
11853
+ await super.mute();
11854
+ });
11475
11855
  return this;
11476
11856
  }
11477
11857
 
11478
11858
  async unmute() {
11479
- if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
11480
- livekitLogger.debug('reacquiring mic track');
11481
- await this.restartTrack();
11482
- }
11859
+ await this.muteQueue.run(async () => {
11860
+ if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
11861
+ livekitLogger.debug('reacquiring mic track');
11862
+ await this.restartTrack();
11863
+ }
11483
11864
 
11484
- await super.unmute();
11865
+ await super.unmute();
11866
+ });
11485
11867
  return this;
11486
11868
  }
11487
11869
 
@@ -11647,23 +12029,27 @@ class LocalVideoTrack extends LocalTrack {
11647
12029
  }
11648
12030
 
11649
12031
  async mute() {
11650
- if (this.source === Track.Source.Camera) {
11651
- livekitLogger.debug('stopping camera track'); // also stop the track, so that camera indicator is turned off
12032
+ await this.muteQueue.run(async () => {
12033
+ if (this.source === Track.Source.Camera && !this.isUserProvided) {
12034
+ livekitLogger.debug('stopping camera track'); // also stop the track, so that camera indicator is turned off
11652
12035
 
11653
- this._mediaStreamTrack.stop();
11654
- }
12036
+ this._mediaStreamTrack.stop();
12037
+ }
11655
12038
 
11656
- await super.mute();
12039
+ await super.mute();
12040
+ });
11657
12041
  return this;
11658
12042
  }
11659
12043
 
11660
12044
  async unmute() {
11661
- if (this.source === Track.Source.Camera && !this.isUserProvided) {
11662
- livekitLogger.debug('reacquiring camera track');
11663
- await this.restartTrack();
11664
- }
12045
+ await this.muteQueue.run(async () => {
12046
+ if (this.source === Track.Source.Camera && !this.isUserProvided) {
12047
+ livekitLogger.debug('reacquiring camera track');
12048
+ await this.restartTrack();
12049
+ }
11665
12050
 
11666
- await super.unmute();
12051
+ await super.unmute();
12052
+ });
11667
12053
  return this;
11668
12054
  }
11669
12055
 
@@ -11980,6 +12366,7 @@ class RemoteTrack extends Track {
11980
12366
  setMuted(muted) {
11981
12367
  if (this.isMuted !== muted) {
11982
12368
  this.isMuted = muted;
12369
+ this._mediaStreamTrack.enabled = !muted;
11983
12370
  this.emit(muted ? TrackEvent.Muted : TrackEvent.Unmuted, this);
11984
12371
  }
11985
12372
  }
@@ -13068,7 +13455,7 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
13068
13455
  encodings.push({
13069
13456
  rid: videoRids[2 - i],
13070
13457
  scaleResolutionDownBy: 2 ** i,
13071
- maxBitrate: videoEncoding ? videoEncoding.maxBitrate / 2 ** i : 0,
13458
+ maxBitrate: videoEncoding ? videoEncoding.maxBitrate / 3 ** i : 0,
13072
13459
 
13073
13460
  /* @ts-ignore */
13074
13461
  maxFramerate: original.encoding.maxFramerate,
@@ -13235,7 +13622,7 @@ class RemoteTrackPublication extends TrackPublication {
13235
13622
  super(...arguments);
13236
13623
  /** @internal */
13237
13624
 
13238
- this._allowed = true;
13625
+ this.allowed = true;
13239
13626
  this.disabled = false;
13240
13627
  this.currentVideoQuality = VideoQuality.HIGH;
13241
13628
 
@@ -13267,7 +13654,10 @@ class RemoteTrackPublication extends TrackPublication {
13267
13654
 
13268
13655
 
13269
13656
  setSubscribed(subscribed) {
13270
- this.subscribed = subscribed;
13657
+ this.subscribed = subscribed; // reset allowed status when desired subscription state changes
13658
+ // server will notify client via signal message if it's not allowed
13659
+
13660
+ this.allowed = true;
13271
13661
  const sub = {
13272
13662
  trackSids: [this.trackSid],
13273
13663
  subscribe: this.subscribed,
@@ -13283,11 +13673,11 @@ class RemoteTrackPublication extends TrackPublication {
13283
13673
 
13284
13674
  get subscriptionStatus() {
13285
13675
  if (this.subscribed === false || !super.isSubscribed) {
13286
- return TrackPublication.SubscriptionStatus.Unsubscribed;
13287
- }
13676
+ if (!this.allowed) {
13677
+ return TrackPublication.SubscriptionStatus.NotAllowed;
13678
+ }
13288
13679
 
13289
- if (!this._allowed) {
13290
- return TrackPublication.SubscriptionStatus.NotAllowed;
13680
+ return TrackPublication.SubscriptionStatus.Unsubscribed;
13291
13681
  }
13292
13682
 
13293
13683
  return TrackPublication.SubscriptionStatus.Subscribed;
@@ -13302,10 +13692,6 @@ class RemoteTrackPublication extends TrackPublication {
13302
13692
  return false;
13303
13693
  }
13304
13694
 
13305
- if (!this._allowed) {
13306
- return false;
13307
- }
13308
-
13309
13695
  return super.isSubscribed;
13310
13696
  }
13311
13697
 
@@ -13373,11 +13759,14 @@ class RemoteTrackPublication extends TrackPublication {
13373
13759
 
13374
13760
 
13375
13761
  setTrack(track) {
13376
- if (this.track) {
13762
+ const prevStatus = this.subscriptionStatus;
13763
+ const prevTrack = this.track;
13764
+
13765
+ if (prevTrack) {
13377
13766
  // unregister listener
13378
- this.track.off(TrackEvent.VideoDimensionsChanged, this.handleVideoDimensionsChange);
13379
- this.track.off(TrackEvent.VisibilityChanged, this.handleVisibilityChange);
13380
- this.track.off(TrackEvent.Ended, this.handleEnded);
13767
+ prevTrack.off(TrackEvent.VideoDimensionsChanged, this.handleVideoDimensionsChange);
13768
+ prevTrack.off(TrackEvent.VisibilityChanged, this.handleVisibilityChange);
13769
+ prevTrack.off(TrackEvent.Ended, this.handleEnded);
13381
13770
  }
13382
13771
 
13383
13772
  super.setTrack(track);
@@ -13388,6 +13777,25 @@ class RemoteTrackPublication extends TrackPublication {
13388
13777
  track.on(TrackEvent.VisibilityChanged, this.handleVisibilityChange);
13389
13778
  track.on(TrackEvent.Ended, this.handleEnded);
13390
13779
  }
13780
+
13781
+ this.emitSubscriptionUpdateIfChanged(prevStatus);
13782
+
13783
+ if (!!track !== !!prevTrack) {
13784
+ // when undefined status changes, there's a subscription changed event
13785
+ if (track) {
13786
+ this.emit(TrackEvent.Subscribed, track);
13787
+ } else {
13788
+ this.emit(TrackEvent.Unsubscribed, prevTrack);
13789
+ }
13790
+ }
13791
+ }
13792
+ /** @internal */
13793
+
13794
+
13795
+ setAllowed(allowed) {
13796
+ const prevStatus = this.subscriptionStatus;
13797
+ this.allowed = allowed;
13798
+ this.emitSubscriptionUpdateIfChanged(prevStatus);
13391
13799
  }
13392
13800
  /** @internal */
13393
13801
 
@@ -13400,6 +13808,16 @@ class RemoteTrackPublication extends TrackPublication {
13400
13808
  (_a = this.track) === null || _a === void 0 ? void 0 : _a.setMuted(info.muted);
13401
13809
  }
13402
13810
 
13811
+ emitSubscriptionUpdateIfChanged(previousStatus) {
13812
+ const currentStatus = this.subscriptionStatus;
13813
+
13814
+ if (previousStatus === currentStatus) {
13815
+ return;
13816
+ }
13817
+
13818
+ this.emit(TrackEvent.SubscriptionPermissionChanged, currentStatus, previousStatus);
13819
+ }
13820
+
13403
13821
  isManualOperationAllowed() {
13404
13822
  if (this.isAdaptiveStream) {
13405
13823
  livekitLogger.warn('adaptive stream is enabled, cannot change track settings', {
@@ -13474,8 +13892,14 @@ class RemoteParticipant extends Participant {
13474
13892
  });
13475
13893
  this.signalClient.sendUpdateSubscription(sub);
13476
13894
  });
13477
- publication.on(TrackEvent.Ended, track => {
13478
- this.emit(ParticipantEvent.TrackUnsubscribed, track, publication);
13895
+ publication.on(TrackEvent.SubscriptionPermissionChanged, status => {
13896
+ this.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, publication, status);
13897
+ });
13898
+ publication.on(TrackEvent.Subscribed, track => {
13899
+ this.emit(ParticipantEvent.TrackSubscribed, track, publication);
13900
+ });
13901
+ publication.on(TrackEvent.Unsubscribed, previousTrack => {
13902
+ this.emit(ParticipantEvent.TrackUnsubscribed, previousTrack, publication);
13479
13903
  });
13480
13904
  }
13481
13905
 
@@ -13576,15 +14000,12 @@ class RemoteParticipant extends Participant {
13576
14000
  track.isMuted = publication.isMuted;
13577
14001
  track.setMediaStream(mediaStream);
13578
14002
  track.start();
13579
- publication.setTrack(track); // subscription means participant has permissions to subscribe
13580
-
13581
- publication._allowed = true; // set participant volume on new microphone tracks
14003
+ publication.setTrack(track); // set participant volume on new microphone tracks
13582
14004
 
13583
14005
  if (this.volume !== undefined && track instanceof RemoteAudioTrack && track.source === Track.Source.Microphone) {
13584
14006
  track.setVolume(this.volume);
13585
14007
  }
13586
14008
 
13587
- this.emit(ParticipantEvent.TrackSubscribed, track, publication);
13588
14009
  return publication;
13589
14010
  }
13590
14011
  /** @internal */
@@ -13672,15 +14093,8 @@ class RemoteParticipant extends Participant {
13672
14093
  } = publication;
13673
14094
 
13674
14095
  if (track) {
13675
- const {
13676
- isSubscribed
13677
- } = publication;
13678
14096
  track.stop();
13679
- publication.setTrack(undefined); // always send unsubscribed, since apps may rely on this
13680
-
13681
- if (isSubscribed) {
13682
- this.emit(ParticipantEvent.TrackUnsubscribed, track, publication);
13683
- }
14097
+ publication.setTrack(undefined);
13684
14098
  }
13685
14099
 
13686
14100
  if (sendUnpublish) {
@@ -13801,11 +14215,47 @@ class LocalParticipant extends Participant {
13801
14215
  this.unpublishTrack(track.track);
13802
14216
  };
13803
14217
 
13804
- this.handleTrackEnded = track => {
13805
- livekitLogger.debug('unpublishing local track due to TrackEnded', {
13806
- track: track.sid
13807
- });
13808
- this.unpublishTrack(track);
14218
+ this.handleTrackEnded = async track => {
14219
+ if (track.source === Track.Source.ScreenShare || track.source === Track.Source.ScreenShareAudio) {
14220
+ livekitLogger.debug('unpublishing local track due to TrackEnded', {
14221
+ track: track.sid
14222
+ });
14223
+ this.unpublishTrack(track);
14224
+ } else if (track.isUserProvided) {
14225
+ await track.pauseUpstream();
14226
+ } else if (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) {
14227
+ try {
14228
+ if (isWeb()) {
14229
+ try {
14230
+ const currentPermissions = await (navigator === null || navigator === void 0 ? void 0 : navigator.permissions.query({
14231
+ // the permission query for camera and microphone currently not supported in Safari and Firefox
14232
+ // @ts-ignore
14233
+ name: track.source === Track.Source.Camera ? 'camera' : 'microphone'
14234
+ }));
14235
+
14236
+ if (currentPermissions && currentPermissions.state === 'denied') {
14237
+ livekitLogger.warn("user has revoked access to ".concat(track.source)); // detect granted change after permissions were denied to try and resume then
14238
+
14239
+ currentPermissions.onchange = () => {
14240
+ if (currentPermissions.state !== 'denied') {
14241
+ track.restartTrack();
14242
+ currentPermissions.onchange = null;
14243
+ }
14244
+ };
14245
+
14246
+ throw new Error('GetUserMedia Permission denied');
14247
+ }
14248
+ } catch (e) {// permissions query fails for firefox, we continue and try to restart the track
14249
+ }
14250
+ }
14251
+
14252
+ livekitLogger.debug('track ended, attempting to use a different device');
14253
+ await track.restartTrack();
14254
+ } catch (e) {
14255
+ livekitLogger.warn("could not restart track, pausing upstream instead");
14256
+ await track.pauseUpstream();
14257
+ }
14258
+ }
13809
14259
  };
13810
14260
 
13811
14261
  this.audioTracks = new Map();
@@ -13864,8 +14314,8 @@ class LocalParticipant extends Participant {
13864
14314
  */
13865
14315
 
13866
14316
 
13867
- setCameraEnabled(enabled, options) {
13868
- return this.setTrackEnabled(Track.Source.Camera, enabled, options);
14317
+ setCameraEnabled(enabled, options, publishOptions) {
14318
+ return this.setTrackEnabled(Track.Source.Camera, enabled, options, publishOptions);
13869
14319
  }
13870
14320
  /**
13871
14321
  * Enable or disable a participant's microphone track.
@@ -13875,8 +14325,8 @@ class LocalParticipant extends Participant {
13875
14325
  */
13876
14326
 
13877
14327
 
13878
- setMicrophoneEnabled(enabled, options) {
13879
- return this.setTrackEnabled(Track.Source.Microphone, enabled, options);
14328
+ setMicrophoneEnabled(enabled, options, publishOptions) {
14329
+ return this.setTrackEnabled(Track.Source.Microphone, enabled, options, publishOptions);
13880
14330
  }
13881
14331
  /**
13882
14332
  * Start or stop sharing a participant's screen
@@ -13884,8 +14334,8 @@ class LocalParticipant extends Participant {
13884
14334
  */
13885
14335
 
13886
14336
 
13887
- setScreenShareEnabled(enabled, options) {
13888
- return this.setTrackEnabled(Track.Source.ScreenShare, enabled, options);
14337
+ setScreenShareEnabled(enabled, options, publishOptions) {
14338
+ return this.setTrackEnabled(Track.Source.ScreenShare, enabled, options, publishOptions);
13889
14339
  }
13890
14340
  /** @internal */
13891
14341
 
@@ -13901,7 +14351,7 @@ class LocalParticipant extends Participant {
13901
14351
  return changed;
13902
14352
  }
13903
14353
 
13904
- async setTrackEnabled(source, enabled, options) {
14354
+ async setTrackEnabled(source, enabled, options, publishOptions) {
13905
14355
  var _a, _b;
13906
14356
 
13907
14357
  livekitLogger.debug('setTrackEnabled', {
@@ -13951,7 +14401,7 @@ class LocalParticipant extends Participant {
13951
14401
  const publishPromises = [];
13952
14402
 
13953
14403
  for (const localTrack of localTracks) {
13954
- publishPromises.push(this.publishTrack(localTrack));
14404
+ publishPromises.push(this.publishTrack(localTrack, publishOptions));
13955
14405
  }
13956
14406
 
13957
14407
  const publishedTracks = await Promise.all(publishPromises); // for screen share publications including audio, this will only return the screen share publication, not the screen share audio one
@@ -14131,7 +14581,7 @@ class LocalParticipant extends Participant {
14131
14581
 
14132
14582
 
14133
14583
  async publishTrack(track, options) {
14134
- var _a, _b, _c, _d, _e, _f, _g;
14584
+ var _a, _b, _c, _d, _e, _f, _g, _h;
14135
14585
 
14136
14586
  const opts = _objectSpread2(_objectSpread2({}, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.publishDefaults), options); // convert raw media track into audio or video track
14137
14587
 
@@ -14275,6 +14725,10 @@ class LocalParticipant extends Participant {
14275
14725
  track.codec = opts.videoCodec;
14276
14726
  }
14277
14727
 
14728
+ if (track.codec === 'av1' && encodings && ((_h = encodings[0]) === null || _h === void 0 ? void 0 : _h.maxBitrate)) {
14729
+ this.engine.publisher.setTrackCodecBitrate(req.cid, track.codec, encodings[0].maxBitrate / 1000);
14730
+ }
14731
+
14278
14732
  this.engine.negotiate(); // store RTPSender
14279
14733
 
14280
14734
  track.sender = transceiver.sender;
@@ -14296,7 +14750,7 @@ class LocalParticipant extends Participant {
14296
14750
 
14297
14751
 
14298
14752
  async publishAdditionalCodecForTrack(track, videoCodec, options) {
14299
- var _a, _b, _c, _d, _e;
14753
+ var _a, _b, _c, _d, _e, _f;
14300
14754
 
14301
14755
  const opts = _objectSpread2(_objectSpread2({}, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.publishDefaults), options); // clear scalabilityMode setting for backup codec
14302
14756
 
@@ -14364,6 +14818,11 @@ class LocalParticipant extends Participant {
14364
14818
  const transceiver = await this.engine.publisher.pc.addTransceiver(simulcastTrack.mediaStreamTrack, transceiverInit);
14365
14819
  this.setPreferredCodec(transceiver, track.kind, opts.videoCodec);
14366
14820
  track.setSimulcastTrackSender(opts.videoCodec, transceiver.sender);
14821
+
14822
+ if (videoCodec === 'av1' && ((_f = encodings[0]) === null || _f === void 0 ? void 0 : _f.maxBitrate)) {
14823
+ this.engine.publisher.setTrackCodecBitrate(req.cid, videoCodec, encodings[0].maxBitrate / 1000);
14824
+ }
14825
+
14367
14826
  this.engine.negotiate();
14368
14827
  livekitLogger.debug("published ".concat(opts.videoCodec, " for track ").concat(track.sid), {
14369
14828
  encodings,
@@ -18141,57 +18600,6 @@ adapterFactory({
18141
18600
  window: typeof window === 'undefined' ? undefined : window
18142
18601
  });
18143
18602
 
18144
- class Queue {
18145
- constructor() {
18146
- this.queue = [];
18147
- this.running = false;
18148
- }
18149
-
18150
- enqueue(cb) {
18151
- livekitLogger.trace('enqueuing request to fire later');
18152
- this.queue.push(cb);
18153
- }
18154
-
18155
- dequeue() {
18156
- const evt = this.queue.shift();
18157
- if (evt) evt();
18158
- livekitLogger.trace('firing request from queue');
18159
- }
18160
-
18161
- async run() {
18162
- if (this.running) return;
18163
- livekitLogger.trace('start queue');
18164
- this.running = true;
18165
-
18166
- while (this.running && this.queue.length > 0) {
18167
- this.dequeue();
18168
- }
18169
-
18170
- this.running = false;
18171
- livekitLogger.trace('queue finished');
18172
- }
18173
-
18174
- pause() {
18175
- livekitLogger.trace('pausing queue');
18176
- this.running = false;
18177
- }
18178
-
18179
- reset() {
18180
- livekitLogger.trace('resetting queue');
18181
- this.running = false;
18182
- this.queue = [];
18183
- }
18184
-
18185
- isRunning() {
18186
- return this.running;
18187
- }
18188
-
18189
- isEmpty() {
18190
- return this.queue.length === 0;
18191
- }
18192
-
18193
- }
18194
-
18195
18603
  const passThroughQueueSignals = ['syncState', 'trickle', 'offer', 'answer', 'simulate', 'leave'];
18196
18604
 
18197
18605
  function canPassThroughQueue(req) {
@@ -18212,6 +18620,7 @@ class SignalClient {
18212
18620
  this.isReconnecting = false;
18213
18621
  this.useJSON = useJSON;
18214
18622
  this.requestQueue = new Queue();
18623
+ this.queuedRequests = [];
18215
18624
  }
18216
18625
 
18217
18626
  async join(url, token, opts, abortSignal) {
@@ -18439,14 +18848,20 @@ class SignalClient {
18439
18848
 
18440
18849
  async sendRequest(req) {
18441
18850
  let fromQueue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
18442
- // capture all requests while reconnecting and put them in a queue.
18443
- // keep order by queueing up new events as long as the queue is not empty
18851
+ // capture all requests while reconnecting and put them in a queue
18444
18852
  // unless the request originates from the queue, then don't enqueue again
18445
18853
  const canQueue = !fromQueue && !canPassThroughQueue(req);
18446
18854
 
18447
- if (canQueue && (this.isReconnecting || !this.requestQueue.isEmpty())) {
18448
- this.requestQueue.enqueue(() => this.sendRequest(req, true));
18855
+ if (canQueue && this.isReconnecting) {
18856
+ this.queuedRequests.push(async () => {
18857
+ await this.sendRequest(req, true);
18858
+ });
18449
18859
  return;
18860
+ } // make sure previously queued requests are being sent first
18861
+
18862
+
18863
+ if (!fromQueue) {
18864
+ await this.requestQueue.flush();
18450
18865
  }
18451
18866
 
18452
18867
  if (this.signalLatency) {
@@ -18544,8 +18959,15 @@ class SignalClient {
18544
18959
  }
18545
18960
 
18546
18961
  setReconnected() {
18962
+ while (this.queuedRequests.length > 0) {
18963
+ const req = this.queuedRequests.shift();
18964
+
18965
+ if (req) {
18966
+ this.requestQueue.run(req);
18967
+ }
18968
+ }
18969
+
18547
18970
  this.isReconnecting = false;
18548
- this.requestQueue.run();
18549
18971
  }
18550
18972
 
18551
18973
  handleWSError(ev) {
@@ -18634,7 +19056,8 @@ class PCTransport {
18634
19056
  constructor(config) {
18635
19057
  this.pendingCandidates = [];
18636
19058
  this.restartingIce = false;
18637
- this.renegotiate = false; // debounced negotiate interface
19059
+ this.renegotiate = false;
19060
+ this.trackBitrates = []; // debounced negotiate interface
18638
19061
 
18639
19062
  this.negotiate = r(() => {
18640
19063
  this.createAndSendOffer();
@@ -18698,11 +19121,38 @@ class PCTransport {
18698
19121
 
18699
19122
 
18700
19123
  livekitLogger.debug('starting to negotiate');
18701
- const offer = await this.pc.createOffer(options);
19124
+ const offer = await this.pc.createOffer(options); // mung sdp for codec bitrate setting that can't apply by sendEncoding
19125
+
19126
+ this.trackBitrates.forEach(trackbr => {
19127
+ var _a;
19128
+
19129
+ let sdp = (_a = offer.sdp) !== null && _a !== void 0 ? _a : '';
19130
+ const sidIndex = sdp.search(new RegExp("msid.* ".concat(trackbr.sid)));
19131
+
19132
+ if (sidIndex < 0) {
19133
+ return;
19134
+ }
19135
+
19136
+ const mlineStart = sdp.substring(0, sidIndex).lastIndexOf('m=');
19137
+ const mlineEnd = sdp.indexOf('m=', sidIndex);
19138
+ const mediaSection = sdp.substring(mlineStart, mlineEnd);
19139
+ const mungedMediaSection = mediaSection.replace(new RegExp("a=rtpmap:(\\d+) ".concat(trackbr.codec, "/\\d+"), 'i'), "$&\r\na=fmtp:$1 x-google-max-bitrate=".concat(trackbr.maxbr));
19140
+ sdp = sdp.substring(0, mlineStart) + mungedMediaSection + sdp.substring(mlineEnd);
19141
+ offer.sdp = sdp;
19142
+ });
19143
+ this.trackBitrates = [];
18702
19144
  await this.pc.setLocalDescription(offer);
18703
19145
  this.onOffer(offer);
18704
19146
  }
18705
19147
 
19148
+ setTrackCodecBitrate(sid, codec, maxbr) {
19149
+ this.trackBitrates.push({
19150
+ sid,
19151
+ codec,
19152
+ maxbr
19153
+ });
19154
+ }
19155
+
18706
19156
  close() {
18707
19157
  this.pc.close();
18708
19158
  }
@@ -19082,23 +19532,9 @@ class RTCEngine extends events.exports.EventEmitter {
19082
19532
  const track = ev.stream.getTracks()[0];
19083
19533
  this.emit(EngineEvent.MediaTrackAdded, track, ev.stream);
19084
19534
  };
19085
- } // data channels
19086
-
19087
-
19088
- this.lossyDC = this.publisher.pc.createDataChannel(lossyDataChannel, {
19089
- // will drop older packets that arrive
19090
- ordered: true,
19091
- maxRetransmits: 0
19092
- });
19093
- this.reliableDC = this.publisher.pc.createDataChannel(reliableDataChannel, {
19094
- ordered: true
19095
- }); // also handle messages over the pub channel, for backwards compatibility
19096
-
19097
- this.lossyDC.onmessage = this.handleDataMessage;
19098
- this.reliableDC.onmessage = this.handleDataMessage; // handle datachannel errors
19535
+ }
19099
19536
 
19100
- this.lossyDC.onerror = this.handleDataError;
19101
- this.reliableDC.onerror = this.handleDataError; // configure signaling client
19537
+ this.createDataChannels(); // configure signaling client
19102
19538
 
19103
19539
  this.client.onAnswer = async sd => {
19104
19540
  if (!this.publisher) {
@@ -19173,7 +19609,7 @@ class RTCEngine extends events.exports.EventEmitter {
19173
19609
  this.fullReconnectOnNext = true;
19174
19610
  this.primaryPC = undefined;
19175
19611
  } else {
19176
- this.emit(EngineEvent.Disconnected);
19612
+ this.emit(EngineEvent.Disconnected, leave === null || leave === void 0 ? void 0 : leave.reason);
19177
19613
  this.close();
19178
19614
  }
19179
19615
 
@@ -19183,6 +19619,39 @@ class RTCEngine extends events.exports.EventEmitter {
19183
19619
  };
19184
19620
  }
19185
19621
 
19622
+ createDataChannels() {
19623
+ if (!this.publisher) {
19624
+ return;
19625
+ } // clear old data channel callbacks if recreate
19626
+
19627
+
19628
+ if (this.lossyDC) {
19629
+ this.lossyDC.onmessage = null;
19630
+ this.lossyDC.onerror = null;
19631
+ }
19632
+
19633
+ if (this.reliableDC) {
19634
+ this.reliableDC.onmessage = null;
19635
+ this.reliableDC.onerror = null;
19636
+ } // create data channels
19637
+
19638
+
19639
+ this.lossyDC = this.publisher.pc.createDataChannel(lossyDataChannel, {
19640
+ // will drop older packets that arrive
19641
+ ordered: true,
19642
+ maxRetransmits: 0
19643
+ });
19644
+ this.reliableDC = this.publisher.pc.createDataChannel(reliableDataChannel, {
19645
+ ordered: true
19646
+ }); // also handle messages over the pub channel, for backwards compatibility
19647
+
19648
+ this.lossyDC.onmessage = this.handleDataMessage;
19649
+ this.reliableDC.onmessage = this.handleDataMessage; // handle datachannel errors
19650
+
19651
+ this.lossyDC.onerror = this.handleDataError;
19652
+ this.reliableDC.onerror = this.handleDataError;
19653
+ }
19654
+
19186
19655
  async restartConnection() {
19187
19656
  var _a, _b;
19188
19657
 
@@ -19222,6 +19691,8 @@ class RTCEngine extends events.exports.EventEmitter {
19222
19691
  }
19223
19692
 
19224
19693
  async resumeConnection() {
19694
+ var _a;
19695
+
19225
19696
  if (!this.url || !this.token) {
19226
19697
  // permanent failure, don't attempt reconnection
19227
19698
  throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
@@ -19254,7 +19725,13 @@ class RTCEngine extends events.exports.EventEmitter {
19254
19725
  }
19255
19726
 
19256
19727
  await this.waitForPCConnected();
19257
- this.client.setReconnected(); // resume success
19728
+ this.client.setReconnected(); // recreate publish datachannel if it's id is null
19729
+ // (for safari https://bugs.webkit.org/show_bug.cgi?id=184688)
19730
+
19731
+ if (((_a = this.reliableDC) === null || _a === void 0 ? void 0 : _a.readyState) === 'open' && this.reliableDC.id === null) {
19732
+ this.createDataChannels();
19733
+ } // resume success
19734
+
19258
19735
 
19259
19736
  this.emit(EngineEvent.Resumed);
19260
19737
  }
@@ -19624,11 +20101,15 @@ class Room extends events.exports.EventEmitter {
19624
20101
  */
19625
20102
 
19626
20103
 
19627
- this.disconnect = function () {
20104
+ this.disconnect = async function () {
19628
20105
  let stopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
19629
20106
 
19630
20107
  var _a, _b;
19631
20108
 
20109
+ livekitLogger.info('disconnect from room', {
20110
+ identity: _this.localParticipant.identity
20111
+ });
20112
+
19632
20113
  if (_this.state === ConnectionState.Connecting) {
19633
20114
  // try aborting pending connection attempt
19634
20115
  livekitLogger.warn('abort connection attempt');
@@ -19638,7 +20119,7 @@ class Room extends events.exports.EventEmitter {
19638
20119
 
19639
20120
 
19640
20121
  if ((_b = _this.engine) === null || _b === void 0 ? void 0 : _b.client.isConnected) {
19641
- _this.engine.client.sendLeave();
20122
+ await _this.engine.client.sendLeave();
19642
20123
  } // close engine (also closes client)
19643
20124
 
19644
20125
 
@@ -19646,7 +20127,7 @@ class Room extends events.exports.EventEmitter {
19646
20127
  _this.engine.close();
19647
20128
  }
19648
20129
 
19649
- _this.handleDisconnect(stopTracks);
20130
+ _this.handleDisconnect(stopTracks, DisconnectReason.CLIENT_INITIATED);
19650
20131
  /* @ts-ignore */
19651
20132
 
19652
20133
 
@@ -19843,9 +20324,7 @@ class Room extends events.exports.EventEmitter {
19843
20324
  return;
19844
20325
  }
19845
20326
 
19846
- pub._allowed = update.allowed;
19847
- participant.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus);
19848
- this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
20327
+ pub.setAllowed(update.allowed);
19849
20328
  };
19850
20329
 
19851
20330
  this.handleDataPacket = (userPacket, kind) => {
@@ -19925,8 +20404,8 @@ class Room extends events.exports.EventEmitter {
19925
20404
  this.engine.client.onConnectionQuality = this.handleConnectionQualityUpdate;
19926
20405
  this.engine.on(EngineEvent.MediaTrackAdded, (mediaTrack, stream, receiver) => {
19927
20406
  this.onTrackAdded(mediaTrack, stream, receiver);
19928
- }).on(EngineEvent.Disconnected, () => {
19929
- this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
20407
+ }).on(EngineEvent.Disconnected, reason => {
20408
+ this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, reason);
19930
20409
  }).on(EngineEvent.ActiveSpeakersUpdate, this.handleActiveSpeakersUpdate).on(EngineEvent.DataPacketReceived, this.handleDataPacket).on(EngineEvent.Resuming, () => {
19931
20410
  if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
19932
20411
  this.emit(RoomEvent.Reconnecting);
@@ -20146,15 +20625,16 @@ class Room extends events.exports.EventEmitter {
20146
20625
  // at that time, ICE connectivity has not been established so the track is not
20147
20626
  // technically subscribed.
20148
20627
  // We'll defer these events until when the room is connected or eventually disconnected.
20149
- if (this.state === ConnectionState.Connecting || this.state === ConnectionState.Reconnecting) {
20150
- setTimeout(() => {
20628
+ if (this.connectFuture) {
20629
+ this.connectFuture.promise.then(() => {
20151
20630
  this.onTrackAdded(mediaTrack, stream, receiver);
20152
- }, 50);
20631
+ });
20153
20632
  return;
20154
20633
  }
20155
20634
 
20156
20635
  if (this.state === ConnectionState.Disconnected) {
20157
20636
  livekitLogger.warn('skipping incoming track after Room disconnected');
20637
+ return;
20158
20638
  }
20159
20639
 
20160
20640
  const parts = unpackStreamId(stream.id);
@@ -20183,9 +20663,14 @@ class Room extends events.exports.EventEmitter {
20183
20663
 
20184
20664
  handleDisconnect() {
20185
20665
  let shouldStopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
20666
+ let reason = arguments.length > 1 ? arguments[1] : undefined;
20186
20667
 
20187
20668
  var _a;
20188
20669
 
20670
+ if (this.state === ConnectionState.Disconnected) {
20671
+ return;
20672
+ }
20673
+
20189
20674
  this.participants.forEach(p => {
20190
20675
  p.tracks.forEach(pub => {
20191
20676
  p.unpublishTrack(pub.trackSid);
@@ -20203,6 +20688,9 @@ class Room extends events.exports.EventEmitter {
20203
20688
  (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
20204
20689
  }
20205
20690
  });
20691
+ this.localParticipant.tracks.clear();
20692
+ this.localParticipant.videoTracks.clear();
20693
+ this.localParticipant.audioTracks.clear();
20206
20694
  this.participants.clear();
20207
20695
  this.activeSpeakers = [];
20208
20696
 
@@ -20217,7 +20705,7 @@ class Room extends events.exports.EventEmitter {
20217
20705
  }
20218
20706
 
20219
20707
  this.setAndEmitConnectionState(ConnectionState.Disconnected);
20220
- this.emit(RoomEvent.Disconnected);
20708
+ this.emit(RoomEvent.Disconnected, reason);
20221
20709
  }
20222
20710
 
20223
20711
  handleParticipantDisconnected(sid, participant) {
@@ -20304,6 +20792,8 @@ class Room extends events.exports.EventEmitter {
20304
20792
  this.emitWhenConnected(RoomEvent.ConnectionQualityChanged, quality, participant);
20305
20793
  }).on(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions => {
20306
20794
  this.emitWhenConnected(RoomEvent.ParticipantPermissionsChanged, prevPermissions, participant);
20795
+ }).on(ParticipantEvent.TrackSubscriptionPermissionChanged, (pub, status) => {
20796
+ this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, status, participant);
20307
20797
  }); // update info at the end after callbacks have been set up
20308
20798
 
20309
20799
  if (info) {
@@ -20543,5 +21033,5 @@ async function createLocalScreenTracks(options) {
20543
21033
  return localTracks;
20544
21034
  }
20545
21035
 
20546
- export { AudioPresets, ConnectionError, ConnectionQuality, ConnectionState, DataPacket_Kind, EngineEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, MediaDeviceFailure, Participant, ParticipantEvent, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, RoomState, ScreenSharePresets, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, detachTrack, protocolVersion, setLogExtension, setLogLevel, version };
21036
+ export { AudioPresets, ConnectionError, ConnectionQuality, ConnectionState, DataPacket_Kind, DisconnectReason, EngineEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, MediaDeviceFailure, Participant, ParticipantEvent, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, RoomState, ScreenSharePresets, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, detachTrack, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, protocolVersion, setLogExtension, setLogLevel, version };
20547
21037
  //# sourceMappingURL=livekit-client.esm.mjs.map