livekit-client 1.6.2 → 1.6.4

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 (64) hide show
  1. package/dist/livekit-client.esm.mjs +468 -140
  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/src/api/SignalClient.d.ts +3 -3
  6. package/dist/src/api/SignalClient.d.ts.map +1 -1
  7. package/dist/src/connectionHelper/ConnectionCheck.d.ts +2 -2
  8. package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
  9. package/dist/src/index.d.ts +2 -1
  10. package/dist/src/index.d.ts.map +1 -1
  11. package/dist/src/proto/livekit_models.d.ts +53 -4
  12. package/dist/src/proto/livekit_models.d.ts.map +1 -1
  13. package/dist/src/proto/livekit_rtc.d.ts +650 -91
  14. package/dist/src/proto/livekit_rtc.d.ts.map +1 -1
  15. package/dist/src/room/PCTransport.d.ts +1 -0
  16. package/dist/src/room/PCTransport.d.ts.map +1 -1
  17. package/dist/src/room/RTCEngine.d.ts +2 -0
  18. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  19. package/dist/src/room/Room.d.ts +1 -1
  20. package/dist/src/room/Room.d.ts.map +1 -1
  21. package/dist/src/room/errors.d.ts +3 -0
  22. package/dist/src/room/errors.d.ts.map +1 -1
  23. package/dist/src/room/participant/LocalParticipant.d.ts +1 -3
  24. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  25. package/dist/src/room/participant/Participant.d.ts +1 -1
  26. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  27. package/dist/src/room/timers.d.ts +13 -0
  28. package/dist/src/room/timers.d.ts.map +1 -0
  29. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  30. package/dist/src/room/track/create.d.ts.map +1 -1
  31. package/dist/src/room/track/options.d.ts +2 -2
  32. package/dist/src/room/track/options.d.ts.map +1 -1
  33. package/dist/src/test/mocks.d.ts +1 -1
  34. package/dist/ts4.2/src/api/SignalClient.d.ts +3 -3
  35. package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +2 -2
  36. package/dist/ts4.2/src/index.d.ts +2 -1
  37. package/dist/ts4.2/src/proto/livekit_models.d.ts +59 -4
  38. package/dist/ts4.2/src/proto/livekit_rtc.d.ts +739 -120
  39. package/dist/ts4.2/src/room/PCTransport.d.ts +1 -0
  40. package/dist/ts4.2/src/room/RTCEngine.d.ts +2 -0
  41. package/dist/ts4.2/src/room/Room.d.ts +1 -1
  42. package/dist/ts4.2/src/room/errors.d.ts +3 -0
  43. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +1 -3
  44. package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -1
  45. package/dist/ts4.2/src/room/timers.d.ts +13 -0
  46. package/dist/ts4.2/src/room/track/options.d.ts +2 -2
  47. package/dist/ts4.2/src/test/mocks.d.ts +1 -1
  48. package/package.json +17 -17
  49. package/src/api/SignalClient.ts +33 -21
  50. package/src/connectionHelper/ConnectionCheck.ts +1 -1
  51. package/src/index.ts +2 -0
  52. package/src/proto/google/protobuf/timestamp.ts +2 -2
  53. package/src/proto/livekit_models.ts +158 -10
  54. package/src/proto/livekit_rtc.ts +205 -6
  55. package/src/room/PCTransport.ts +22 -6
  56. package/src/room/RTCEngine.ts +58 -45
  57. package/src/room/Room.ts +8 -10
  58. package/src/room/errors.ts +6 -0
  59. package/src/room/participant/LocalParticipant.ts +12 -17
  60. package/src/room/participant/Participant.ts +10 -2
  61. package/src/room/timers.ts +16 -0
  62. package/src/room/track/RemoteVideoTrack.ts +2 -1
  63. package/src/room/track/create.ts +6 -1
  64. package/src/room/track/options.ts +2 -2
@@ -9,6 +9,9 @@ import {
9
9
  DisconnectReason,
10
10
  disconnectReasonFromJSON,
11
11
  disconnectReasonToJSON,
12
+ Encryption_Type,
13
+ encryption_TypeFromJSON,
14
+ encryption_TypeToJSON,
12
15
  ParticipantInfo,
13
16
  ParticipantTracks,
14
17
  Room,
@@ -148,7 +151,8 @@ export interface SignalRequest {
148
151
  | { $case: "subscriptionPermission"; subscriptionPermission: SubscriptionPermission }
149
152
  | { $case: "syncState"; syncState: SyncState }
150
153
  | { $case: "simulate"; simulate: SimulateScenario }
151
- | { $case: "ping"; ping: number };
154
+ | { $case: "ping"; ping: number }
155
+ | { $case: "updateMetadata"; updateMetadata: UpdateParticipantMetadata };
152
156
  }
153
157
 
154
158
  export interface SignalResponse {
@@ -169,7 +173,8 @@ export interface SignalResponse {
169
173
  | { $case: "subscriptionPermissionUpdate"; subscriptionPermissionUpdate: SubscriptionPermissionUpdate }
170
174
  | { $case: "refreshToken"; refreshToken: string }
171
175
  | { $case: "trackUnpublished"; trackUnpublished: TrackUnpublishedResponse }
172
- | { $case: "pong"; pong: number };
176
+ | { $case: "pong"; pong: number }
177
+ | { $case: "reconnect"; reconnect: ReconnectResponse };
173
178
  }
174
179
 
175
180
  export interface SimulcastCodec {
@@ -198,6 +203,7 @@ export interface AddTrackRequest {
198
203
  stereo: boolean;
199
204
  /** true if RED (Redundant Encoding) is disabled for audio */
200
205
  disableRed: boolean;
206
+ encryption: Encryption_Type;
201
207
  }
202
208
 
203
209
  export interface TrickleRequest {
@@ -232,6 +238,11 @@ export interface JoinResponse {
232
238
  serverInfo?: ServerInfo;
233
239
  }
234
240
 
241
+ export interface ReconnectResponse {
242
+ iceServers: ICEServer[];
243
+ clientConfiguration?: ClientConfiguration;
244
+ }
245
+
235
246
  export interface TrackPublishedResponse {
236
247
  cid: string;
237
248
  track?: TrackInfo;
@@ -267,8 +278,17 @@ export interface UpdateTrackSettings {
267
278
  width: number;
268
279
  /** for video, height to receive */
269
280
  height: number;
270
- /** for video, frame rate to receive */
271
281
  fps: number;
282
+ /**
283
+ * subscription priority. 1 being the highest (0 is unset)
284
+ * when unset, server sill assign priority based on the order of subscription
285
+ * server will use priority in the following ways:
286
+ * 1. when subscribed tracks exceed per-participant subscription limit, server will
287
+ * pause the lowest priority tracks
288
+ * 2. when the network is congested, server will assign available bandwidth to
289
+ * higher priority tracks first. lowest priority tracks can be paused
290
+ */
291
+ priority: number;
272
292
  }
273
293
 
274
294
  export interface LeaveRequest {
@@ -286,6 +306,10 @@ export interface UpdateVideoLayers {
286
306
  layers: VideoLayer[];
287
307
  }
288
308
 
309
+ export interface UpdateParticipantMetadata {
310
+ metadata: string;
311
+ }
312
+
289
313
  export interface ICEServer {
290
314
  urls: string[];
291
315
  username: string;
@@ -425,6 +449,9 @@ export const SignalRequest = {
425
449
  if (message.message?.$case === "ping") {
426
450
  writer.uint32(112).int64(message.message.ping);
427
451
  }
452
+ if (message.message?.$case === "updateMetadata") {
453
+ UpdateParticipantMetadata.encode(message.message.updateMetadata, writer.uint32(122).fork()).ldelim();
454
+ }
428
455
  return writer;
429
456
  },
430
457
 
@@ -480,6 +507,12 @@ export const SignalRequest = {
480
507
  case 14:
481
508
  message.message = { $case: "ping", ping: longToNumber(reader.int64() as Long) };
482
509
  break;
510
+ case 15:
511
+ message.message = {
512
+ $case: "updateMetadata",
513
+ updateMetadata: UpdateParticipantMetadata.decode(reader, reader.uint32()),
514
+ };
515
+ break;
483
516
  default:
484
517
  reader.skipType(tag & 7);
485
518
  break;
@@ -519,6 +552,8 @@ export const SignalRequest = {
519
552
  ? { $case: "simulate", simulate: SimulateScenario.fromJSON(object.simulate) }
520
553
  : isSet(object.ping)
521
554
  ? { $case: "ping", ping: Number(object.ping) }
555
+ : isSet(object.updateMetadata)
556
+ ? { $case: "updateMetadata", updateMetadata: UpdateParticipantMetadata.fromJSON(object.updateMetadata) }
522
557
  : undefined,
523
558
  };
524
559
  },
@@ -555,6 +590,9 @@ export const SignalRequest = {
555
590
  message.message?.$case === "simulate" &&
556
591
  (obj.simulate = message.message?.simulate ? SimulateScenario.toJSON(message.message?.simulate) : undefined);
557
592
  message.message?.$case === "ping" && (obj.ping = Math.round(message.message?.ping));
593
+ message.message?.$case === "updateMetadata" && (obj.updateMetadata = message.message?.updateMetadata
594
+ ? UpdateParticipantMetadata.toJSON(message.message?.updateMetadata)
595
+ : undefined);
558
596
  return obj;
559
597
  },
560
598
 
@@ -641,6 +679,16 @@ export const SignalRequest = {
641
679
  if (object.message?.$case === "ping" && object.message?.ping !== undefined && object.message?.ping !== null) {
642
680
  message.message = { $case: "ping", ping: object.message.ping };
643
681
  }
682
+ if (
683
+ object.message?.$case === "updateMetadata" &&
684
+ object.message?.updateMetadata !== undefined &&
685
+ object.message?.updateMetadata !== null
686
+ ) {
687
+ message.message = {
688
+ $case: "updateMetadata",
689
+ updateMetadata: UpdateParticipantMetadata.fromPartial(object.message.updateMetadata),
690
+ };
691
+ }
644
692
  return message;
645
693
  },
646
694
  };
@@ -703,6 +751,9 @@ export const SignalResponse = {
703
751
  if (message.message?.$case === "pong") {
704
752
  writer.uint32(144).int64(message.message.pong);
705
753
  }
754
+ if (message.message?.$case === "reconnect") {
755
+ ReconnectResponse.encode(message.message.reconnect, writer.uint32(154).fork()).ldelim();
756
+ }
706
757
  return writer;
707
758
  },
708
759
 
@@ -785,6 +836,9 @@ export const SignalResponse = {
785
836
  case 18:
786
837
  message.message = { $case: "pong", pong: longToNumber(reader.int64() as Long) };
787
838
  break;
839
+ case 19:
840
+ message.message = { $case: "reconnect", reconnect: ReconnectResponse.decode(reader, reader.uint32()) };
841
+ break;
788
842
  default:
789
843
  reader.skipType(tag & 7);
790
844
  break;
@@ -835,6 +889,8 @@ export const SignalResponse = {
835
889
  ? { $case: "trackUnpublished", trackUnpublished: TrackUnpublishedResponse.fromJSON(object.trackUnpublished) }
836
890
  : isSet(object.pong)
837
891
  ? { $case: "pong", pong: Number(object.pong) }
892
+ : isSet(object.reconnect)
893
+ ? { $case: "reconnect", reconnect: ReconnectResponse.fromJSON(object.reconnect) }
838
894
  : undefined,
839
895
  };
840
896
  },
@@ -882,6 +938,8 @@ export const SignalResponse = {
882
938
  ? TrackUnpublishedResponse.toJSON(message.message?.trackUnpublished)
883
939
  : undefined);
884
940
  message.message?.$case === "pong" && (obj.pong = Math.round(message.message?.pong));
941
+ message.message?.$case === "reconnect" &&
942
+ (obj.reconnect = message.message?.reconnect ? ReconnectResponse.toJSON(message.message?.reconnect) : undefined);
885
943
  return obj;
886
944
  },
887
945
 
@@ -999,6 +1057,13 @@ export const SignalResponse = {
999
1057
  if (object.message?.$case === "pong" && object.message?.pong !== undefined && object.message?.pong !== null) {
1000
1058
  message.message = { $case: "pong", pong: object.message.pong };
1001
1059
  }
1060
+ if (
1061
+ object.message?.$case === "reconnect" &&
1062
+ object.message?.reconnect !== undefined &&
1063
+ object.message?.reconnect !== null
1064
+ ) {
1065
+ message.message = { $case: "reconnect", reconnect: ReconnectResponse.fromPartial(object.message.reconnect) };
1066
+ }
1002
1067
  return message;
1003
1068
  },
1004
1069
  };
@@ -1085,6 +1150,7 @@ function createBaseAddTrackRequest(): AddTrackRequest {
1085
1150
  sid: "",
1086
1151
  stereo: false,
1087
1152
  disableRed: false,
1153
+ encryption: 0,
1088
1154
  };
1089
1155
  }
1090
1156
 
@@ -1129,6 +1195,9 @@ export const AddTrackRequest = {
1129
1195
  if (message.disableRed === true) {
1130
1196
  writer.uint32(104).bool(message.disableRed);
1131
1197
  }
1198
+ if (message.encryption !== 0) {
1199
+ writer.uint32(112).int32(message.encryption);
1200
+ }
1132
1201
  return writer;
1133
1202
  },
1134
1203
 
@@ -1178,6 +1247,9 @@ export const AddTrackRequest = {
1178
1247
  case 13:
1179
1248
  message.disableRed = reader.bool();
1180
1249
  break;
1250
+ case 14:
1251
+ message.encryption = reader.int32() as any;
1252
+ break;
1181
1253
  default:
1182
1254
  reader.skipType(tag & 7);
1183
1255
  break;
@@ -1203,6 +1275,7 @@ export const AddTrackRequest = {
1203
1275
  sid: isSet(object.sid) ? String(object.sid) : "",
1204
1276
  stereo: isSet(object.stereo) ? Boolean(object.stereo) : false,
1205
1277
  disableRed: isSet(object.disableRed) ? Boolean(object.disableRed) : false,
1278
+ encryption: isSet(object.encryption) ? encryption_TypeFromJSON(object.encryption) : 0,
1206
1279
  };
1207
1280
  },
1208
1281
 
@@ -1229,6 +1302,7 @@ export const AddTrackRequest = {
1229
1302
  message.sid !== undefined && (obj.sid = message.sid);
1230
1303
  message.stereo !== undefined && (obj.stereo = message.stereo);
1231
1304
  message.disableRed !== undefined && (obj.disableRed = message.disableRed);
1305
+ message.encryption !== undefined && (obj.encryption = encryption_TypeToJSON(message.encryption));
1232
1306
  return obj;
1233
1307
  },
1234
1308
 
@@ -1247,6 +1321,7 @@ export const AddTrackRequest = {
1247
1321
  message.sid = object.sid ?? "";
1248
1322
  message.stereo = object.stereo ?? false;
1249
1323
  message.disableRed = object.disableRed ?? false;
1324
+ message.encryption = object.encryption ?? 0;
1250
1325
  return message;
1251
1326
  },
1252
1327
  };
@@ -1550,6 +1625,74 @@ export const JoinResponse = {
1550
1625
  },
1551
1626
  };
1552
1627
 
1628
+ function createBaseReconnectResponse(): ReconnectResponse {
1629
+ return { iceServers: [], clientConfiguration: undefined };
1630
+ }
1631
+
1632
+ export const ReconnectResponse = {
1633
+ encode(message: ReconnectResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
1634
+ for (const v of message.iceServers) {
1635
+ ICEServer.encode(v!, writer.uint32(10).fork()).ldelim();
1636
+ }
1637
+ if (message.clientConfiguration !== undefined) {
1638
+ ClientConfiguration.encode(message.clientConfiguration, writer.uint32(18).fork()).ldelim();
1639
+ }
1640
+ return writer;
1641
+ },
1642
+
1643
+ decode(input: _m0.Reader | Uint8Array, length?: number): ReconnectResponse {
1644
+ const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
1645
+ let end = length === undefined ? reader.len : reader.pos + length;
1646
+ const message = createBaseReconnectResponse();
1647
+ while (reader.pos < end) {
1648
+ const tag = reader.uint32();
1649
+ switch (tag >>> 3) {
1650
+ case 1:
1651
+ message.iceServers.push(ICEServer.decode(reader, reader.uint32()));
1652
+ break;
1653
+ case 2:
1654
+ message.clientConfiguration = ClientConfiguration.decode(reader, reader.uint32());
1655
+ break;
1656
+ default:
1657
+ reader.skipType(tag & 7);
1658
+ break;
1659
+ }
1660
+ }
1661
+ return message;
1662
+ },
1663
+
1664
+ fromJSON(object: any): ReconnectResponse {
1665
+ return {
1666
+ iceServers: Array.isArray(object?.iceServers) ? object.iceServers.map((e: any) => ICEServer.fromJSON(e)) : [],
1667
+ clientConfiguration: isSet(object.clientConfiguration)
1668
+ ? ClientConfiguration.fromJSON(object.clientConfiguration)
1669
+ : undefined,
1670
+ };
1671
+ },
1672
+
1673
+ toJSON(message: ReconnectResponse): unknown {
1674
+ const obj: any = {};
1675
+ if (message.iceServers) {
1676
+ obj.iceServers = message.iceServers.map((e) => e ? ICEServer.toJSON(e) : undefined);
1677
+ } else {
1678
+ obj.iceServers = [];
1679
+ }
1680
+ message.clientConfiguration !== undefined && (obj.clientConfiguration = message.clientConfiguration
1681
+ ? ClientConfiguration.toJSON(message.clientConfiguration)
1682
+ : undefined);
1683
+ return obj;
1684
+ },
1685
+
1686
+ fromPartial<I extends Exact<DeepPartial<ReconnectResponse>, I>>(object: I): ReconnectResponse {
1687
+ const message = createBaseReconnectResponse();
1688
+ message.iceServers = object.iceServers?.map((e) => ICEServer.fromPartial(e)) || [];
1689
+ message.clientConfiguration = (object.clientConfiguration !== undefined && object.clientConfiguration !== null)
1690
+ ? ClientConfiguration.fromPartial(object.clientConfiguration)
1691
+ : undefined;
1692
+ return message;
1693
+ },
1694
+ };
1695
+
1553
1696
  function createBaseTrackPublishedResponse(): TrackPublishedResponse {
1554
1697
  return { cid: "", track: undefined };
1555
1698
  }
@@ -1845,7 +1988,7 @@ export const UpdateSubscription = {
1845
1988
  };
1846
1989
 
1847
1990
  function createBaseUpdateTrackSettings(): UpdateTrackSettings {
1848
- return { trackSids: [], disabled: false, quality: 0, width: 0, height: 0, fps: 0 };
1991
+ return { trackSids: [], disabled: false, quality: 0, width: 0, height: 0, fps: 0, priority: 0 };
1849
1992
  }
1850
1993
 
1851
1994
  export const UpdateTrackSettings = {
@@ -1868,6 +2011,9 @@ export const UpdateTrackSettings = {
1868
2011
  if (message.fps !== 0) {
1869
2012
  writer.uint32(56).uint32(message.fps);
1870
2013
  }
2014
+ if (message.priority !== 0) {
2015
+ writer.uint32(64).uint32(message.priority);
2016
+ }
1871
2017
  return writer;
1872
2018
  },
1873
2019
 
@@ -1896,6 +2042,9 @@ export const UpdateTrackSettings = {
1896
2042
  case 7:
1897
2043
  message.fps = reader.uint32();
1898
2044
  break;
2045
+ case 8:
2046
+ message.priority = reader.uint32();
2047
+ break;
1899
2048
  default:
1900
2049
  reader.skipType(tag & 7);
1901
2050
  break;
@@ -1912,6 +2061,7 @@ export const UpdateTrackSettings = {
1912
2061
  width: isSet(object.width) ? Number(object.width) : 0,
1913
2062
  height: isSet(object.height) ? Number(object.height) : 0,
1914
2063
  fps: isSet(object.fps) ? Number(object.fps) : 0,
2064
+ priority: isSet(object.priority) ? Number(object.priority) : 0,
1915
2065
  };
1916
2066
  },
1917
2067
 
@@ -1927,6 +2077,7 @@ export const UpdateTrackSettings = {
1927
2077
  message.width !== undefined && (obj.width = Math.round(message.width));
1928
2078
  message.height !== undefined && (obj.height = Math.round(message.height));
1929
2079
  message.fps !== undefined && (obj.fps = Math.round(message.fps));
2080
+ message.priority !== undefined && (obj.priority = Math.round(message.priority));
1930
2081
  return obj;
1931
2082
  },
1932
2083
 
@@ -1938,6 +2089,7 @@ export const UpdateTrackSettings = {
1938
2089
  message.width = object.width ?? 0;
1939
2090
  message.height = object.height ?? 0;
1940
2091
  message.fps = object.fps ?? 0;
2092
+ message.priority = object.priority ?? 0;
1941
2093
  return message;
1942
2094
  },
1943
2095
  };
@@ -2062,6 +2214,53 @@ export const UpdateVideoLayers = {
2062
2214
  },
2063
2215
  };
2064
2216
 
2217
+ function createBaseUpdateParticipantMetadata(): UpdateParticipantMetadata {
2218
+ return { metadata: "" };
2219
+ }
2220
+
2221
+ export const UpdateParticipantMetadata = {
2222
+ encode(message: UpdateParticipantMetadata, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
2223
+ if (message.metadata !== "") {
2224
+ writer.uint32(10).string(message.metadata);
2225
+ }
2226
+ return writer;
2227
+ },
2228
+
2229
+ decode(input: _m0.Reader | Uint8Array, length?: number): UpdateParticipantMetadata {
2230
+ const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
2231
+ let end = length === undefined ? reader.len : reader.pos + length;
2232
+ const message = createBaseUpdateParticipantMetadata();
2233
+ while (reader.pos < end) {
2234
+ const tag = reader.uint32();
2235
+ switch (tag >>> 3) {
2236
+ case 1:
2237
+ message.metadata = reader.string();
2238
+ break;
2239
+ default:
2240
+ reader.skipType(tag & 7);
2241
+ break;
2242
+ }
2243
+ }
2244
+ return message;
2245
+ },
2246
+
2247
+ fromJSON(object: any): UpdateParticipantMetadata {
2248
+ return { metadata: isSet(object.metadata) ? String(object.metadata) : "" };
2249
+ },
2250
+
2251
+ toJSON(message: UpdateParticipantMetadata): unknown {
2252
+ const obj: any = {};
2253
+ message.metadata !== undefined && (obj.metadata = message.metadata);
2254
+ return obj;
2255
+ },
2256
+
2257
+ fromPartial<I extends Exact<DeepPartial<UpdateParticipantMetadata>, I>>(object: I): UpdateParticipantMetadata {
2258
+ const message = createBaseUpdateParticipantMetadata();
2259
+ message.metadata = object.metadata ?? "";
2260
+ return message;
2261
+ },
2262
+ };
2263
+
2065
2264
  function createBaseICEServer(): ICEServer {
2066
2265
  return { urls: [], username: "", credential: "" };
2067
2266
  }
@@ -3192,7 +3391,7 @@ export const SimulateScenario = {
3192
3391
  declare var self: any | undefined;
3193
3392
  declare var window: any | undefined;
3194
3393
  declare var global: any | undefined;
3195
- var globalThis: any = (() => {
3394
+ var tsProtoGlobalThis: any = (() => {
3196
3395
  if (typeof globalThis !== "undefined") {
3197
3396
  return globalThis;
3198
3397
  }
@@ -3222,7 +3421,7 @@ export type Exact<P, I extends P> = P extends Builtin ? P
3222
3421
 
3223
3422
  function longToNumber(long: Long): number {
3224
3423
  if (long.gt(Number.MAX_SAFE_INTEGER)) {
3225
- throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
3424
+ throw new tsProtoGlobalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
3226
3425
  }
3227
3426
  return long.toNumber();
3228
3427
  }
@@ -30,6 +30,8 @@ export default class PCTransport extends EventEmitter {
30
30
 
31
31
  remoteStereoMids: string[] = [];
32
32
 
33
+ remoteNackMids: string[] = [];
34
+
33
35
  onOffer?: (offer: RTCSessionDescriptionInit) => void;
34
36
 
35
37
  constructor(config?: RTCConfiguration) {
@@ -50,7 +52,9 @@ export default class PCTransport extends EventEmitter {
50
52
 
51
53
  async setRemoteDescription(sd: RTCSessionDescriptionInit): Promise<void> {
52
54
  if (sd.type === 'offer') {
53
- this.remoteStereoMids = extractStereoTracksFromOffer(sd);
55
+ let { stereoMids, nackMids } = extractStereoAndNackAudioFromOffer(sd);
56
+ this.remoteStereoMids = stereoMids;
57
+ this.remoteNackMids = nackMids;
54
58
  }
55
59
  await this.pc.setRemoteDescription(sd);
56
60
 
@@ -116,7 +120,7 @@ export default class PCTransport extends EventEmitter {
116
120
  const sdpParsed = parse(offer.sdp ?? '');
117
121
  sdpParsed.media.forEach((media) => {
118
122
  if (media.type === 'audio') {
119
- ensureAudioNackAndStereo(media, []);
123
+ ensureAudioNackAndStereo(media, [], []);
120
124
  } else if (media.type === 'video') {
121
125
  // mung sdp for codec bitrate setting that can't apply by sendEncoding
122
126
  this.trackBitrates.some((trackbr): boolean => {
@@ -169,7 +173,7 @@ export default class PCTransport extends EventEmitter {
169
173
  const sdpParsed = parse(answer.sdp ?? '');
170
174
  sdpParsed.media.forEach((media) => {
171
175
  if (media.type === 'audio') {
172
- ensureAudioNackAndStereo(media, this.remoteStereoMids);
176
+ ensureAudioNackAndStereo(media, this.remoteStereoMids, this.remoteNackMids);
173
177
  }
174
178
  });
175
179
  await this.setMungedLocalDescription(answer, write(sdpParsed));
@@ -226,6 +230,7 @@ function ensureAudioNackAndStereo(
226
230
  payloads?: string | undefined;
227
231
  } & MediaDescription,
228
232
  stereoMids: string[],
233
+ nackMids: string[],
229
234
  ) {
230
235
  // found opus codec to add nack fb
231
236
  let opusPayload = 0;
@@ -243,7 +248,10 @@ function ensureAudioNackAndStereo(
243
248
  media.rtcpFb = [];
244
249
  }
245
250
 
246
- if (!media.rtcpFb.some((fb) => fb.payload === opusPayload && fb.type === 'nack')) {
251
+ if (
252
+ nackMids.includes(media.mid!) &&
253
+ !media.rtcpFb.some((fb) => fb.payload === opusPayload && fb.type === 'nack')
254
+ ) {
247
255
  media.rtcpFb.push({
248
256
  payload: opusPayload,
249
257
  type: 'nack',
@@ -264,8 +272,12 @@ function ensureAudioNackAndStereo(
264
272
  }
265
273
  }
266
274
 
267
- function extractStereoTracksFromOffer(offer: RTCSessionDescriptionInit): string[] {
275
+ function extractStereoAndNackAudioFromOffer(offer: RTCSessionDescriptionInit): {
276
+ stereoMids: string[];
277
+ nackMids: string[];
278
+ } {
268
279
  const stereoMids: string[] = [];
280
+ const nackMids: string[] = [];
269
281
  const sdpParsed = parse(offer.sdp ?? '');
270
282
  let opusPayload = 0;
271
283
  sdpParsed.media.forEach((media) => {
@@ -278,6 +290,10 @@ function extractStereoTracksFromOffer(offer: RTCSessionDescriptionInit): string[
278
290
  return false;
279
291
  });
280
292
 
293
+ if (media.rtcpFb?.some((fb) => fb.payload === opusPayload && fb.type === 'nack')) {
294
+ nackMids.push(media.mid!);
295
+ }
296
+
281
297
  media.fmtp.some((fmtp): boolean => {
282
298
  if (fmtp.payload === opusPayload) {
283
299
  if (fmtp.config.includes('sprop-stereo=1')) {
@@ -289,5 +305,5 @@ function extractStereoTracksFromOffer(offer: RTCSessionDescriptionInit): string[
289
305
  });
290
306
  }
291
307
  });
292
- return stereoMids;
308
+ return { stereoMids, nackMids };
293
309
  }
@@ -17,6 +17,7 @@ import {
17
17
  AddTrackRequest,
18
18
  JoinResponse,
19
19
  LeaveRequest,
20
+ ReconnectResponse,
20
21
  SignalTarget,
21
22
  TrackPublishedResponse,
22
23
  } from '../proto/livekit_rtc';
@@ -31,6 +32,7 @@ import {
31
32
  import { EngineEvent } from './events';
32
33
  import PCTransport, { PCEvents } from './PCTransport';
33
34
  import type { ReconnectContext, ReconnectPolicy } from './ReconnectPolicy';
35
+ import CriticalTimers from './timers';
34
36
  import type LocalTrack from './track/LocalTrack';
35
37
  import type LocalVideoTrack from './track/LocalVideoTrack';
36
38
  import type { SimulcastTrackInfo } from './track/LocalVideoTrack';
@@ -279,35 +281,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
279
281
 
280
282
  this.participantSid = joinResponse.participant?.sid;
281
283
 
282
- const rtcConfig = { ...this.rtcConfig };
283
-
284
- // update ICE servers before creating PeerConnection
285
- if (joinResponse.iceServers && !rtcConfig.iceServers) {
286
- const rtcIceServers: RTCIceServer[] = [];
287
- joinResponse.iceServers.forEach((iceServer) => {
288
- const rtcIceServer: RTCIceServer = {
289
- urls: iceServer.urls,
290
- };
291
- if (iceServer.username) rtcIceServer.username = iceServer.username;
292
- if (iceServer.credential) {
293
- rtcIceServer.credential = iceServer.credential;
294
- }
295
- rtcIceServers.push(rtcIceServer);
296
- });
297
- rtcConfig.iceServers = rtcIceServers;
298
- }
299
-
300
- if (
301
- joinResponse.clientConfiguration &&
302
- joinResponse.clientConfiguration.forceRelay === ClientConfigSetting.ENABLED
303
- ) {
304
- rtcConfig.iceTransportPolicy = 'relay';
305
- }
306
-
307
- // @ts-ignore
308
- rtcConfig.sdpSemantics = 'unified-plan';
309
- // @ts-ignore
310
- rtcConfig.continualGatheringPolicy = 'gather_continually';
284
+ const rtcConfig = this.makeRTCConfiguration(joinResponse);
311
285
 
312
286
  this.publisher = new PCTransport(rtcConfig);
313
287
  this.subscriber = new PCTransport(rtcConfig);
@@ -448,6 +422,40 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
448
422
  };
449
423
  }
450
424
 
425
+ private makeRTCConfiguration(serverResponse: JoinResponse | ReconnectResponse): RTCConfiguration {
426
+ const rtcConfig = { ...this.rtcConfig };
427
+
428
+ // update ICE servers before creating PeerConnection
429
+ if (serverResponse.iceServers && !rtcConfig.iceServers) {
430
+ const rtcIceServers: RTCIceServer[] = [];
431
+ serverResponse.iceServers.forEach((iceServer) => {
432
+ const rtcIceServer: RTCIceServer = {
433
+ urls: iceServer.urls,
434
+ };
435
+ if (iceServer.username) rtcIceServer.username = iceServer.username;
436
+ if (iceServer.credential) {
437
+ rtcIceServer.credential = iceServer.credential;
438
+ }
439
+ rtcIceServers.push(rtcIceServer);
440
+ });
441
+ rtcConfig.iceServers = rtcIceServers;
442
+ }
443
+
444
+ if (
445
+ serverResponse.clientConfiguration &&
446
+ serverResponse.clientConfiguration.forceRelay === ClientConfigSetting.ENABLED
447
+ ) {
448
+ rtcConfig.iceTransportPolicy = 'relay';
449
+ }
450
+
451
+ // @ts-ignore
452
+ rtcConfig.sdpSemantics = 'unified-plan';
453
+ // @ts-ignore
454
+ rtcConfig.continualGatheringPolicy = 'gather_continually';
455
+
456
+ return rtcConfig;
457
+ }
458
+
451
459
  private createDataChannels() {
452
460
  if (!this.publisher) {
453
461
  return;
@@ -673,14 +681,14 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
673
681
  return;
674
682
  }
675
683
 
676
- log.debug(`${connection} disconnected`);
684
+ log.warn(`${connection} disconnected`);
677
685
  if (this.reconnectAttempts === 0) {
678
686
  // only reset start time on the first try
679
687
  this.reconnectStart = Date.now();
680
688
  }
681
689
 
682
690
  const disconnect = (duration: number) => {
683
- log.info(
691
+ log.warn(
684
692
  `could not recover connection after ${this.reconnectAttempts} attempts, ${duration}ms. giving up`,
685
693
  );
686
694
  this.emit(EngineEvent.Disconnected);
@@ -703,10 +711,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
703
711
 
704
712
  log.debug(`reconnecting in ${delay}ms`);
705
713
 
706
- if (this.reconnectTimeout) {
707
- clearTimeout(this.reconnectTimeout);
708
- }
709
- this.reconnectTimeout = setTimeout(() => this.attemptReconnect(signalEvents), delay);
714
+ this.clearReconnectTimeout();
715
+ this.reconnectTimeout = CriticalTimers.setTimeout(
716
+ () => this.attemptReconnect(signalEvents),
717
+ delay,
718
+ );
710
719
  };
711
720
 
712
721
  private async attemptReconnect(signalEvents: boolean = false) {
@@ -733,11 +742,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
733
742
  } else {
734
743
  await this.resumeConnection(signalEvents);
735
744
  }
736
- this.reconnectAttempts = 0;
745
+ this.clearPendingReconnect();
737
746
  this.fullReconnectOnNext = false;
738
- if (this.reconnectTimeout) {
739
- clearTimeout(this.reconnectTimeout);
740
- }
741
747
  } catch (e) {
742
748
  this.reconnectAttempts += 1;
743
749
  let reconnectRequired = false;
@@ -841,7 +847,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
841
847
  }
842
848
 
843
849
  try {
844
- await this.client.reconnect(this.url, this.token, this.participantSid);
850
+ const res = await this.client.reconnect(this.url, this.token, this.participantSid);
851
+ if (res) {
852
+ const rtcConfig = this.makeRTCConfiguration(res);
853
+ this.publisher.pc.setConfiguration(rtcConfig);
854
+ this.subscriber.pc.setConfiguration(rtcConfig);
855
+ }
845
856
  } catch (e) {
846
857
  let message = '';
847
858
  if (e instanceof Error) {
@@ -1034,19 +1045,21 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1034
1045
  }
1035
1046
  }
1036
1047
 
1037
- private clearPendingReconnect() {
1048
+ private clearReconnectTimeout() {
1038
1049
  if (this.reconnectTimeout) {
1039
- clearTimeout(this.reconnectTimeout);
1050
+ CriticalTimers.clearTimeout(this.reconnectTimeout);
1040
1051
  }
1052
+ }
1053
+
1054
+ private clearPendingReconnect() {
1055
+ this.clearReconnectTimeout();
1041
1056
  this.reconnectAttempts = 0;
1042
1057
  }
1043
1058
 
1044
1059
  private handleBrowserOnLine = () => {
1045
1060
  // in case the engine is currently reconnecting, attempt a reconnect immediately after the browser state has changed to 'onLine'
1046
1061
  if (this.client.isReconnecting) {
1047
- if (this.reconnectTimeout) {
1048
- clearTimeout(this.reconnectTimeout);
1049
- }
1062
+ this.clearReconnectTimeout();
1050
1063
  this.attemptReconnect(true);
1051
1064
  }
1052
1065
  };