livekit-client 1.0.0 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/dist/livekit-client.esm.mjs +913 -233
  2. package/dist/livekit-client.esm.mjs.map +1 -1
  3. package/dist/livekit-client.umd.js +1 -1
  4. package/dist/livekit-client.umd.js.map +1 -1
  5. package/dist/{api → src/api}/RequestQueue.d.ts +0 -0
  6. package/dist/src/api/RequestQueue.d.ts.map +1 -0
  7. package/dist/{api → src/api}/SignalClient.d.ts +1 -1
  8. package/dist/src/api/SignalClient.d.ts.map +1 -0
  9. package/dist/{index.d.ts → src/index.d.ts} +2 -2
  10. package/dist/src/index.d.ts.map +1 -0
  11. package/dist/{logger.d.ts → src/logger.d.ts} +0 -0
  12. package/dist/src/logger.d.ts.map +1 -0
  13. package/dist/{options.d.ts → src/options.d.ts} +0 -0
  14. package/dist/src/options.d.ts.map +1 -0
  15. package/dist/{proto → src/proto}/google/protobuf/timestamp.d.ts +0 -0
  16. package/dist/src/proto/google/protobuf/timestamp.d.ts.map +1 -0
  17. package/dist/{proto → src/proto}/livekit_models.d.ts +80 -0
  18. package/dist/src/proto/livekit_models.d.ts.map +1 -0
  19. package/dist/{proto → src/proto}/livekit_rtc.d.ts +661 -0
  20. package/dist/src/proto/livekit_rtc.d.ts.map +1 -0
  21. package/dist/{room → src/room}/DeviceManager.d.ts +0 -0
  22. package/dist/src/room/DeviceManager.d.ts.map +1 -0
  23. package/dist/{room → src/room}/PCTransport.d.ts +0 -0
  24. package/dist/src/room/PCTransport.d.ts.map +1 -0
  25. package/dist/{room → src/room}/RTCEngine.d.ts +1 -0
  26. package/dist/src/room/RTCEngine.d.ts.map +1 -0
  27. package/dist/{room → src/room}/Room.d.ts +2 -0
  28. package/dist/src/room/Room.d.ts.map +1 -0
  29. package/dist/{room → src/room}/errors.d.ts +0 -0
  30. package/dist/src/room/errors.d.ts.map +1 -0
  31. package/dist/{room → src/room}/events.d.ts +5 -1
  32. package/dist/src/room/events.d.ts.map +1 -0
  33. package/dist/{room → src/room}/participant/LocalParticipant.d.ts +4 -1
  34. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -0
  35. package/dist/{room → src/room}/participant/Participant.d.ts +0 -0
  36. package/dist/src/room/participant/Participant.d.ts.map +1 -0
  37. package/dist/{room → src/room}/participant/ParticipantTrackPermission.d.ts +0 -0
  38. package/dist/src/room/participant/ParticipantTrackPermission.d.ts.map +1 -0
  39. package/dist/{room → src/room}/participant/RemoteParticipant.d.ts +0 -0
  40. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -0
  41. package/dist/{room → src/room}/participant/publishUtils.d.ts +0 -0
  42. package/dist/src/room/participant/publishUtils.d.ts.map +1 -0
  43. package/dist/{room → src/room}/stats.d.ts +1 -0
  44. package/dist/src/room/stats.d.ts.map +1 -0
  45. package/dist/{room → src/room}/track/LocalAudioTrack.d.ts +0 -0
  46. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -0
  47. package/dist/{room → src/room}/track/LocalTrack.d.ts +3 -0
  48. package/dist/src/room/track/LocalTrack.d.ts.map +1 -0
  49. package/dist/{room → src/room}/track/LocalTrackPublication.d.ts +0 -0
  50. package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -0
  51. package/dist/{room → src/room}/track/LocalVideoTrack.d.ts +17 -2
  52. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -0
  53. package/dist/{room → src/room}/track/RemoteAudioTrack.d.ts +0 -0
  54. package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -0
  55. package/dist/{room → src/room}/track/RemoteTrack.d.ts +0 -1
  56. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -0
  57. package/dist/{room → src/room}/track/RemoteTrackPublication.d.ts +0 -0
  58. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -0
  59. package/dist/{room → src/room}/track/RemoteVideoTrack.d.ts +25 -1
  60. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -0
  61. package/dist/{room → src/room}/track/Track.d.ts +6 -1
  62. package/dist/src/room/track/Track.d.ts.map +1 -0
  63. package/dist/{room → src/room}/track/TrackPublication.d.ts +0 -0
  64. package/dist/src/room/track/TrackPublication.d.ts.map +1 -0
  65. package/dist/{room → src/room}/track/create.d.ts +0 -0
  66. package/dist/src/room/track/create.d.ts.map +1 -0
  67. package/dist/{room → src/room}/track/defaults.d.ts +0 -0
  68. package/dist/src/room/track/defaults.d.ts.map +1 -0
  69. package/dist/{room → src/room}/track/options.d.ts +2 -1
  70. package/dist/src/room/track/options.d.ts.map +1 -0
  71. package/dist/{room → src/room}/track/types.d.ts +5 -0
  72. package/dist/src/room/track/types.d.ts.map +1 -0
  73. package/dist/{room → src/room}/track/utils.d.ts +0 -0
  74. package/dist/src/room/track/utils.d.ts.map +1 -0
  75. package/dist/{room → src/room}/utils.d.ts +0 -0
  76. package/dist/src/room/utils.d.ts.map +1 -0
  77. package/dist/src/test/MockMediaStreamTrack.d.ts +26 -0
  78. package/dist/src/test/MockMediaStreamTrack.d.ts.map +1 -0
  79. package/dist/{test → src/test}/mocks.d.ts +0 -0
  80. package/dist/src/test/mocks.d.ts.map +1 -0
  81. package/dist/src/version.d.ts +3 -0
  82. package/dist/src/version.d.ts.map +1 -0
  83. package/package.json +7 -3
  84. package/src/api/SignalClient.ts +2 -2
  85. package/src/index.ts +2 -1
  86. package/src/proto/livekit_models.ts +90 -0
  87. package/src/proto/livekit_rtc.ts +235 -1
  88. package/src/room/RTCEngine.ts +30 -2
  89. package/src/room/Room.ts +61 -16
  90. package/src/room/events.ts +5 -0
  91. package/src/room/participant/LocalParticipant.ts +104 -23
  92. package/src/room/participant/RemoteParticipant.ts +1 -0
  93. package/src/room/stats.ts +2 -0
  94. package/src/room/track/LocalAudioTrack.ts +4 -0
  95. package/src/room/track/LocalTrack.ts +12 -5
  96. package/src/room/track/LocalVideoTrack.ts +144 -56
  97. package/src/room/track/RemoteTrack.ts +0 -2
  98. package/src/room/track/RemoteVideoTrack.test.ts +149 -0
  99. package/src/room/track/RemoteVideoTrack.ts +118 -37
  100. package/src/room/track/Track.ts +23 -2
  101. package/src/room/track/options.ts +2 -1
  102. package/src/room/track/types.ts +5 -0
  103. package/src/test/MockMediaStreamTrack.ts +83 -0
  104. package/src/version.ts +4 -2
  105. package/dist/api/RequestQueue.d.ts.map +0 -1
  106. package/dist/api/SignalClient.d.ts.map +0 -1
  107. package/dist/index.d.ts.map +0 -1
  108. package/dist/logger.d.ts.map +0 -1
  109. package/dist/options.d.ts.map +0 -1
  110. package/dist/proto/google/protobuf/timestamp.d.ts.map +0 -1
  111. package/dist/proto/livekit_models.d.ts.map +0 -1
  112. package/dist/proto/livekit_rtc.d.ts.map +0 -1
  113. package/dist/room/DeviceManager.d.ts.map +0 -1
  114. package/dist/room/PCTransport.d.ts.map +0 -1
  115. package/dist/room/RTCEngine.d.ts.map +0 -1
  116. package/dist/room/Room.d.ts.map +0 -1
  117. package/dist/room/errors.d.ts.map +0 -1
  118. package/dist/room/events.d.ts.map +0 -1
  119. package/dist/room/participant/LocalParticipant.d.ts.map +0 -1
  120. package/dist/room/participant/Participant.d.ts.map +0 -1
  121. package/dist/room/participant/ParticipantTrackPermission.d.ts.map +0 -1
  122. package/dist/room/participant/RemoteParticipant.d.ts.map +0 -1
  123. package/dist/room/participant/publishUtils.d.ts.map +0 -1
  124. package/dist/room/stats.d.ts.map +0 -1
  125. package/dist/room/track/LocalAudioTrack.d.ts.map +0 -1
  126. package/dist/room/track/LocalTrack.d.ts.map +0 -1
  127. package/dist/room/track/LocalTrackPublication.d.ts.map +0 -1
  128. package/dist/room/track/LocalVideoTrack.d.ts.map +0 -1
  129. package/dist/room/track/RemoteAudioTrack.d.ts.map +0 -1
  130. package/dist/room/track/RemoteTrack.d.ts.map +0 -1
  131. package/dist/room/track/RemoteTrackPublication.d.ts.map +0 -1
  132. package/dist/room/track/RemoteVideoTrack.d.ts.map +0 -1
  133. package/dist/room/track/Track.d.ts.map +0 -1
  134. package/dist/room/track/TrackPublication.d.ts.map +0 -1
  135. package/dist/room/track/create.d.ts.map +0 -1
  136. package/dist/room/track/defaults.d.ts.map +0 -1
  137. package/dist/room/track/options.d.ts.map +0 -1
  138. package/dist/room/track/types.d.ts.map +0 -1
  139. package/dist/room/track/utils.d.ts.map +0 -1
  140. package/dist/room/utils.d.ts.map +0 -1
  141. package/dist/test/mocks.d.ts.map +0 -1
  142. package/dist/version.d.ts +0 -3
  143. package/dist/version.d.ts.map +0 -1
@@ -5200,6 +5200,91 @@ const ParticipantInfo = {
5200
5200
 
5201
5201
  };
5202
5202
 
5203
+ function createBaseSimulcastCodecInfo() {
5204
+ return {
5205
+ mimeType: '',
5206
+ mid: '',
5207
+ cid: ''
5208
+ };
5209
+ }
5210
+
5211
+ const SimulcastCodecInfo = {
5212
+ encode(message) {
5213
+ let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : minimal.Writer.create();
5214
+
5215
+ if (message.mimeType !== '') {
5216
+ writer.uint32(10).string(message.mimeType);
5217
+ }
5218
+
5219
+ if (message.mid !== '') {
5220
+ writer.uint32(18).string(message.mid);
5221
+ }
5222
+
5223
+ if (message.cid !== '') {
5224
+ writer.uint32(26).string(message.cid);
5225
+ }
5226
+
5227
+ return writer;
5228
+ },
5229
+
5230
+ decode(input, length) {
5231
+ const reader = input instanceof minimal.Reader ? input : new minimal.Reader(input);
5232
+ let end = length === undefined ? reader.len : reader.pos + length;
5233
+ const message = createBaseSimulcastCodecInfo();
5234
+
5235
+ while (reader.pos < end) {
5236
+ const tag = reader.uint32();
5237
+
5238
+ switch (tag >>> 3) {
5239
+ case 1:
5240
+ message.mimeType = reader.string();
5241
+ break;
5242
+
5243
+ case 2:
5244
+ message.mid = reader.string();
5245
+ break;
5246
+
5247
+ case 3:
5248
+ message.cid = reader.string();
5249
+ break;
5250
+
5251
+ default:
5252
+ reader.skipType(tag & 7);
5253
+ break;
5254
+ }
5255
+ }
5256
+
5257
+ return message;
5258
+ },
5259
+
5260
+ fromJSON(object) {
5261
+ return {
5262
+ mimeType: isSet$1(object.mimeType) ? String(object.mimeType) : '',
5263
+ mid: isSet$1(object.mid) ? String(object.mid) : '',
5264
+ cid: isSet$1(object.cid) ? String(object.cid) : ''
5265
+ };
5266
+ },
5267
+
5268
+ toJSON(message) {
5269
+ const obj = {};
5270
+ message.mimeType !== undefined && (obj.mimeType = message.mimeType);
5271
+ message.mid !== undefined && (obj.mid = message.mid);
5272
+ message.cid !== undefined && (obj.cid = message.cid);
5273
+ return obj;
5274
+ },
5275
+
5276
+ fromPartial(object) {
5277
+ var _a, _b, _c;
5278
+
5279
+ const message = createBaseSimulcastCodecInfo();
5280
+ message.mimeType = (_a = object.mimeType) !== null && _a !== void 0 ? _a : '';
5281
+ message.mid = (_b = object.mid) !== null && _b !== void 0 ? _b : '';
5282
+ message.cid = (_c = object.cid) !== null && _c !== void 0 ? _c : '';
5283
+ return message;
5284
+ }
5285
+
5286
+ };
5287
+
5203
5288
  function createBaseTrackInfo() {
5204
5289
  return {
5205
5290
  sid: '',
@@ -5213,7 +5298,8 @@ function createBaseTrackInfo() {
5213
5298
  source: 0,
5214
5299
  layers: [],
5215
5300
  mimeType: '',
5216
- mid: ''
5301
+ mid: '',
5302
+ codecs: []
5217
5303
  };
5218
5304
  }
5219
5305
 
@@ -5269,6 +5355,10 @@ const TrackInfo = {
5269
5355
  writer.uint32(98).string(message.mid);
5270
5356
  }
5271
5357
 
5358
+ for (const v of message.codecs) {
5359
+ SimulcastCodecInfo.encode(v, writer.uint32(106).fork()).ldelim();
5360
+ }
5361
+
5272
5362
  return writer;
5273
5363
  },
5274
5364
 
@@ -5329,6 +5419,10 @@ const TrackInfo = {
5329
5419
  message.mid = reader.string();
5330
5420
  break;
5331
5421
 
5422
+ case 13:
5423
+ message.codecs.push(SimulcastCodecInfo.decode(reader, reader.uint32()));
5424
+ break;
5425
+
5332
5426
  default:
5333
5427
  reader.skipType(tag & 7);
5334
5428
  break;
@@ -5351,7 +5445,8 @@ const TrackInfo = {
5351
5445
  source: isSet$1(object.source) ? trackSourceFromJSON(object.source) : 0,
5352
5446
  layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : [],
5353
5447
  mimeType: isSet$1(object.mimeType) ? String(object.mimeType) : '',
5354
- mid: isSet$1(object.mid) ? String(object.mid) : ''
5448
+ mid: isSet$1(object.mid) ? String(object.mid) : '',
5449
+ codecs: Array.isArray(object === null || object === void 0 ? void 0 : object.codecs) ? object.codecs.map(e => SimulcastCodecInfo.fromJSON(e)) : []
5355
5450
  };
5356
5451
  },
5357
5452
 
@@ -5375,11 +5470,18 @@ const TrackInfo = {
5375
5470
 
5376
5471
  message.mimeType !== undefined && (obj.mimeType = message.mimeType);
5377
5472
  message.mid !== undefined && (obj.mid = message.mid);
5473
+
5474
+ if (message.codecs) {
5475
+ obj.codecs = message.codecs.map(e => e ? SimulcastCodecInfo.toJSON(e) : undefined);
5476
+ } else {
5477
+ obj.codecs = [];
5478
+ }
5479
+
5378
5480
  return obj;
5379
5481
  },
5380
5482
 
5381
5483
  fromPartial(object) {
5382
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
5484
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
5383
5485
 
5384
5486
  const message = createBaseTrackInfo();
5385
5487
  message.sid = (_a = object.sid) !== null && _a !== void 0 ? _a : '';
@@ -5394,6 +5496,7 @@ const TrackInfo = {
5394
5496
  message.layers = ((_k = object.layers) === null || _k === void 0 ? void 0 : _k.map(e => VideoLayer.fromPartial(e))) || [];
5395
5497
  message.mimeType = (_l = object.mimeType) !== null && _l !== void 0 ? _l : '';
5396
5498
  message.mid = (_m = object.mid) !== null && _m !== void 0 ? _m : '';
5499
+ message.codecs = ((_o = object.codecs) === null || _o === void 0 ? void 0 : _o.map(e => SimulcastCodecInfo.fromPartial(e))) || [];
5397
5500
  return message;
5398
5501
  }
5399
5502
 
@@ -6381,6 +6484,42 @@ function streamStateToJSON(object) {
6381
6484
  return 'UNKNOWN';
6382
6485
  }
6383
6486
  }
6487
+ var CandidateProtocol;
6488
+
6489
+ (function (CandidateProtocol) {
6490
+ CandidateProtocol[CandidateProtocol["UDP"] = 0] = "UDP";
6491
+ CandidateProtocol[CandidateProtocol["TCP"] = 1] = "TCP";
6492
+ CandidateProtocol[CandidateProtocol["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
6493
+ })(CandidateProtocol || (CandidateProtocol = {}));
6494
+
6495
+ function candidateProtocolFromJSON(object) {
6496
+ switch (object) {
6497
+ case 0:
6498
+ case 'UDP':
6499
+ return CandidateProtocol.UDP;
6500
+
6501
+ case 1:
6502
+ case 'TCP':
6503
+ return CandidateProtocol.TCP;
6504
+
6505
+ case -1:
6506
+ case 'UNRECOGNIZED':
6507
+ default:
6508
+ return CandidateProtocol.UNRECOGNIZED;
6509
+ }
6510
+ }
6511
+ function candidateProtocolToJSON(object) {
6512
+ switch (object) {
6513
+ case CandidateProtocol.UDP:
6514
+ return 'UDP';
6515
+
6516
+ case CandidateProtocol.TCP:
6517
+ return 'TCP';
6518
+
6519
+ default:
6520
+ return 'UNKNOWN';
6521
+ }
6522
+ }
6384
6523
 
6385
6524
  function createBaseSignalRequest() {
6386
6525
  return {
@@ -6814,6 +6953,91 @@ const SignalResponse = {
6814
6953
 
6815
6954
  };
6816
6955
 
6956
+ function createBaseSimulcastCodec() {
6957
+ return {
6958
+ codec: '',
6959
+ cid: '',
6960
+ enableSimulcastLayers: false
6961
+ };
6962
+ }
6963
+
6964
+ const SimulcastCodec = {
6965
+ encode(message) {
6966
+ let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : minimal.Writer.create();
6967
+
6968
+ if (message.codec !== '') {
6969
+ writer.uint32(10).string(message.codec);
6970
+ }
6971
+
6972
+ if (message.cid !== '') {
6973
+ writer.uint32(18).string(message.cid);
6974
+ }
6975
+
6976
+ if (message.enableSimulcastLayers === true) {
6977
+ writer.uint32(24).bool(message.enableSimulcastLayers);
6978
+ }
6979
+
6980
+ return writer;
6981
+ },
6982
+
6983
+ decode(input, length) {
6984
+ const reader = input instanceof minimal.Reader ? input : new minimal.Reader(input);
6985
+ let end = length === undefined ? reader.len : reader.pos + length;
6986
+ const message = createBaseSimulcastCodec();
6987
+
6988
+ while (reader.pos < end) {
6989
+ const tag = reader.uint32();
6990
+
6991
+ switch (tag >>> 3) {
6992
+ case 1:
6993
+ message.codec = reader.string();
6994
+ break;
6995
+
6996
+ case 2:
6997
+ message.cid = reader.string();
6998
+ break;
6999
+
7000
+ case 3:
7001
+ message.enableSimulcastLayers = reader.bool();
7002
+ break;
7003
+
7004
+ default:
7005
+ reader.skipType(tag & 7);
7006
+ break;
7007
+ }
7008
+ }
7009
+
7010
+ return message;
7011
+ },
7012
+
7013
+ fromJSON(object) {
7014
+ return {
7015
+ codec: isSet(object.codec) ? String(object.codec) : '',
7016
+ cid: isSet(object.cid) ? String(object.cid) : '',
7017
+ enableSimulcastLayers: isSet(object.enableSimulcastLayers) ? Boolean(object.enableSimulcastLayers) : false
7018
+ };
7019
+ },
7020
+
7021
+ toJSON(message) {
7022
+ const obj = {};
7023
+ message.codec !== undefined && (obj.codec = message.codec);
7024
+ message.cid !== undefined && (obj.cid = message.cid);
7025
+ message.enableSimulcastLayers !== undefined && (obj.enableSimulcastLayers = message.enableSimulcastLayers);
7026
+ return obj;
7027
+ },
7028
+
7029
+ fromPartial(object) {
7030
+ var _a, _b, _c;
7031
+
7032
+ const message = createBaseSimulcastCodec();
7033
+ message.codec = (_a = object.codec) !== null && _a !== void 0 ? _a : '';
7034
+ message.cid = (_b = object.cid) !== null && _b !== void 0 ? _b : '';
7035
+ message.enableSimulcastLayers = (_c = object.enableSimulcastLayers) !== null && _c !== void 0 ? _c : false;
7036
+ return message;
7037
+ }
7038
+
7039
+ };
7040
+
6817
7041
  function createBaseAddTrackRequest() {
6818
7042
  return {
6819
7043
  cid: '',
@@ -6824,7 +7048,8 @@ function createBaseAddTrackRequest() {
6824
7048
  muted: false,
6825
7049
  disableDtx: false,
6826
7050
  source: 0,
6827
- layers: []
7051
+ layers: [],
7052
+ simulcastCodecs: []
6828
7053
  };
6829
7054
  }
6830
7055
 
@@ -6868,6 +7093,10 @@ const AddTrackRequest = {
6868
7093
  VideoLayer.encode(v, writer.uint32(74).fork()).ldelim();
6869
7094
  }
6870
7095
 
7096
+ for (const v of message.simulcastCodecs) {
7097
+ SimulcastCodec.encode(v, writer.uint32(82).fork()).ldelim();
7098
+ }
7099
+
6871
7100
  return writer;
6872
7101
  },
6873
7102
 
@@ -6916,6 +7145,10 @@ const AddTrackRequest = {
6916
7145
  message.layers.push(VideoLayer.decode(reader, reader.uint32()));
6917
7146
  break;
6918
7147
 
7148
+ case 10:
7149
+ message.simulcastCodecs.push(SimulcastCodec.decode(reader, reader.uint32()));
7150
+ break;
7151
+
6919
7152
  default:
6920
7153
  reader.skipType(tag & 7);
6921
7154
  break;
@@ -6935,7 +7168,8 @@ const AddTrackRequest = {
6935
7168
  muted: isSet(object.muted) ? Boolean(object.muted) : false,
6936
7169
  disableDtx: isSet(object.disableDtx) ? Boolean(object.disableDtx) : false,
6937
7170
  source: isSet(object.source) ? trackSourceFromJSON(object.source) : 0,
6938
- layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : []
7171
+ layers: Array.isArray(object === null || object === void 0 ? void 0 : object.layers) ? object.layers.map(e => VideoLayer.fromJSON(e)) : [],
7172
+ simulcastCodecs: Array.isArray(object === null || object === void 0 ? void 0 : object.simulcastCodecs) ? object.simulcastCodecs.map(e => SimulcastCodec.fromJSON(e)) : []
6939
7173
  };
6940
7174
  },
6941
7175
 
@@ -6956,11 +7190,17 @@ const AddTrackRequest = {
6956
7190
  obj.layers = [];
6957
7191
  }
6958
7192
 
7193
+ if (message.simulcastCodecs) {
7194
+ obj.simulcastCodecs = message.simulcastCodecs.map(e => e ? SimulcastCodec.toJSON(e) : undefined);
7195
+ } else {
7196
+ obj.simulcastCodecs = [];
7197
+ }
7198
+
6959
7199
  return obj;
6960
7200
  },
6961
7201
 
6962
7202
  fromPartial(object) {
6963
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
7203
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
6964
7204
 
6965
7205
  const message = createBaseAddTrackRequest();
6966
7206
  message.cid = (_a = object.cid) !== null && _a !== void 0 ? _a : '';
@@ -6972,6 +7212,7 @@ const AddTrackRequest = {
6972
7212
  message.disableDtx = (_g = object.disableDtx) !== null && _g !== void 0 ? _g : false;
6973
7213
  message.source = (_h = object.source) !== null && _h !== void 0 ? _h : 0;
6974
7214
  message.layers = ((_j = object.layers) === null || _j === void 0 ? void 0 : _j.map(e => VideoLayer.fromPartial(e))) || [];
7215
+ message.simulcastCodecs = ((_k = object.simulcastCodecs) === null || _k === void 0 ? void 0 : _k.map(e => SimulcastCodec.fromPartial(e))) || [];
6975
7216
  return message;
6976
7217
  }
6977
7218
 
@@ -8512,10 +8753,90 @@ const SubscribedQuality = {
8512
8753
 
8513
8754
  };
8514
8755
 
8756
+ function createBaseSubscribedCodec() {
8757
+ return {
8758
+ codec: '',
8759
+ qualities: []
8760
+ };
8761
+ }
8762
+
8763
+ const SubscribedCodec = {
8764
+ encode(message) {
8765
+ let writer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : minimal.Writer.create();
8766
+
8767
+ if (message.codec !== '') {
8768
+ writer.uint32(10).string(message.codec);
8769
+ }
8770
+
8771
+ for (const v of message.qualities) {
8772
+ SubscribedQuality.encode(v, writer.uint32(18).fork()).ldelim();
8773
+ }
8774
+
8775
+ return writer;
8776
+ },
8777
+
8778
+ decode(input, length) {
8779
+ const reader = input instanceof minimal.Reader ? input : new minimal.Reader(input);
8780
+ let end = length === undefined ? reader.len : reader.pos + length;
8781
+ const message = createBaseSubscribedCodec();
8782
+
8783
+ while (reader.pos < end) {
8784
+ const tag = reader.uint32();
8785
+
8786
+ switch (tag >>> 3) {
8787
+ case 1:
8788
+ message.codec = reader.string();
8789
+ break;
8790
+
8791
+ case 2:
8792
+ message.qualities.push(SubscribedQuality.decode(reader, reader.uint32()));
8793
+ break;
8794
+
8795
+ default:
8796
+ reader.skipType(tag & 7);
8797
+ break;
8798
+ }
8799
+ }
8800
+
8801
+ return message;
8802
+ },
8803
+
8804
+ fromJSON(object) {
8805
+ return {
8806
+ codec: isSet(object.codec) ? String(object.codec) : '',
8807
+ qualities: Array.isArray(object === null || object === void 0 ? void 0 : object.qualities) ? object.qualities.map(e => SubscribedQuality.fromJSON(e)) : []
8808
+ };
8809
+ },
8810
+
8811
+ toJSON(message) {
8812
+ const obj = {};
8813
+ message.codec !== undefined && (obj.codec = message.codec);
8814
+
8815
+ if (message.qualities) {
8816
+ obj.qualities = message.qualities.map(e => e ? SubscribedQuality.toJSON(e) : undefined);
8817
+ } else {
8818
+ obj.qualities = [];
8819
+ }
8820
+
8821
+ return obj;
8822
+ },
8823
+
8824
+ fromPartial(object) {
8825
+ var _a, _b;
8826
+
8827
+ const message = createBaseSubscribedCodec();
8828
+ message.codec = (_a = object.codec) !== null && _a !== void 0 ? _a : '';
8829
+ message.qualities = ((_b = object.qualities) === null || _b === void 0 ? void 0 : _b.map(e => SubscribedQuality.fromPartial(e))) || [];
8830
+ return message;
8831
+ }
8832
+
8833
+ };
8834
+
8515
8835
  function createBaseSubscribedQualityUpdate() {
8516
8836
  return {
8517
8837
  trackSid: '',
8518
- subscribedQualities: []
8838
+ subscribedQualities: [],
8839
+ subscribedCodecs: []
8519
8840
  };
8520
8841
  }
8521
8842
 
@@ -8531,6 +8852,10 @@ const SubscribedQualityUpdate = {
8531
8852
  SubscribedQuality.encode(v, writer.uint32(18).fork()).ldelim();
8532
8853
  }
8533
8854
 
8855
+ for (const v of message.subscribedCodecs) {
8856
+ SubscribedCodec.encode(v, writer.uint32(26).fork()).ldelim();
8857
+ }
8858
+
8534
8859
  return writer;
8535
8860
  },
8536
8861
 
@@ -8551,6 +8876,10 @@ const SubscribedQualityUpdate = {
8551
8876
  message.subscribedQualities.push(SubscribedQuality.decode(reader, reader.uint32()));
8552
8877
  break;
8553
8878
 
8879
+ case 3:
8880
+ message.subscribedCodecs.push(SubscribedCodec.decode(reader, reader.uint32()));
8881
+ break;
8882
+
8554
8883
  default:
8555
8884
  reader.skipType(tag & 7);
8556
8885
  break;
@@ -8563,7 +8892,8 @@ const SubscribedQualityUpdate = {
8563
8892
  fromJSON(object) {
8564
8893
  return {
8565
8894
  trackSid: isSet(object.trackSid) ? String(object.trackSid) : '',
8566
- subscribedQualities: Array.isArray(object === null || object === void 0 ? void 0 : object.subscribedQualities) ? object.subscribedQualities.map(e => SubscribedQuality.fromJSON(e)) : []
8895
+ subscribedQualities: Array.isArray(object === null || object === void 0 ? void 0 : object.subscribedQualities) ? object.subscribedQualities.map(e => SubscribedQuality.fromJSON(e)) : [],
8896
+ subscribedCodecs: Array.isArray(object === null || object === void 0 ? void 0 : object.subscribedCodecs) ? object.subscribedCodecs.map(e => SubscribedCodec.fromJSON(e)) : []
8567
8897
  };
8568
8898
  },
8569
8899
 
@@ -8577,15 +8907,22 @@ const SubscribedQualityUpdate = {
8577
8907
  obj.subscribedQualities = [];
8578
8908
  }
8579
8909
 
8910
+ if (message.subscribedCodecs) {
8911
+ obj.subscribedCodecs = message.subscribedCodecs.map(e => e ? SubscribedCodec.toJSON(e) : undefined);
8912
+ } else {
8913
+ obj.subscribedCodecs = [];
8914
+ }
8915
+
8580
8916
  return obj;
8581
8917
  },
8582
8918
 
8583
8919
  fromPartial(object) {
8584
- var _a, _b;
8920
+ var _a, _b, _c;
8585
8921
 
8586
8922
  const message = createBaseSubscribedQualityUpdate();
8587
8923
  message.trackSid = (_a = object.trackSid) !== null && _a !== void 0 ? _a : '';
8588
8924
  message.subscribedQualities = ((_b = object.subscribedQualities) === null || _b === void 0 ? void 0 : _b.map(e => SubscribedQuality.fromPartial(e))) || [];
8925
+ message.subscribedCodecs = ((_c = object.subscribedCodecs) === null || _c === void 0 ? void 0 : _c.map(e => SubscribedCodec.fromPartial(e))) || [];
8589
8926
  return message;
8590
8927
  }
8591
8928
 
@@ -9056,7 +9393,8 @@ function createBaseSimulateScenario() {
9056
9393
  speakerUpdate: undefined,
9057
9394
  nodeFailure: undefined,
9058
9395
  migration: undefined,
9059
- serverLeave: undefined
9396
+ serverLeave: undefined,
9397
+ switchCandidateProtocol: undefined
9060
9398
  };
9061
9399
  }
9062
9400
 
@@ -9080,6 +9418,10 @@ const SimulateScenario = {
9080
9418
  writer.uint32(32).bool(message.serverLeave);
9081
9419
  }
9082
9420
 
9421
+ if (message.switchCandidateProtocol !== undefined) {
9422
+ writer.uint32(40).int32(message.switchCandidateProtocol);
9423
+ }
9424
+
9083
9425
  return writer;
9084
9426
  },
9085
9427
 
@@ -9108,6 +9450,10 @@ const SimulateScenario = {
9108
9450
  message.serverLeave = reader.bool();
9109
9451
  break;
9110
9452
 
9453
+ case 5:
9454
+ message.switchCandidateProtocol = reader.int32();
9455
+ break;
9456
+
9111
9457
  default:
9112
9458
  reader.skipType(tag & 7);
9113
9459
  break;
@@ -9122,7 +9468,8 @@ const SimulateScenario = {
9122
9468
  speakerUpdate: isSet(object.speakerUpdate) ? Number(object.speakerUpdate) : undefined,
9123
9469
  nodeFailure: isSet(object.nodeFailure) ? Boolean(object.nodeFailure) : undefined,
9124
9470
  migration: isSet(object.migration) ? Boolean(object.migration) : undefined,
9125
- serverLeave: isSet(object.serverLeave) ? Boolean(object.serverLeave) : undefined
9471
+ serverLeave: isSet(object.serverLeave) ? Boolean(object.serverLeave) : undefined,
9472
+ switchCandidateProtocol: isSet(object.switchCandidateProtocol) ? candidateProtocolFromJSON(object.switchCandidateProtocol) : undefined
9126
9473
  };
9127
9474
  },
9128
9475
 
@@ -9132,17 +9479,19 @@ const SimulateScenario = {
9132
9479
  message.nodeFailure !== undefined && (obj.nodeFailure = message.nodeFailure);
9133
9480
  message.migration !== undefined && (obj.migration = message.migration);
9134
9481
  message.serverLeave !== undefined && (obj.serverLeave = message.serverLeave);
9482
+ message.switchCandidateProtocol !== undefined && (obj.switchCandidateProtocol = message.switchCandidateProtocol !== undefined ? candidateProtocolToJSON(message.switchCandidateProtocol) : undefined);
9135
9483
  return obj;
9136
9484
  },
9137
9485
 
9138
9486
  fromPartial(object) {
9139
- var _a, _b, _c, _d;
9487
+ var _a, _b, _c, _d, _e;
9140
9488
 
9141
9489
  const message = createBaseSimulateScenario();
9142
9490
  message.speakerUpdate = (_a = object.speakerUpdate) !== null && _a !== void 0 ? _a : undefined;
9143
9491
  message.nodeFailure = (_b = object.nodeFailure) !== null && _b !== void 0 ? _b : undefined;
9144
9492
  message.migration = (_c = object.migration) !== null && _c !== void 0 ? _c : undefined;
9145
9493
  message.serverLeave = (_d = object.serverLeave) !== null && _d !== void 0 ? _d : undefined;
9494
+ message.switchCandidateProtocol = (_e = object.switchCandidateProtocol) !== null && _e !== void 0 ? _e : undefined;
9146
9495
  return message;
9147
9496
  }
9148
9497
 
@@ -9462,6 +9811,11 @@ var RoomEvent;
9462
9811
  */
9463
9812
 
9464
9813
  RoomEvent["ParticipantPermissionsChanged"] = "participantPermissionsChanged";
9814
+ /**
9815
+ * Signal connected, can publish tracks.
9816
+ */
9817
+
9818
+ RoomEvent["SignalConnected"] = "signalConnected";
9465
9819
  })(RoomEvent || (RoomEvent = {}));
9466
9820
 
9467
9821
  var ParticipantEvent;
@@ -9704,83 +10058,10 @@ function computeBitrate(currentStats, prevStats) {
9704
10058
  return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp);
9705
10059
  }
9706
10060
 
9707
- const defaultId = 'default';
9708
- class DeviceManager {
9709
- static getInstance() {
9710
- if (this.instance === undefined) {
9711
- this.instance = new DeviceManager();
9712
- }
9713
-
9714
- return this.instance;
9715
- }
9716
-
9717
- async getDevices(kind) {
9718
- let requestPermissions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
9719
- let devices = await navigator.mediaDevices.enumerateDevices();
9720
-
9721
- if (requestPermissions) {
9722
- const isDummyDeviceOrEmpty = devices.length === 0 || devices.some(device => {
9723
- const noLabel = device.label === '';
9724
- const isRelevant = kind ? device.kind === kind : true;
9725
- return noLabel && isRelevant;
9726
- });
9727
-
9728
- if (isDummyDeviceOrEmpty) {
9729
- const permissionsToAcquire = {
9730
- video: kind !== 'audioinput' && kind !== 'audiooutput',
9731
- audio: kind !== 'videoinput'
9732
- };
9733
- const stream = await navigator.mediaDevices.getUserMedia(permissionsToAcquire);
9734
- devices = await navigator.mediaDevices.enumerateDevices();
9735
- stream.getTracks().forEach(track => {
9736
- track.stop();
9737
- });
9738
- }
9739
- }
9740
-
9741
- if (kind) {
9742
- devices = devices.filter(device => device.kind === kind);
9743
- } // Chrome returns 'default' devices, we would filter them out, but put the default
9744
- // device at first
9745
- // we would only do this if there are more than 1 device though
9746
-
9747
-
9748
- if (devices.length > 1 && devices[0].deviceId === defaultId) {
9749
- // find another device with matching group id, and move that to 0
9750
- const defaultDevice = devices[0];
9751
-
9752
- for (let i = 1; i < devices.length; i += 1) {
9753
- if (devices[i].groupId === defaultDevice.groupId) {
9754
- const temp = devices[0];
9755
- devices[0] = devices[i];
9756
- devices[i] = temp;
9757
- break;
9758
- }
9759
- }
9760
-
9761
- return devices.filter(device => device !== defaultDevice);
9762
- }
9763
-
9764
- return devices;
9765
- }
9766
-
9767
- async normalizeDeviceId(kind, deviceId, groupId) {
9768
- if (deviceId !== defaultId) {
9769
- return deviceId;
9770
- } // resolve actual device id if it's 'default': Chrome returns it when no
9771
- // device has been chosen
9772
-
9773
-
9774
- const devices = await this.getDevices(kind);
9775
- const device = devices.find(d => d.groupId === groupId && d.deviceId !== defaultId);
9776
- return device === null || device === void 0 ? void 0 : device.deviceId;
9777
- }
9778
-
9779
- }
9780
- DeviceManager.mediaDeviceKinds = ['audioinput', 'audiooutput', 'videoinput'];
10061
+ var version$1 = "1.0.3";
9781
10062
 
9782
- const version = '1.0.0';
9783
- const protocolVersion = 7;
10063
+ const version = version$1;
10064
+ const protocolVersion = 8;
9784
10065
 
9785
10066
  const separator = '|';
9786
10067
  function unpackStreamId(packed) {
@@ -9887,6 +10168,81 @@ function getEmptyAudioStreamTrack() {
9887
10168
  return emptyAudioStreamTrack;
9888
10169
  }
9889
10170
 
10171
+ const defaultId = 'default';
10172
+ class DeviceManager {
10173
+ static getInstance() {
10174
+ if (this.instance === undefined) {
10175
+ this.instance = new DeviceManager();
10176
+ }
10177
+
10178
+ return this.instance;
10179
+ }
10180
+
10181
+ async getDevices(kind) {
10182
+ let requestPermissions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
10183
+ let devices = await navigator.mediaDevices.enumerateDevices();
10184
+
10185
+ if (requestPermissions) {
10186
+ const isDummyDeviceOrEmpty = devices.length === 0 || devices.some(device => {
10187
+ const noLabel = device.label === '';
10188
+ const isRelevant = kind ? device.kind === kind : true;
10189
+ return noLabel && isRelevant;
10190
+ });
10191
+
10192
+ if (isDummyDeviceOrEmpty) {
10193
+ const permissionsToAcquire = {
10194
+ video: kind !== 'audioinput' && kind !== 'audiooutput',
10195
+ audio: kind !== 'videoinput'
10196
+ };
10197
+ const stream = await navigator.mediaDevices.getUserMedia(permissionsToAcquire);
10198
+ devices = await navigator.mediaDevices.enumerateDevices();
10199
+ stream.getTracks().forEach(track => {
10200
+ track.stop();
10201
+ });
10202
+ }
10203
+ }
10204
+
10205
+ if (kind) {
10206
+ devices = devices.filter(device => device.kind === kind);
10207
+ } // Chrome returns 'default' devices, we would filter them out, but put the default
10208
+ // device at first
10209
+ // we would only do this if there are more than 1 device though
10210
+
10211
+
10212
+ if (devices.length > 1 && devices[0].deviceId === defaultId) {
10213
+ // find another device with matching group id, and move that to 0
10214
+ const defaultDevice = devices[0];
10215
+
10216
+ for (let i = 1; i < devices.length; i += 1) {
10217
+ if (devices[i].groupId === defaultDevice.groupId) {
10218
+ const temp = devices[0];
10219
+ devices[0] = devices[i];
10220
+ devices[i] = temp;
10221
+ break;
10222
+ }
10223
+ }
10224
+
10225
+ return devices.filter(device => device !== defaultDevice);
10226
+ }
10227
+
10228
+ return devices;
10229
+ }
10230
+
10231
+ async normalizeDeviceId(kind, deviceId, groupId) {
10232
+ if (deviceId !== defaultId) {
10233
+ return deviceId;
10234
+ } // resolve actual device id if it's 'default': Chrome returns it when no
10235
+ // device has been chosen
10236
+
10237
+
10238
+ const devices = await this.getDevices(kind);
10239
+ const device = devices.find(d => d.groupId === groupId && d.deviceId !== defaultId);
10240
+ return device === null || device === void 0 ? void 0 : device.deviceId;
10241
+ }
10242
+
10243
+ }
10244
+ DeviceManager.mediaDeviceKinds = ['audioinput', 'audiooutput', 'videoinput'];
10245
+
9890
10246
  var events = {exports: {}};
9891
10247
 
9892
10248
  var R = typeof Reflect === 'object' ? Reflect : null;
@@ -10332,6 +10688,7 @@ function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
10332
10688
  }
10333
10689
  }
10334
10690
 
10691
+ const BACKGROUND_REACTION_DELAY = 5000; // keep old audio elements when detached, we would re-use them since on iOS
10335
10692
  // Safari tracks which audio elements have been "blessed" by the user.
10336
10693
 
10337
10694
  const recycledElements = [];
@@ -10340,10 +10697,25 @@ class Track extends events.exports.EventEmitter {
10340
10697
  super();
10341
10698
  this.attachedElements = [];
10342
10699
  this.isMuted = false;
10700
+ /**
10701
+ * indicates current state of stream
10702
+ */
10703
+
10704
+ this.streamState = Track.StreamState.Active;
10343
10705
  this._currentBitrate = 0;
10344
10706
 
10345
10707
  this.appVisibilityChangedListener = () => {
10346
- this.handleAppVisibilityChanged();
10708
+ if (this.backgroundTimeout) {
10709
+ clearTimeout(this.backgroundTimeout);
10710
+ } // delay app visibility update if it goes to hidden
10711
+ // update immediately if it comes back to focus
10712
+
10713
+
10714
+ if (document.visibilityState === 'hidden') {
10715
+ this.backgroundTimeout = setTimeout(() => this.handleAppVisibilityChanged(), BACKGROUND_REACTION_DELAY);
10716
+ } else {
10717
+ this.handleAppVisibilityChanged();
10718
+ }
10347
10719
  };
10348
10720
 
10349
10721
  this.kind = kind;
@@ -10769,7 +11141,11 @@ class LocalTrack extends Track {
10769
11141
 
10770
11142
  track.addEventListener('ended', this.handleEnded);
10771
11143
  livekitLogger.debug('replace MediaStreamTrack');
10772
- await this.sender.replaceTrack(track);
11144
+
11145
+ if (this.sender) {
11146
+ await this.sender.replaceTrack(track);
11147
+ }
11148
+
10773
11149
  this._mediaStreamTrack = track;
10774
11150
  this.attachedElements.forEach(el => {
10775
11151
  attachToElement(track, el);
@@ -10779,10 +11155,6 @@ class LocalTrack extends Track {
10779
11155
  }
10780
11156
 
10781
11157
  async restart(constraints) {
10782
- if (!this.sender) {
10783
- throw new TrackInvalidError('unable to restart an unpublished track');
10784
- }
10785
-
10786
11158
  if (!constraints) {
10787
11159
  constraints = this.constraints;
10788
11160
  }
@@ -10816,7 +11188,12 @@ class LocalTrack extends Track {
10816
11188
  const newTrack = mediaStream.getTracks()[0];
10817
11189
  newTrack.addEventListener('ended', this.handleEnded);
10818
11190
  livekitLogger.debug('re-acquired MediaStreamTrack');
10819
- await this.sender.replaceTrack(newTrack);
11191
+
11192
+ if (this.sender) {
11193
+ // Track can be restarted after it's unpublished
11194
+ await this.sender.replaceTrack(newTrack);
11195
+ }
11196
+
10820
11197
  this._mediaStreamTrack = newTrack;
10821
11198
  this.attachedElements.forEach(el => {
10822
11199
  attachToElement(newTrack, el);
@@ -11090,6 +11467,10 @@ class LocalAudioTrack extends LocalTrack {
11090
11467
 
11091
11468
 
11092
11469
  startMonitor() {
11470
+ if (!isWeb()) {
11471
+ return;
11472
+ }
11473
+
11093
11474
  setTimeout(() => {
11094
11475
  this.monitorSender();
11095
11476
  }, monitorFrequency);
@@ -11136,6 +11517,7 @@ class LocalAudioTrack extends LocalTrack {
11136
11517
  class LocalVideoTrack extends LocalTrack {
11137
11518
  constructor(mediaTrack, constraints) {
11138
11519
  super(mediaTrack, Track.Kind.Video, constraints);
11520
+ this.simulcastCodecs = new Map();
11139
11521
 
11140
11522
  this.monitorSender = async () => {
11141
11523
  if (!this.sender) {
@@ -11187,7 +11569,13 @@ class LocalVideoTrack extends LocalTrack {
11187
11569
  startMonitor(signalClient) {
11188
11570
  var _a;
11189
11571
 
11190
- this.signalClient = signalClient; // save original encodings
11572
+ this.signalClient = signalClient;
11573
+
11574
+ if (!isWeb()) {
11575
+ return;
11576
+ } // save original encodings
11577
+ // TODO : merge simulcast tracks stats
11578
+
11191
11579
 
11192
11580
  const params = (_a = this.sender) === null || _a === void 0 ? void 0 : _a.getParameters();
11193
11581
 
@@ -11205,6 +11593,11 @@ class LocalVideoTrack extends LocalTrack {
11205
11593
 
11206
11594
  this._mediaStreamTrack.getConstraints();
11207
11595
 
11596
+ this.simulcastCodecs.forEach(trackInfo => {
11597
+ trackInfo.mediaStreamTrack.stop();
11598
+ trackInfo.sender = undefined;
11599
+ });
11600
+ this.simulcastCodecs.clear();
11208
11601
  super.stop();
11209
11602
  }
11210
11603
 
@@ -11252,7 +11645,7 @@ class LocalVideoTrack extends LocalTrack {
11252
11645
  bytesSent: v.bytesSent,
11253
11646
  framesSent: v.framesSent,
11254
11647
  timestamp: v.timestamp,
11255
- rid: (_a = v.rid) !== null && _a !== void 0 ? _a : '',
11648
+ rid: (_a = v.rid) !== null && _a !== void 0 ? _a : v.id,
11256
11649
  retransmittedPacketsSent: v.retransmittedPacketsSent,
11257
11650
  qualityLimitationReason: v.qualityLimitationReason,
11258
11651
  qualityLimitationResolutionChanges: v.qualityLimitationResolutionChanges
@@ -11314,6 +11707,58 @@ class LocalVideoTrack extends LocalTrack {
11314
11707
 
11315
11708
  await this.restart(constraints);
11316
11709
  }
11710
+
11711
+ addSimulcastTrack(codec, encodings) {
11712
+ if (this.simulcastCodecs.has(codec)) {
11713
+ throw new Error("".concat(codec, " already added"));
11714
+ }
11715
+
11716
+ const simulcastCodecInfo = {
11717
+ codec,
11718
+ mediaStreamTrack: this.mediaStreamTrack.clone(),
11719
+ sender: undefined,
11720
+ encodings
11721
+ };
11722
+ this.simulcastCodecs.set(codec, simulcastCodecInfo);
11723
+ return simulcastCodecInfo;
11724
+ }
11725
+
11726
+ setSimulcastTrackSender(codec, sender) {
11727
+ const simulcastCodecInfo = this.simulcastCodecs.get(codec);
11728
+
11729
+ if (!simulcastCodecInfo) {
11730
+ return;
11731
+ }
11732
+
11733
+ simulcastCodecInfo.sender = sender;
11734
+ }
11735
+ /**
11736
+ * @internal
11737
+ * Sets codecs that should be publishing
11738
+ */
11739
+
11740
+
11741
+ async setPublishingCodecs(codecs) {
11742
+ livekitLogger.debug('setting publishing codecs', codecs);
11743
+
11744
+ for await (const codec of codecs) {
11745
+ if (this.codec === codec.codec) {
11746
+ await this.setPublishingLayers(codec.qualities);
11747
+ } else {
11748
+ const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec);
11749
+ livekitLogger.debug("try setPublishingCodec for ".concat(codec.codec), simulcastCodecInfo);
11750
+
11751
+ if (!simulcastCodecInfo || !simulcastCodecInfo.sender) {
11752
+ return;
11753
+ }
11754
+
11755
+ if (simulcastCodecInfo.encodings) {
11756
+ livekitLogger.debug("try setPublishingLayersForSender ".concat(codec.codec));
11757
+ await setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities);
11758
+ }
11759
+ }
11760
+ }
11761
+ }
11317
11762
  /**
11318
11763
  * @internal
11319
11764
  * Sets layers that should be publishing
@@ -11327,77 +11772,87 @@ class LocalVideoTrack extends LocalTrack {
11327
11772
  return;
11328
11773
  }
11329
11774
 
11330
- const params = this.sender.getParameters();
11331
- const {
11332
- encodings
11333
- } = params;
11775
+ await setPublishingLayersForSender(this.sender, this.encodings, qualities);
11776
+ }
11334
11777
 
11335
- if (!encodings) {
11336
- return;
11337
- }
11778
+ async handleAppVisibilityChanged() {
11779
+ await super.handleAppVisibilityChanged();
11780
+ if (!isMobile()) return;
11338
11781
 
11339
- if (encodings.length !== this.encodings.length) {
11340
- livekitLogger.warn('cannot set publishing layers, encodings mismatch');
11341
- return;
11782
+ if (this.isInBackground && this.source === Track.Source.Camera) {
11783
+ this._mediaStreamTrack.enabled = false;
11342
11784
  }
11785
+ }
11343
11786
 
11344
- let hasChanged = false;
11345
- encodings.forEach((encoding, idx) => {
11346
- var _a;
11347
-
11348
- let rid = (_a = encoding.rid) !== null && _a !== void 0 ? _a : '';
11787
+ }
11349
11788
 
11350
- if (rid === '') {
11351
- rid = 'q';
11352
- }
11789
+ async function setPublishingLayersForSender(sender, senderEncodings, qualities) {
11790
+ livekitLogger.debug('setPublishingLayersForSender', {
11791
+ sender,
11792
+ qualities,
11793
+ senderEncodings
11794
+ });
11795
+ const params = sender.getParameters();
11796
+ const {
11797
+ encodings
11798
+ } = params;
11353
11799
 
11354
- const quality = videoQualityForRid(rid);
11355
- const subscribedQuality = qualities.find(q => q.quality === quality);
11800
+ if (!encodings) {
11801
+ return;
11802
+ }
11356
11803
 
11357
- if (!subscribedQuality) {
11358
- return;
11359
- }
11804
+ if (encodings.length !== senderEncodings.length) {
11805
+ livekitLogger.warn('cannot set publishing layers, encodings mismatch');
11806
+ return;
11807
+ }
11360
11808
 
11361
- if (encoding.active !== subscribedQuality.enabled) {
11362
- hasChanged = true;
11363
- encoding.active = subscribedQuality.enabled;
11364
- livekitLogger.debug("setting layer ".concat(subscribedQuality.quality, " to ").concat(encoding.active ? 'enabled' : 'disabled')); // FireFox does not support setting encoding.active to false, so we
11365
- // have a workaround of lowering its bitrate and resolution to the min.
11809
+ let hasChanged = false;
11810
+ encodings.forEach((encoding, idx) => {
11811
+ var _a;
11366
11812
 
11367
- if (isFireFox()) {
11368
- if (subscribedQuality.enabled) {
11369
- encoding.scaleResolutionDownBy = this.encodings[idx].scaleResolutionDownBy;
11370
- encoding.maxBitrate = this.encodings[idx].maxBitrate;
11371
- /* @ts-ignore */
11813
+ let rid = (_a = encoding.rid) !== null && _a !== void 0 ? _a : '';
11372
11814
 
11373
- encoding.maxFrameRate = this.encodings[idx].maxFrameRate;
11374
- } else {
11375
- encoding.scaleResolutionDownBy = 4;
11376
- encoding.maxBitrate = 10;
11377
- /* @ts-ignore */
11815
+ if (rid === '') {
11816
+ rid = 'q';
11817
+ }
11378
11818
 
11379
- encoding.maxFrameRate = 2;
11380
- }
11381
- }
11382
- }
11383
- });
11819
+ const quality = videoQualityForRid(rid);
11820
+ const subscribedQuality = qualities.find(q => q.quality === quality);
11384
11821
 
11385
- if (hasChanged) {
11386
- params.encodings = encodings;
11387
- await this.sender.setParameters(params);
11822
+ if (!subscribedQuality) {
11823
+ return;
11388
11824
  }
11389
- }
11390
11825
 
11391
- async handleAppVisibilityChanged() {
11392
- await super.handleAppVisibilityChanged();
11393
- if (!isMobile()) return;
11826
+ if (encoding.active !== subscribedQuality.enabled) {
11827
+ hasChanged = true;
11828
+ encoding.active = subscribedQuality.enabled;
11829
+ livekitLogger.debug("setting layer ".concat(subscribedQuality.quality, " to ").concat(encoding.active ? 'enabled' : 'disabled')); // FireFox does not support setting encoding.active to false, so we
11830
+ // have a workaround of lowering its bitrate and resolution to the min.
11394
11831
 
11395
- if (this.isInBackground && this.source === Track.Source.Camera) {
11396
- this._mediaStreamTrack.enabled = false;
11832
+ if (isFireFox()) {
11833
+ if (subscribedQuality.enabled) {
11834
+ encoding.scaleResolutionDownBy = senderEncodings[idx].scaleResolutionDownBy;
11835
+ encoding.maxBitrate = senderEncodings[idx].maxBitrate;
11836
+ /* @ts-ignore */
11837
+
11838
+ encoding.maxFrameRate = senderEncodings[idx].maxFrameRate;
11839
+ } else {
11840
+ encoding.scaleResolutionDownBy = 4;
11841
+ encoding.maxBitrate = 10;
11842
+ /* @ts-ignore */
11843
+
11844
+ encoding.maxFrameRate = 2;
11845
+ }
11846
+ }
11397
11847
  }
11398
- }
11848
+ });
11399
11849
 
11850
+ if (hasChanged) {
11851
+ params.encodings = encodings;
11852
+ await sender.setParameters(params);
11853
+ }
11400
11854
  }
11855
+
11401
11856
  function videoQualityForRid(rid) {
11402
11857
  switch (rid) {
11403
11858
  case 'f':
@@ -11448,7 +11903,6 @@ function videoLayersFromEncodings(width, height, encodings) {
11448
11903
  class RemoteTrack extends Track {
11449
11904
  constructor(mediaTrack, sid, kind, receiver) {
11450
11905
  super(mediaTrack, kind);
11451
- this.streamState = Track.StreamState.Active;
11452
11906
  this.sid = sid;
11453
11907
  this.receiver = receiver;
11454
11908
  }
@@ -11657,21 +12111,6 @@ class RemoteVideoTrack extends RemoteTrack {
11657
12111
  }, monitorFrequency);
11658
12112
  };
11659
12113
 
11660
- this.handleVisibilityChanged = entry => {
11661
- const {
11662
- target,
11663
- isIntersecting
11664
- } = entry;
11665
- const elementInfo = this.elementInfos.find(info => info.element === target);
11666
-
11667
- if (elementInfo) {
11668
- elementInfo.visible = isIntersecting;
11669
- elementInfo.visibilityChangedAt = Date.now();
11670
- }
11671
-
11672
- this.updateVisibility();
11673
- };
11674
-
11675
12114
  this.debouncedHandleResize = r(() => {
11676
12115
  this.updateDimensions();
11677
12116
  }, REACTION_DELAY);
@@ -11718,23 +12157,55 @@ class RemoteVideoTrack extends RemoteTrack {
11718
12157
 
11719
12158
 
11720
12159
  if (this.adaptiveStreamSettings && this.elementInfos.find(info => info.element === element) === undefined) {
11721
- this.elementInfos.push({
11722
- element,
11723
- visible: true // default visible
12160
+ const elementInfo = new HTMLElementInfo(element);
12161
+ this.observeElementInfo(elementInfo);
12162
+ }
11724
12163
 
11725
- });
11726
- element.handleResize = this.debouncedHandleResize;
11727
- element.handleVisibilityChanged = this.handleVisibilityChanged;
11728
- getIntersectionObserver().observe(element);
11729
- getResizeObserver().observe(element); // trigger the first resize update cycle
12164
+ this.hasUsedAttach = true;
12165
+ return element;
12166
+ }
12167
+ /**
12168
+ * Observe an ElementInfo for changes when adaptive streaming.
12169
+ * @param elementInfo
12170
+ * @internal
12171
+ */
12172
+
12173
+
12174
+ observeElementInfo(elementInfo) {
12175
+ if (this.adaptiveStreamSettings && this.elementInfos.find(info => info === elementInfo) === undefined) {
12176
+ elementInfo.handleResize = () => {
12177
+ this.debouncedHandleResize();
12178
+ };
12179
+
12180
+ elementInfo.handleVisibilityChanged = () => {
12181
+ this.updateVisibility();
12182
+ };
12183
+
12184
+ this.elementInfos.push(elementInfo);
12185
+ elementInfo.observe(); // trigger the first resize update cycle
11730
12186
  // if the tab is backgrounded, the initial resize event does not fire until
11731
12187
  // the tab comes into focus for the first time.
11732
12188
 
11733
12189
  this.debouncedHandleResize();
12190
+ this.updateVisibility();
11734
12191
  }
12192
+ }
12193
+ /**
12194
+ * Stop observing an ElementInfo for changes.
12195
+ * @param elementInfo
12196
+ * @internal
12197
+ */
11735
12198
 
11736
- this.hasUsedAttach = true;
11737
- return element;
12199
+
12200
+ stopObservingElementInfo(elementInfo) {
12201
+ const stopElementInfos = this.elementInfos.filter(info => info === elementInfo);
12202
+
12203
+ for (const info of stopElementInfos) {
12204
+ info.stopObserving();
12205
+ }
12206
+
12207
+ this.elementInfos = this.elementInfos.filter(info => info !== elementInfo);
12208
+ this.updateVisibility();
11738
12209
  }
11739
12210
 
11740
12211
  detach(element) {
@@ -11753,6 +12224,14 @@ class RemoteVideoTrack extends RemoteTrack {
11753
12224
 
11754
12225
  return detachedElements;
11755
12226
  }
12227
+ /** @internal */
12228
+
12229
+
12230
+ getDecoderImplementation() {
12231
+ var _a;
12232
+
12233
+ return (_a = this.prevStats) === null || _a === void 0 ? void 0 : _a.decoderImplementation;
12234
+ }
11756
12235
 
11757
12236
  async getReceiverStats() {
11758
12237
  if (!this.receiver) {
@@ -11777,7 +12256,8 @@ class RemoteVideoTrack extends RemoteTrack {
11777
12256
  nackCount: v.nackCount,
11778
12257
  jitter: v.jitter,
11779
12258
  timestamp: v.timestamp,
11780
- bytesReceived: v.bytesReceived
12259
+ bytesReceived: v.bytesReceived,
12260
+ decoderImplementation: v.decoderImplementation
11781
12261
  };
11782
12262
  }
11783
12263
  });
@@ -11785,24 +12265,28 @@ class RemoteVideoTrack extends RemoteTrack {
11785
12265
  }
11786
12266
 
11787
12267
  stopObservingElement(element) {
11788
- var _a, _b;
12268
+ const stopElementInfos = this.elementInfos.filter(info => info.element === element);
12269
+
12270
+ for (const info of stopElementInfos) {
12271
+ info.stopObserving();
12272
+ }
11789
12273
 
11790
- (_a = getIntersectionObserver()) === null || _a === void 0 ? void 0 : _a.unobserve(element);
11791
- (_b = getResizeObserver()) === null || _b === void 0 ? void 0 : _b.unobserve(element);
11792
12274
  this.elementInfos = this.elementInfos.filter(info => info.element !== element);
11793
12275
  }
11794
12276
 
11795
12277
  async handleAppVisibilityChanged() {
11796
12278
  await super.handleAppVisibilityChanged();
11797
- if (!this.isAdaptiveStream) return; // on desktop don't pause when tab is backgrounded
11798
-
11799
- if (!isMobile()) return;
12279
+ if (!this.isAdaptiveStream) return;
11800
12280
  this.updateVisibility();
11801
12281
  }
11802
12282
 
11803
12283
  updateVisibility() {
12284
+ var _a, _b;
12285
+
11804
12286
  const lastVisibilityChange = this.elementInfos.reduce((prev, info) => Math.max(prev, info.visibilityChangedAt || 0), 0);
11805
- const isVisible = this.elementInfos.some(info => info.visible) && !this.isInBackground;
12287
+ const backgroundPause = ((_b = (_a = this.adaptiveStreamSettings) === null || _a === void 0 ? void 0 : _a.pauseVideoInBackground) !== null && _b !== void 0 ? _b : true // default to true
12288
+ ) ? this.isInBackground : false;
12289
+ const isVisible = this.elementInfos.some(info => info.visible) && !backgroundPause;
11806
12290
 
11807
12291
  if (this.lastVisible === isVisible) {
11808
12292
  return;
@@ -11829,8 +12313,8 @@ class RemoteVideoTrack extends RemoteTrack {
11829
12313
  for (const info of this.elementInfos) {
11830
12314
  const pixelDensity = (_b = (_a = this.adaptiveStreamSettings) === null || _a === void 0 ? void 0 : _a.pixelDensity) !== null && _b !== void 0 ? _b : 1;
11831
12315
  const pixelDensityValue = pixelDensity === 'screen' ? window.devicePixelRatio : pixelDensity;
11832
- const currentElementWidth = info.element.clientWidth * pixelDensityValue;
11833
- const currentElementHeight = info.element.clientHeight * pixelDensityValue;
12316
+ const currentElementWidth = info.width() * pixelDensityValue;
12317
+ const currentElementHeight = info.height() * pixelDensityValue;
11834
12318
 
11835
12319
  if (currentElementWidth + currentElementHeight > maxWidth + maxHeight) {
11836
12320
  maxWidth = currentElementWidth;
@@ -11851,6 +12335,59 @@ class RemoteVideoTrack extends RemoteTrack {
11851
12335
 
11852
12336
  }
11853
12337
 
12338
+ class HTMLElementInfo {
12339
+ constructor(element) {
12340
+ let visible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
12341
+
12342
+ this.onVisibilityChanged = entry => {
12343
+ var _a;
12344
+
12345
+ const {
12346
+ target,
12347
+ isIntersecting
12348
+ } = entry;
12349
+
12350
+ if (target === this.element) {
12351
+ this.visible = isIntersecting;
12352
+ this.visibilityChangedAt = Date.now();
12353
+ (_a = this.handleVisibilityChanged) === null || _a === void 0 ? void 0 : _a.call(this);
12354
+ }
12355
+ };
12356
+
12357
+ this.element = element;
12358
+ this.visible = visible;
12359
+ this.visibilityChangedAt = 0;
12360
+ }
12361
+
12362
+ width() {
12363
+ return this.element.clientWidth;
12364
+ }
12365
+
12366
+ height() {
12367
+ return this.element.clientWidth;
12368
+ }
12369
+
12370
+ observe() {
12371
+ this.element.handleResize = () => {
12372
+ var _a;
12373
+
12374
+ (_a = this.handleResize) === null || _a === void 0 ? void 0 : _a.call(this);
12375
+ };
12376
+
12377
+ this.element.handleVisibilityChanged = this.onVisibilityChanged;
12378
+ getIntersectionObserver().observe(this.element);
12379
+ getResizeObserver().observe(this.element);
12380
+ }
12381
+
12382
+ stopObserving() {
12383
+ var _a, _b;
12384
+
12385
+ (_a = getIntersectionObserver()) === null || _a === void 0 ? void 0 : _a.unobserve(this.element);
12386
+ (_b = getResizeObserver()) === null || _b === void 0 ? void 0 : _b.unobserve(this.element);
12387
+ }
12388
+
12389
+ }
12390
+
11854
12391
  class TrackPublication extends events.exports.EventEmitter {
11855
12392
  constructor(kind, id, name) {
11856
12393
  super();
@@ -12830,6 +13367,7 @@ class RemoteParticipant extends Participant {
12830
13367
  super.addTrackPublication(publication); // register action events
12831
13368
 
12832
13369
  publication.on(TrackEvent.UpdateSettings, settings => {
13370
+ livekitLogger.debug('send update settings', settings);
12833
13371
  this.signalClient.sendUpdateTrackSettings(settings);
12834
13372
  });
12835
13373
  publication.on(TrackEvent.UpdateSubscription, sub => {
@@ -13067,13 +13605,25 @@ class RemoteParticipant extends Participant {
13067
13605
 
13068
13606
  }
13069
13607
 
13608
+ const compatibleCodecForSVC = 'vp8';
13070
13609
  class LocalParticipant extends Participant {
13071
13610
  /** @internal */
13072
13611
  constructor(sid, identity, engine, options) {
13073
13612
  super(sid, identity);
13074
13613
  this.pendingPublishing = new Set();
13614
+ this.participantTrackPermissions = [];
13615
+ this.allParticipantsAllowedToSubscribe = true;
13616
+
13617
+ this.updateTrackSubscriptionPermissions = () => {
13618
+ livekitLogger.debug('updating track subscription permissions', {
13619
+ allParticipantsAllowed: this.allParticipantsAllowedToSubscribe,
13620
+ participantTrackPermissions: this.participantTrackPermissions
13621
+ });
13622
+ this.engine.client.sendUpdateSubscriptionPermissions(this.allParticipantsAllowedToSubscribe, this.participantTrackPermissions.map(p => trackPermissionToProto(p)));
13623
+ };
13075
13624
  /** @internal */
13076
13625
 
13626
+
13077
13627
  this.onTrackUnmuted = track => {
13078
13628
  this.onTrackMuted(track, track.isUpstreamPaused);
13079
13629
  }; // when the local track changes in mute status, we'll notify server as such
@@ -13105,7 +13655,7 @@ class LocalParticipant extends Participant {
13105
13655
  };
13106
13656
 
13107
13657
  this.handleSubscribedQualityUpdate = update => {
13108
- var _a, _b;
13658
+ var _a, _b, _c;
13109
13659
 
13110
13660
  if (!((_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.dynacast)) {
13111
13661
  return;
@@ -13121,7 +13671,11 @@ class LocalParticipant extends Participant {
13121
13671
  return;
13122
13672
  }
13123
13673
 
13124
- (_b = pub.videoTrack) === null || _b === void 0 ? void 0 : _b.setPublishingLayers(update.subscribedQualities);
13674
+ if (update.subscribedCodecs.length > 0) {
13675
+ (_b = pub.videoTrack) === null || _b === void 0 ? void 0 : _b.setPublishingCodecs(update.subscribedCodecs);
13676
+ } else if (update.subscribedQualities.length > 0) {
13677
+ (_c = pub.videoTrack) === null || _c === void 0 ? void 0 : _c.setPublishingLayers(update.subscribedQualities);
13678
+ }
13125
13679
  };
13126
13680
 
13127
13681
  this.handleLocalTrackUnpublished = unpublished => {
@@ -13138,7 +13692,10 @@ class LocalParticipant extends Participant {
13138
13692
  this.unpublishTrack(track.track);
13139
13693
  };
13140
13694
 
13141
- this.onTrackUnpublish = track => {
13695
+ this.handleTrackEnded = track => {
13696
+ livekitLogger.debug('unpublishing local track due to TrackEnded', {
13697
+ track: track.sid
13698
+ });
13142
13699
  this.unpublishTrack(track);
13143
13700
  };
13144
13701
 
@@ -13164,6 +13721,7 @@ class LocalParticipant extends Participant {
13164
13721
 
13165
13722
  this.engine.client.onSubscribedQualityUpdate = this.handleSubscribedQualityUpdate;
13166
13723
  this.engine.client.onLocalTrackUnpublished = this.handleLocalTrackUnpublished;
13724
+ this.engine.on(EngineEvent.Connected, this.updateTrackSubscriptionPermissions).on(EngineEvent.Restarted, this.updateTrackSubscriptionPermissions).on(EngineEvent.Resumed, this.updateTrackSubscriptionPermissions);
13167
13725
  }
13168
13726
 
13169
13727
  get lastCameraError() {
@@ -13506,7 +14064,7 @@ class LocalParticipant extends Participant {
13506
14064
 
13507
14065
  track.on(TrackEvent.Muted, this.onTrackMuted);
13508
14066
  track.on(TrackEvent.Unmuted, this.onTrackUnmuted);
13509
- track.on(TrackEvent.Ended, this.onTrackUnpublish);
14067
+ track.on(TrackEvent.Ended, this.handleTrackEnded);
13510
14068
  track.on(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused);
13511
14069
  track.on(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed); // create track publication from track
13512
14070
 
@@ -13521,6 +14079,8 @@ class LocalParticipant extends Participant {
13521
14079
  }); // compute encodings and layers for video
13522
14080
 
13523
14081
  let encodings;
14082
+ let simEncodings;
14083
+ let simulcastTracks;
13524
14084
 
13525
14085
  if (track.kind === Track.Kind.Video) {
13526
14086
  // TODO: support react native, which doesn't expose getSettings
@@ -13529,21 +14089,32 @@ class LocalParticipant extends Participant {
13529
14089
  const height = (_e = settings.height) !== null && _e !== void 0 ? _e : (_f = track.dimensions) === null || _f === void 0 ? void 0 : _f.height; // width and height should be defined for video
13530
14090
 
13531
14091
  req.width = width !== null && width !== void 0 ? width : 0;
13532
- req.height = height !== null && height !== void 0 ? height : 0; // for svc codecs, disable simulcast and enable scalability L3T3
13533
- // by default
13534
-
13535
- if (track instanceof LocalVideoTrack) {
13536
- if ((opts === null || opts === void 0 ? void 0 : opts.videoCodec) === 'vp9' || (opts === null || opts === void 0 ? void 0 : opts.videoCodec) === 'av1') {
13537
- opts.simulcast = false;
13538
- opts.scalabilityMode = (_g = opts.scalabilityMode) !== null && _g !== void 0 ? _g : 'L3T3';
13539
- } else {
13540
- // other codecs, unset scalability
13541
- opts.scalabilityMode = undefined;
13542
- }
14092
+ req.height = height !== null && height !== void 0 ? height : 0; // for svc codecs, disable simulcast and use vp8 for backup codec
14093
+
14094
+ if (track instanceof LocalVideoTrack && ((opts === null || opts === void 0 ? void 0 : opts.videoCodec) === 'vp9' || (opts === null || opts === void 0 ? void 0 : opts.videoCodec) === 'av1')) {
14095
+ // set scalabilityMode to 'L3T3' by default
14096
+ opts.scalabilityMode = (_g = opts.scalabilityMode) !== null && _g !== void 0 ? _g : 'L3T3'; // add backup codec track
14097
+
14098
+ const simOpts = _objectSpread2({}, opts);
14099
+
14100
+ simOpts.simulcast = true;
14101
+ simOpts.scalabilityMode = undefined;
14102
+ simEncodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, width, height, simOpts);
14103
+ const simulcastTrack = track.addSimulcastTrack(compatibleCodecForSVC, simEncodings);
14104
+ simulcastTracks = [simulcastTrack];
14105
+ req.simulcastCodecs = [{
14106
+ codec: opts.videoCodec,
14107
+ cid: track.mediaStreamTrack.id,
14108
+ enableSimulcastLayers: true
14109
+ }, {
14110
+ codec: simulcastTrack.codec,
14111
+ cid: simulcastTrack.mediaStreamTrack.id,
14112
+ enableSimulcastLayers: true
14113
+ }];
13543
14114
  }
13544
14115
 
13545
14116
  encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, width, height, opts);
13546
- req.layers = videoLayersFromEncodings(req.width, req.height, encodings);
14117
+ req.layers = videoLayersFromEncodings(req.width, req.height, simEncodings !== null && simEncodings !== void 0 ? simEncodings : encodings);
13547
14118
  } else if (track.kind === Track.Kind.Audio && opts.audioBitrate) {
13548
14119
  encodings = [{
13549
14120
  maxBitrate: opts.audioBitrate
@@ -13555,7 +14126,9 @@ class LocalParticipant extends Participant {
13555
14126
  }
13556
14127
 
13557
14128
  const ti = await this.engine.addTrack(req);
13558
- const publication = new LocalTrackPublication(track.kind, ti, track);
14129
+ const publication = new LocalTrackPublication(track.kind, ti, track); // save options for when it needs to be republished again
14130
+
14131
+ publication.options = opts;
13559
14132
  track.sid = ti.sid;
13560
14133
 
13561
14134
  if (!this.engine.publisher) {
@@ -13572,12 +14145,32 @@ class LocalParticipant extends Participant {
13572
14145
 
13573
14146
  if (encodings) {
13574
14147
  transceiverInit.sendEncodings = encodings;
13575
- }
14148
+ } // addTransceiver for react-native is async. web is synchronous, but await won't effect it.
13576
14149
 
13577
- const transceiver = this.engine.publisher.pc.addTransceiver(track.mediaStreamTrack, transceiverInit);
13578
14150
 
13579
- if (opts.videoCodec) {
14151
+ const transceiver = await this.engine.publisher.pc.addTransceiver(track.mediaStreamTrack, transceiverInit);
14152
+
14153
+ if (track.kind === Track.Kind.Video && opts.videoCodec) {
13580
14154
  this.setPreferredCodec(transceiver, track.kind, opts.videoCodec);
14155
+ track.codec = opts.videoCodec;
14156
+ }
14157
+
14158
+ const localTrack = track;
14159
+
14160
+ if (simulcastTracks) {
14161
+ for await (const simulcastTrack of simulcastTracks) {
14162
+ const simTransceiverInit = {
14163
+ direction: 'sendonly'
14164
+ };
14165
+
14166
+ if (simulcastTrack.encodings) {
14167
+ simTransceiverInit.sendEncodings = simulcastTrack.encodings;
14168
+ }
14169
+
14170
+ const simTransceiver = await this.engine.publisher.pc.addTransceiver(simulcastTrack.mediaStreamTrack, simTransceiverInit);
14171
+ this.setPreferredCodec(simTransceiver, localTrack.kind, simulcastTrack.codec);
14172
+ localTrack.setSimulcastTrackSender(simulcastTrack.codec, simTransceiver.sender);
14173
+ }
13581
14174
  }
13582
14175
 
13583
14176
  this.engine.negotiate(); // store RTPSender
@@ -13615,9 +14208,10 @@ class LocalParticipant extends Participant {
13615
14208
  }
13616
14209
 
13617
14210
  track = publication.track;
14211
+ track.sender = undefined;
13618
14212
  track.off(TrackEvent.Muted, this.onTrackMuted);
13619
14213
  track.off(TrackEvent.Unmuted, this.onTrackUnmuted);
13620
- track.off(TrackEvent.Ended, this.onTrackUnpublish);
14214
+ track.off(TrackEvent.Ended, this.handleTrackEnded);
13621
14215
  track.off(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused);
13622
14216
  track.off(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed);
13623
14217
 
@@ -13633,7 +14227,7 @@ class LocalParticipant extends Participant {
13633
14227
  mediaStreamTrack
13634
14228
  } = track;
13635
14229
 
13636
- if (this.engine.publisher) {
14230
+ if (this.engine.publisher && this.engine.publisher.pc.connectionState !== 'closed') {
13637
14231
  const senders = this.engine.publisher.pc.getSenders();
13638
14232
  senders.forEach(sender => {
13639
14233
  var _a;
@@ -13738,7 +14332,12 @@ class LocalParticipant extends Participant {
13738
14332
 
13739
14333
  setTrackSubscriptionPermissions(allParticipantsAllowed) {
13740
14334
  let participantTrackPermissions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
13741
- this.engine.client.sendUpdateSubscriptionPermissions(allParticipantsAllowed, participantTrackPermissions.map(p => trackPermissionToProto(p)));
14335
+ this.participantTrackPermissions = participantTrackPermissions;
14336
+ this.allParticipantsAllowedToSubscribe = allParticipantsAllowed;
14337
+
14338
+ if (this.engine.client.isConnected) {
14339
+ this.updateTrackSubscriptionPermissions();
14340
+ }
13742
14341
  }
13743
14342
 
13744
14343
  getPublicationForTrack(track) {
@@ -13771,6 +14370,7 @@ class LocalParticipant extends Participant {
13771
14370
 
13772
14371
  const cap = RTCRtpSender.getCapabilities(kind);
13773
14372
  if (!cap) return;
14373
+ livekitLogger.debug('get capabilities', cap);
13774
14374
  let selected;
13775
14375
  const codecs = [];
13776
14376
  cap.codecs.forEach(c => {
@@ -17620,8 +18220,8 @@ class SignalClient {
17620
18220
  });
17621
18221
  }
17622
18222
 
17623
- sendLeave() {
17624
- this.sendRequest(SignalRequest.fromPartial({
18223
+ async sendLeave() {
18224
+ await this.sendRequest(SignalRequest.fromPartial({
17625
18225
  leave: {}
17626
18226
  }));
17627
18227
  }
@@ -17930,6 +18530,7 @@ class RTCEngine extends events.exports.EventEmitter {
17930
18530
  this.reconnectAttempts = 0;
17931
18531
  this.reconnectStart = 0;
17932
18532
  this.fullReconnectOnNext = false;
18533
+ this.attemptingReconnect = false;
17933
18534
 
17934
18535
  this.handleDataChannel = async _ref => {
17935
18536
  let {
@@ -18006,18 +18607,27 @@ class RTCEngine extends events.exports.EventEmitter {
18006
18607
 
18007
18608
  const delay = this.reconnectAttempts * this.reconnectAttempts * 300;
18008
18609
  setTimeout(async () => {
18009
- var _a;
18610
+ var _a, _b, _c;
18010
18611
 
18011
18612
  if (this._isClosed) {
18012
18613
  return;
18614
+ } // guard for attempting reconnection multiple times while one attempt is still not finished
18615
+
18616
+
18617
+ if (this.attemptingReconnect) {
18618
+ return;
18013
18619
  }
18014
18620
 
18015
18621
  if (isFireFox() || // TODO remove once clientConfiguration handles firefox case server side
18016
- ((_a = this.clientConfiguration) === null || _a === void 0 ? void 0 : _a.resumeConnection) === ClientConfigSetting.DISABLED) {
18622
+ ((_a = this.clientConfiguration) === null || _a === void 0 ? void 0 : _a.resumeConnection) === ClientConfigSetting.DISABLED || // signaling state could change to closed due to hardware sleep
18623
+ // those connections cannot be resumed
18624
+ ((_c = (_b = this.primaryPC) === null || _b === void 0 ? void 0 : _b.signalingState) !== null && _c !== void 0 ? _c : 'closed') === 'closed') {
18017
18625
  this.fullReconnectOnNext = true;
18018
18626
  }
18019
18627
 
18020
18628
  try {
18629
+ this.attemptingReconnect = true;
18630
+
18021
18631
  if (this.fullReconnectOnNext) {
18022
18632
  await this.restartConnection();
18023
18633
  } else {
@@ -18028,6 +18638,7 @@ class RTCEngine extends events.exports.EventEmitter {
18028
18638
  this.fullReconnectOnNext = false;
18029
18639
  } catch (e) {
18030
18640
  this.reconnectAttempts += 1;
18641
+ let reconnectRequired = false;
18031
18642
  let recoverable = true;
18032
18643
 
18033
18644
  if (e instanceof UnexpectedConnectionState) {
@@ -18038,7 +18649,14 @@ class RTCEngine extends events.exports.EventEmitter {
18038
18649
  recoverable = false;
18039
18650
  } else if (!(e instanceof SignalReconnectError)) {
18040
18651
  // cannot resume
18652
+ reconnectRequired = true;
18653
+ } // when we flip from resume to reconnect, we need to reset reconnectAttempts
18654
+ // this is needed to fire the right reconnecting events
18655
+
18656
+
18657
+ if (reconnectRequired && !this.fullReconnectOnNext) {
18041
18658
  this.fullReconnectOnNext = true;
18659
+ this.reconnectAttempts = 0;
18042
18660
  }
18043
18661
 
18044
18662
  const duration = Date.now() - this.reconnectStart;
@@ -18054,6 +18672,8 @@ class RTCEngine extends events.exports.EventEmitter {
18054
18672
  this.emit(EngineEvent.Disconnected);
18055
18673
  this.close();
18056
18674
  }
18675
+ } finally {
18676
+ this.attemptingReconnect = false;
18057
18677
  }
18058
18678
  }, delay);
18059
18679
  };
@@ -18202,7 +18822,7 @@ class RTCEngine extends events.exports.EventEmitter {
18202
18822
  this.primaryPC = primaryPC;
18203
18823
 
18204
18824
  primaryPC.onconnectionstatechange = async () => {
18205
- livekitLogger.trace('connection state changed', {
18825
+ livekitLogger.debug('primary PC state changed', {
18206
18826
  state: primaryPC.connectionState
18207
18827
  });
18208
18828
 
@@ -18231,7 +18851,10 @@ class RTCEngine extends events.exports.EventEmitter {
18231
18851
  };
18232
18852
 
18233
18853
  secondaryPC.onconnectionstatechange = async () => {
18234
- // also reconnect if secondary peerconnection fails
18854
+ livekitLogger.debug('secondary PC state changed', {
18855
+ state: secondaryPC.connectionState
18856
+ }); // also reconnect if secondary peerconnection fails
18857
+
18235
18858
  if (secondaryPC.connectionState === 'failed') {
18236
18859
  this.handleDisconnect('secondary peerconnection');
18237
18860
  }
@@ -18359,6 +18982,11 @@ class RTCEngine extends events.exports.EventEmitter {
18359
18982
  this.emit(EngineEvent.Restarting);
18360
18983
  }
18361
18984
 
18985
+ if (this.client.isConnected) {
18986
+ this.client.sendLeave();
18987
+ }
18988
+
18989
+ this.client.close();
18362
18990
  this.primaryPC = undefined;
18363
18991
  (_a = this.publisher) === null || _a === void 0 ? void 0 : _a.close();
18364
18992
  this.publisher = undefined;
@@ -18721,6 +19349,7 @@ class Room extends events.exports.EventEmitter {
18721
19349
  this.name = joinResponse.room.name;
18722
19350
  this.sid = joinResponse.room.sid;
18723
19351
  this.metadata = joinResponse.room.metadata;
19352
+ this.emit(RoomEvent.SignalConnected);
18724
19353
  } catch (err) {
18725
19354
  this.engine.close();
18726
19355
  this.setAndEmitConnectionState(ConnectionState.Disconnected);
@@ -18775,7 +19404,7 @@ class Room extends events.exports.EventEmitter {
18775
19404
  this.disconnect = function () {
18776
19405
  let stopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
18777
19406
 
18778
- var _a;
19407
+ var _a, _b;
18779
19408
 
18780
19409
  if (_this.state === ConnectionState.Connecting) {
18781
19410
  // try aborting pending connection attempt
@@ -18785,9 +19414,12 @@ class Room extends events.exports.EventEmitter {
18785
19414
  } // send leave
18786
19415
 
18787
19416
 
18788
- if (_this.engine) {
19417
+ if ((_b = _this.engine) === null || _b === void 0 ? void 0 : _b.client.isConnected) {
18789
19418
  _this.engine.client.sendLeave();
19419
+ } // close engine (also closes client)
18790
19420
 
19421
+
19422
+ if (_this.engine) {
18791
19423
  _this.engine.close();
18792
19424
  }
18793
19425
 
@@ -18803,8 +19435,10 @@ class Room extends events.exports.EventEmitter {
18803
19435
  };
18804
19436
 
18805
19437
  this.handleRestarting = () => {
18806
- this.setAndEmitConnectionState(ConnectionState.Reconnecting);
18807
- this.emit(RoomEvent.Reconnecting); // also unwind existing participants & existing subscriptions
19438
+ if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
19439
+ this.emit(RoomEvent.Reconnecting);
19440
+ } // also unwind existing participants & existing subscriptions
19441
+
18808
19442
 
18809
19443
  for (const p of this.participants.values()) {
18810
19444
  this.handleParticipantDisconnected(p.sid, p);
@@ -18812,7 +19446,9 @@ class Room extends events.exports.EventEmitter {
18812
19446
  };
18813
19447
 
18814
19448
  this.handleRestarted = async joinResponse => {
18815
- livekitLogger.debug("reconnected to server region ".concat(joinResponse.serverRegion));
19449
+ livekitLogger.debug("reconnected to server", {
19450
+ region: joinResponse.serverRegion
19451
+ });
18816
19452
  this.setAndEmitConnectionState(ConnectionState.Connected);
18817
19453
  this.emit(RoomEvent.Reconnected); // rehydrate participants
18818
19454
 
@@ -18833,7 +19469,19 @@ class Room extends events.exports.EventEmitter {
18833
19469
  await Promise.all(localPubs.map(async pub => {
18834
19470
  const track = pub.track;
18835
19471
  this.localParticipant.unpublishTrack(track, false);
18836
- this.localParticipant.publishTrack(track, pub.options);
19472
+
19473
+ if (!track.isMuted) {
19474
+ if (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) {
19475
+ // we need to restart the track before publishing, often a full reconnect
19476
+ // is necessary because computer had gone to sleep.
19477
+ livekitLogger.debug('restarting existing track', {
19478
+ track: pub.trackSid
19479
+ });
19480
+ await track.restartTrack();
19481
+ }
19482
+
19483
+ await this.localParticipant.publishTrack(track, pub.options);
19484
+ }
18837
19485
  }));
18838
19486
  };
18839
19487
 
@@ -18843,6 +19491,14 @@ class Room extends events.exports.EventEmitter {
18843
19491
  if (info.sid === this.localParticipant.sid || info.identity === this.localParticipant.identity) {
18844
19492
  this.localParticipant.updateInfo(info);
18845
19493
  return;
19494
+ } // ensure identity <=> sid mapping
19495
+
19496
+
19497
+ const sid = this.identityToSid.get(info.identity);
19498
+
19499
+ if (sid && sid !== info.sid) {
19500
+ // sid had changed, need to remove previous participant
19501
+ this.handleParticipantDisconnected(sid, this.participants.get(sid));
18846
19502
  }
18847
19503
 
18848
19504
  let remoteParticipant = this.participants.get(info.sid);
@@ -18853,7 +19509,8 @@ class Room extends events.exports.EventEmitter {
18853
19509
  if (info.state === ParticipantInfo_State.DISCONNECTED) {
18854
19510
  this.handleParticipantDisconnected(info.sid, remoteParticipant);
18855
19511
  } else if (isNewParticipant) {
18856
- // fire connected event
19512
+ this.identityToSid.set(info.identity, info.sid); // fire connected event
19513
+
18857
19514
  this.emit(RoomEvent.ParticipantConnected, remoteParticipant);
18858
19515
  } else {
18859
19516
  // just update, no events
@@ -19022,6 +19679,7 @@ class Room extends events.exports.EventEmitter {
19022
19679
  };
19023
19680
 
19024
19681
  this.participants = new Map();
19682
+ this.identityToSid = new Map();
19025
19683
  this.options = options || {};
19026
19684
 
19027
19685
  switch ((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.publishDefaults) === null || _b === void 0 ? void 0 : _b.videoCodec) {
@@ -19056,8 +19714,9 @@ class Room extends events.exports.EventEmitter {
19056
19714
  }).on(EngineEvent.Disconnected, () => {
19057
19715
  this.handleDisconnect();
19058
19716
  }).on(EngineEvent.ActiveSpeakersUpdate, this.handleActiveSpeakersUpdate).on(EngineEvent.DataPacketReceived, this.handleDataPacket).on(EngineEvent.Resuming, () => {
19059
- this.setAndEmitConnectionState(ConnectionState.Reconnecting);
19060
- this.emit(RoomEvent.Reconnecting);
19717
+ if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
19718
+ this.emit(RoomEvent.Reconnecting);
19719
+ }
19061
19720
  }).on(EngineEvent.Resumed, () => {
19062
19721
  this.setAndEmitConnectionState(ConnectionState.Connected);
19063
19722
  this.emit(RoomEvent.Reconnected);
@@ -19090,15 +19749,15 @@ class Room extends events.exports.EventEmitter {
19090
19749
 
19091
19750
 
19092
19751
  getParticipantByIdentity(identity) {
19093
- for (const [, p] of this.participants) {
19094
- if (p.identity === identity) {
19095
- return p;
19096
- }
19097
- }
19098
-
19099
19752
  if (this.localParticipant.identity === identity) {
19100
19753
  return this.localParticipant;
19101
19754
  }
19755
+
19756
+ const sid = this.identityToSid.get(identity);
19757
+
19758
+ if (sid) {
19759
+ return this.participants.get(sid);
19760
+ }
19102
19761
  }
19103
19762
  /**
19104
19763
  * @internal for testing
@@ -19106,6 +19765,8 @@ class Room extends events.exports.EventEmitter {
19106
19765
 
19107
19766
 
19108
19767
  simulateScenario(scenario) {
19768
+ let postAction = () => {};
19769
+
19109
19770
  let req;
19110
19771
 
19111
19772
  switch (scenario) {
@@ -19132,10 +19793,26 @@ class Room extends events.exports.EventEmitter {
19132
19793
  migration: true
19133
19794
  });
19134
19795
  break;
19796
+
19797
+ case 'switch-candidate':
19798
+ req = SimulateScenario.fromPartial({
19799
+ switchCandidateProtocol: 1
19800
+ });
19801
+
19802
+ postAction = () => {
19803
+ var _a;
19804
+
19805
+ (_a = this.engine.publisher) === null || _a === void 0 ? void 0 : _a.createAndSendOffer({
19806
+ iceRestart: true
19807
+ });
19808
+ };
19809
+
19810
+ break;
19135
19811
  }
19136
19812
 
19137
19813
  if (req) {
19138
19814
  this.engine.client.sendSimulateScenario(req);
19815
+ postAction();
19139
19816
  }
19140
19817
  }
19141
19818
  /**
@@ -19258,7 +19935,7 @@ class Room extends events.exports.EventEmitter {
19258
19935
  var _a, _b;
19259
19936
 
19260
19937
  if (pub.track) {
19261
- this.localParticipant.unpublishTrack(pub.track);
19938
+ this.localParticipant.unpublishTrack(pub.track, shouldStopTracks);
19262
19939
  }
19263
19940
 
19264
19941
  if (shouldStopTracks) {
@@ -19291,8 +19968,9 @@ class Room extends events.exports.EventEmitter {
19291
19968
  return;
19292
19969
  }
19293
19970
 
19971
+ this.identityToSid.delete(participant.identity);
19294
19972
  participant.tracks.forEach(publication => {
19295
- participant.unpublishTrack(publication.trackSid);
19973
+ participant.unpublishTrack(publication.trackSid, true);
19296
19974
  });
19297
19975
  this.emit(RoomEvent.ParticipantDisconnected, participant);
19298
19976
  }
@@ -19420,11 +20098,13 @@ class Room extends events.exports.EventEmitter {
19420
20098
 
19421
20099
  setAndEmitConnectionState(state) {
19422
20100
  if (state === this.state) {
19423
- return;
20101
+ // unchanged
20102
+ return false;
19424
20103
  }
19425
20104
 
19426
20105
  this.state = state;
19427
20106
  this.emit(RoomEvent.ConnectionStateChanged, this.state);
20107
+ return true;
19428
20108
  } // /** @internal */
19429
20109
 
19430
20110