livekit-client 1.6.4 → 1.6.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "1.6.4",
3
+ "version": "1.6.5",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "./dist/livekit-client.umd.js",
6
6
  "unpkg": "./dist/livekit-client.umd.js",
@@ -5,6 +5,7 @@ import {
5
5
  ClientInfo,
6
6
  DisconnectReason,
7
7
  ParticipantInfo,
8
+ ReconnectReason,
8
9
  Room,
9
10
  SpeakerInfo,
10
11
  VideoLayer,
@@ -40,6 +41,9 @@ interface ConnectOpts {
40
41
  /** internal */
41
42
  reconnect?: boolean;
42
43
 
44
+ /** internal */
45
+ reconnectReason?: number;
46
+
43
47
  /** internal */
44
48
  sid?: string;
45
49
 
@@ -89,6 +93,9 @@ export class SignalClient {
89
93
 
90
94
  useJSON: boolean;
91
95
 
96
+ /** signal rtt in milliseconds */
97
+ rtt: number = 0;
98
+
92
99
  /** simulate signaling latency by delaying messages */
93
100
  signalLatency?: number;
94
101
 
@@ -166,7 +173,12 @@ export class SignalClient {
166
173
  return res as JoinResponse;
167
174
  }
168
175
 
169
- async reconnect(url: string, token: string, sid?: string): Promise<ReconnectResponse | void> {
176
+ async reconnect(
177
+ url: string,
178
+ token: string,
179
+ sid?: string,
180
+ reason?: ReconnectReason,
181
+ ): Promise<ReconnectResponse | void> {
170
182
  if (!this.options) {
171
183
  log.warn('attempted to reconnect without signal options being set, ignoring');
172
184
  return;
@@ -175,7 +187,12 @@ export class SignalClient {
175
187
  // clear ping interval and restart it once reconnected
176
188
  this.clearPingInterval();
177
189
 
178
- const res = await this.connect(url, token, { ...this.options, reconnect: true, sid });
190
+ const res = await this.connect(url, token, {
191
+ ...this.options,
192
+ reconnect: true,
193
+ sid,
194
+ reconnectReason: reason,
195
+ });
179
196
  return res;
180
197
  }
181
198
 
@@ -440,10 +457,18 @@ export class SignalClient {
440
457
  }
441
458
 
442
459
  sendPing() {
460
+ /** send both of ping and pingReq for compatibility to old and new server */
443
461
  this.sendRequest({
444
462
  $case: 'ping',
445
463
  ping: Date.now(),
446
464
  });
465
+ this.sendRequest({
466
+ $case: 'pingReq',
467
+ pingReq: {
468
+ timestamp: Date.now(),
469
+ rtt: this.rtt,
470
+ },
471
+ });
447
472
  }
448
473
 
449
474
  async sendLeave() {
@@ -563,6 +588,9 @@ export class SignalClient {
563
588
  }
564
589
  } else if (msg.$case === 'pong') {
565
590
  this.resetPingTimeout();
591
+ } else if (msg.$case === 'pongResp') {
592
+ this.rtt = Date.now() - msg.pongResp.lastPingTimestamp;
593
+ this.resetPingTimeout();
566
594
  } else {
567
595
  log.debug('unsupported message', msg);
568
596
  }
@@ -582,6 +610,10 @@ export class SignalClient {
582
610
  log.error('websocket error', ev);
583
611
  }
584
612
 
613
+ /**
614
+ * Resets the ping timeout and starts a new timeout.
615
+ * Call this after receiving a pong message
616
+ */
585
617
  private resetPingTimeout() {
586
618
  this.clearPingTimeout();
587
619
  if (!this.pingTimeoutDuration) {
@@ -600,6 +632,9 @@ export class SignalClient {
600
632
  }, this.pingTimeoutDuration * 1000);
601
633
  }
602
634
 
635
+ /**
636
+ * Clears ping timeout (does not start a new timeout)
637
+ */
603
638
  private clearPingTimeout() {
604
639
  if (this.pingTimeout) {
605
640
  CriticalTimers.clearTimeout(this.pingTimeout);
@@ -698,6 +733,10 @@ function createConnectionParams(token: string, info: ClientInfo, opts: ConnectOp
698
733
  params.set('adaptive_stream', '1');
699
734
  }
700
735
 
736
+ if (opts.reconnectReason) {
737
+ params.set('reconnect_reason', opts.reconnectReason.toString());
738
+ }
739
+
701
740
  // @ts-ignore
702
741
  if (navigator.connection?.type) {
703
742
  // @ts-ignore
@@ -287,6 +287,57 @@ export function disconnectReasonToJSON(object: DisconnectReason): string {
287
287
  }
288
288
  }
289
289
 
290
+ export enum ReconnectReason {
291
+ REASON_UNKOWN = 0,
292
+ REASON_SIGNAL_DISCONNECTED = 1,
293
+ REASON_PUBLISHER_FAILED = 2,
294
+ REASON_SUBSCRIBER_FAILED = 3,
295
+ REASON_SWITCH_CANDIDATE = 4,
296
+ UNRECOGNIZED = -1,
297
+ }
298
+
299
+ export function reconnectReasonFromJSON(object: any): ReconnectReason {
300
+ switch (object) {
301
+ case 0:
302
+ case "REASON_UNKOWN":
303
+ return ReconnectReason.REASON_UNKOWN;
304
+ case 1:
305
+ case "REASON_SIGNAL_DISCONNECTED":
306
+ return ReconnectReason.REASON_SIGNAL_DISCONNECTED;
307
+ case 2:
308
+ case "REASON_PUBLISHER_FAILED":
309
+ return ReconnectReason.REASON_PUBLISHER_FAILED;
310
+ case 3:
311
+ case "REASON_SUBSCRIBER_FAILED":
312
+ return ReconnectReason.REASON_SUBSCRIBER_FAILED;
313
+ case 4:
314
+ case "REASON_SWITCH_CANDIDATE":
315
+ return ReconnectReason.REASON_SWITCH_CANDIDATE;
316
+ case -1:
317
+ case "UNRECOGNIZED":
318
+ default:
319
+ return ReconnectReason.UNRECOGNIZED;
320
+ }
321
+ }
322
+
323
+ export function reconnectReasonToJSON(object: ReconnectReason): string {
324
+ switch (object) {
325
+ case ReconnectReason.REASON_UNKOWN:
326
+ return "REASON_UNKOWN";
327
+ case ReconnectReason.REASON_SIGNAL_DISCONNECTED:
328
+ return "REASON_SIGNAL_DISCONNECTED";
329
+ case ReconnectReason.REASON_PUBLISHER_FAILED:
330
+ return "REASON_PUBLISHER_FAILED";
331
+ case ReconnectReason.REASON_SUBSCRIBER_FAILED:
332
+ return "REASON_SUBSCRIBER_FAILED";
333
+ case ReconnectReason.REASON_SWITCH_CANDIDATE:
334
+ return "REASON_SWITCH_CANDIDATE";
335
+ case ReconnectReason.UNRECOGNIZED:
336
+ default:
337
+ return "UNRECOGNIZED";
338
+ }
339
+ }
340
+
290
341
  export interface Room {
291
342
  sid: string;
292
343
  name: string;
@@ -152,7 +152,8 @@ export interface SignalRequest {
152
152
  | { $case: "syncState"; syncState: SyncState }
153
153
  | { $case: "simulate"; simulate: SimulateScenario }
154
154
  | { $case: "ping"; ping: number }
155
- | { $case: "updateMetadata"; updateMetadata: UpdateParticipantMetadata };
155
+ | { $case: "updateMetadata"; updateMetadata: UpdateParticipantMetadata }
156
+ | { $case: "pingReq"; pingReq: Ping };
156
157
  }
157
158
 
158
159
  export interface SignalResponse {
@@ -174,7 +175,8 @@ export interface SignalResponse {
174
175
  | { $case: "refreshToken"; refreshToken: string }
175
176
  | { $case: "trackUnpublished"; trackUnpublished: TrackUnpublishedResponse }
176
177
  | { $case: "pong"; pong: number }
177
- | { $case: "reconnect"; reconnect: ReconnectResponse };
178
+ | { $case: "reconnect"; reconnect: ReconnectResponse }
179
+ | { $case: "pongResp"; pongResp: Pong };
178
180
  }
179
181
 
180
182
  export interface SimulcastCodec {
@@ -241,6 +243,9 @@ export interface JoinResponse {
241
243
  export interface ReconnectResponse {
242
244
  iceServers: ICEServer[];
243
245
  clientConfiguration?: ClientConfiguration;
246
+ room?: Room;
247
+ participant?: ParticipantInfo;
248
+ otherParticipants: ParticipantInfo[];
244
249
  }
245
250
 
246
251
  export interface TrackPublishedResponse {
@@ -404,6 +409,18 @@ export interface SimulateScenario {
404
409
  | { $case: "switchCandidateProtocol"; switchCandidateProtocol: CandidateProtocol };
405
410
  }
406
411
 
412
+ export interface Ping {
413
+ timestamp: number;
414
+ /** rtt in milliseconds calculated by client */
415
+ rtt: number;
416
+ }
417
+
418
+ export interface Pong {
419
+ /** timestamp field of last received ping request */
420
+ lastPingTimestamp: number;
421
+ timestamp: number;
422
+ }
423
+
407
424
  function createBaseSignalRequest(): SignalRequest {
408
425
  return { message: undefined };
409
426
  }
@@ -452,6 +469,9 @@ export const SignalRequest = {
452
469
  if (message.message?.$case === "updateMetadata") {
453
470
  UpdateParticipantMetadata.encode(message.message.updateMetadata, writer.uint32(122).fork()).ldelim();
454
471
  }
472
+ if (message.message?.$case === "pingReq") {
473
+ Ping.encode(message.message.pingReq, writer.uint32(130).fork()).ldelim();
474
+ }
455
475
  return writer;
456
476
  },
457
477
 
@@ -513,6 +533,9 @@ export const SignalRequest = {
513
533
  updateMetadata: UpdateParticipantMetadata.decode(reader, reader.uint32()),
514
534
  };
515
535
  break;
536
+ case 16:
537
+ message.message = { $case: "pingReq", pingReq: Ping.decode(reader, reader.uint32()) };
538
+ break;
516
539
  default:
517
540
  reader.skipType(tag & 7);
518
541
  break;
@@ -554,6 +577,8 @@ export const SignalRequest = {
554
577
  ? { $case: "ping", ping: Number(object.ping) }
555
578
  : isSet(object.updateMetadata)
556
579
  ? { $case: "updateMetadata", updateMetadata: UpdateParticipantMetadata.fromJSON(object.updateMetadata) }
580
+ : isSet(object.pingReq)
581
+ ? { $case: "pingReq", pingReq: Ping.fromJSON(object.pingReq) }
557
582
  : undefined,
558
583
  };
559
584
  },
@@ -593,6 +618,8 @@ export const SignalRequest = {
593
618
  message.message?.$case === "updateMetadata" && (obj.updateMetadata = message.message?.updateMetadata
594
619
  ? UpdateParticipantMetadata.toJSON(message.message?.updateMetadata)
595
620
  : undefined);
621
+ message.message?.$case === "pingReq" &&
622
+ (obj.pingReq = message.message?.pingReq ? Ping.toJSON(message.message?.pingReq) : undefined);
596
623
  return obj;
597
624
  },
598
625
 
@@ -689,6 +716,11 @@ export const SignalRequest = {
689
716
  updateMetadata: UpdateParticipantMetadata.fromPartial(object.message.updateMetadata),
690
717
  };
691
718
  }
719
+ if (
720
+ object.message?.$case === "pingReq" && object.message?.pingReq !== undefined && object.message?.pingReq !== null
721
+ ) {
722
+ message.message = { $case: "pingReq", pingReq: Ping.fromPartial(object.message.pingReq) };
723
+ }
692
724
  return message;
693
725
  },
694
726
  };
@@ -754,6 +786,9 @@ export const SignalResponse = {
754
786
  if (message.message?.$case === "reconnect") {
755
787
  ReconnectResponse.encode(message.message.reconnect, writer.uint32(154).fork()).ldelim();
756
788
  }
789
+ if (message.message?.$case === "pongResp") {
790
+ Pong.encode(message.message.pongResp, writer.uint32(162).fork()).ldelim();
791
+ }
757
792
  return writer;
758
793
  },
759
794
 
@@ -839,6 +874,9 @@ export const SignalResponse = {
839
874
  case 19:
840
875
  message.message = { $case: "reconnect", reconnect: ReconnectResponse.decode(reader, reader.uint32()) };
841
876
  break;
877
+ case 20:
878
+ message.message = { $case: "pongResp", pongResp: Pong.decode(reader, reader.uint32()) };
879
+ break;
842
880
  default:
843
881
  reader.skipType(tag & 7);
844
882
  break;
@@ -891,6 +929,8 @@ export const SignalResponse = {
891
929
  ? { $case: "pong", pong: Number(object.pong) }
892
930
  : isSet(object.reconnect)
893
931
  ? { $case: "reconnect", reconnect: ReconnectResponse.fromJSON(object.reconnect) }
932
+ : isSet(object.pongResp)
933
+ ? { $case: "pongResp", pongResp: Pong.fromJSON(object.pongResp) }
894
934
  : undefined,
895
935
  };
896
936
  },
@@ -940,6 +980,8 @@ export const SignalResponse = {
940
980
  message.message?.$case === "pong" && (obj.pong = Math.round(message.message?.pong));
941
981
  message.message?.$case === "reconnect" &&
942
982
  (obj.reconnect = message.message?.reconnect ? ReconnectResponse.toJSON(message.message?.reconnect) : undefined);
983
+ message.message?.$case === "pongResp" &&
984
+ (obj.pongResp = message.message?.pongResp ? Pong.toJSON(message.message?.pongResp) : undefined);
943
985
  return obj;
944
986
  },
945
987
 
@@ -1064,6 +1106,13 @@ export const SignalResponse = {
1064
1106
  ) {
1065
1107
  message.message = { $case: "reconnect", reconnect: ReconnectResponse.fromPartial(object.message.reconnect) };
1066
1108
  }
1109
+ if (
1110
+ object.message?.$case === "pongResp" &&
1111
+ object.message?.pongResp !== undefined &&
1112
+ object.message?.pongResp !== null
1113
+ ) {
1114
+ message.message = { $case: "pongResp", pongResp: Pong.fromPartial(object.message.pongResp) };
1115
+ }
1067
1116
  return message;
1068
1117
  },
1069
1118
  };
@@ -1626,7 +1675,13 @@ export const JoinResponse = {
1626
1675
  };
1627
1676
 
1628
1677
  function createBaseReconnectResponse(): ReconnectResponse {
1629
- return { iceServers: [], clientConfiguration: undefined };
1678
+ return {
1679
+ iceServers: [],
1680
+ clientConfiguration: undefined,
1681
+ room: undefined,
1682
+ participant: undefined,
1683
+ otherParticipants: [],
1684
+ };
1630
1685
  }
1631
1686
 
1632
1687
  export const ReconnectResponse = {
@@ -1637,6 +1692,15 @@ export const ReconnectResponse = {
1637
1692
  if (message.clientConfiguration !== undefined) {
1638
1693
  ClientConfiguration.encode(message.clientConfiguration, writer.uint32(18).fork()).ldelim();
1639
1694
  }
1695
+ if (message.room !== undefined) {
1696
+ Room.encode(message.room, writer.uint32(26).fork()).ldelim();
1697
+ }
1698
+ if (message.participant !== undefined) {
1699
+ ParticipantInfo.encode(message.participant, writer.uint32(34).fork()).ldelim();
1700
+ }
1701
+ for (const v of message.otherParticipants) {
1702
+ ParticipantInfo.encode(v!, writer.uint32(42).fork()).ldelim();
1703
+ }
1640
1704
  return writer;
1641
1705
  },
1642
1706
 
@@ -1653,6 +1717,15 @@ export const ReconnectResponse = {
1653
1717
  case 2:
1654
1718
  message.clientConfiguration = ClientConfiguration.decode(reader, reader.uint32());
1655
1719
  break;
1720
+ case 3:
1721
+ message.room = Room.decode(reader, reader.uint32());
1722
+ break;
1723
+ case 4:
1724
+ message.participant = ParticipantInfo.decode(reader, reader.uint32());
1725
+ break;
1726
+ case 5:
1727
+ message.otherParticipants.push(ParticipantInfo.decode(reader, reader.uint32()));
1728
+ break;
1656
1729
  default:
1657
1730
  reader.skipType(tag & 7);
1658
1731
  break;
@@ -1667,6 +1740,11 @@ export const ReconnectResponse = {
1667
1740
  clientConfiguration: isSet(object.clientConfiguration)
1668
1741
  ? ClientConfiguration.fromJSON(object.clientConfiguration)
1669
1742
  : undefined,
1743
+ room: isSet(object.room) ? Room.fromJSON(object.room) : undefined,
1744
+ participant: isSet(object.participant) ? ParticipantInfo.fromJSON(object.participant) : undefined,
1745
+ otherParticipants: Array.isArray(object?.otherParticipants)
1746
+ ? object.otherParticipants.map((e: any) => ParticipantInfo.fromJSON(e))
1747
+ : [],
1670
1748
  };
1671
1749
  },
1672
1750
 
@@ -1680,6 +1758,14 @@ export const ReconnectResponse = {
1680
1758
  message.clientConfiguration !== undefined && (obj.clientConfiguration = message.clientConfiguration
1681
1759
  ? ClientConfiguration.toJSON(message.clientConfiguration)
1682
1760
  : undefined);
1761
+ message.room !== undefined && (obj.room = message.room ? Room.toJSON(message.room) : undefined);
1762
+ message.participant !== undefined &&
1763
+ (obj.participant = message.participant ? ParticipantInfo.toJSON(message.participant) : undefined);
1764
+ if (message.otherParticipants) {
1765
+ obj.otherParticipants = message.otherParticipants.map((e) => e ? ParticipantInfo.toJSON(e) : undefined);
1766
+ } else {
1767
+ obj.otherParticipants = [];
1768
+ }
1683
1769
  return obj;
1684
1770
  },
1685
1771
 
@@ -1689,6 +1775,11 @@ export const ReconnectResponse = {
1689
1775
  message.clientConfiguration = (object.clientConfiguration !== undefined && object.clientConfiguration !== null)
1690
1776
  ? ClientConfiguration.fromPartial(object.clientConfiguration)
1691
1777
  : undefined;
1778
+ message.room = (object.room !== undefined && object.room !== null) ? Room.fromPartial(object.room) : undefined;
1779
+ message.participant = (object.participant !== undefined && object.participant !== null)
1780
+ ? ParticipantInfo.fromPartial(object.participant)
1781
+ : undefined;
1782
+ message.otherParticipants = object.otherParticipants?.map((e) => ParticipantInfo.fromPartial(e)) || [];
1692
1783
  return message;
1693
1784
  },
1694
1785
  };
@@ -3388,6 +3479,122 @@ export const SimulateScenario = {
3388
3479
  },
3389
3480
  };
3390
3481
 
3482
+ function createBasePing(): Ping {
3483
+ return { timestamp: 0, rtt: 0 };
3484
+ }
3485
+
3486
+ export const Ping = {
3487
+ encode(message: Ping, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
3488
+ if (message.timestamp !== 0) {
3489
+ writer.uint32(8).int64(message.timestamp);
3490
+ }
3491
+ if (message.rtt !== 0) {
3492
+ writer.uint32(16).int64(message.rtt);
3493
+ }
3494
+ return writer;
3495
+ },
3496
+
3497
+ decode(input: _m0.Reader | Uint8Array, length?: number): Ping {
3498
+ const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
3499
+ let end = length === undefined ? reader.len : reader.pos + length;
3500
+ const message = createBasePing();
3501
+ while (reader.pos < end) {
3502
+ const tag = reader.uint32();
3503
+ switch (tag >>> 3) {
3504
+ case 1:
3505
+ message.timestamp = longToNumber(reader.int64() as Long);
3506
+ break;
3507
+ case 2:
3508
+ message.rtt = longToNumber(reader.int64() as Long);
3509
+ break;
3510
+ default:
3511
+ reader.skipType(tag & 7);
3512
+ break;
3513
+ }
3514
+ }
3515
+ return message;
3516
+ },
3517
+
3518
+ fromJSON(object: any): Ping {
3519
+ return {
3520
+ timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0,
3521
+ rtt: isSet(object.rtt) ? Number(object.rtt) : 0,
3522
+ };
3523
+ },
3524
+
3525
+ toJSON(message: Ping): unknown {
3526
+ const obj: any = {};
3527
+ message.timestamp !== undefined && (obj.timestamp = Math.round(message.timestamp));
3528
+ message.rtt !== undefined && (obj.rtt = Math.round(message.rtt));
3529
+ return obj;
3530
+ },
3531
+
3532
+ fromPartial<I extends Exact<DeepPartial<Ping>, I>>(object: I): Ping {
3533
+ const message = createBasePing();
3534
+ message.timestamp = object.timestamp ?? 0;
3535
+ message.rtt = object.rtt ?? 0;
3536
+ return message;
3537
+ },
3538
+ };
3539
+
3540
+ function createBasePong(): Pong {
3541
+ return { lastPingTimestamp: 0, timestamp: 0 };
3542
+ }
3543
+
3544
+ export const Pong = {
3545
+ encode(message: Pong, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
3546
+ if (message.lastPingTimestamp !== 0) {
3547
+ writer.uint32(8).int64(message.lastPingTimestamp);
3548
+ }
3549
+ if (message.timestamp !== 0) {
3550
+ writer.uint32(16).int64(message.timestamp);
3551
+ }
3552
+ return writer;
3553
+ },
3554
+
3555
+ decode(input: _m0.Reader | Uint8Array, length?: number): Pong {
3556
+ const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
3557
+ let end = length === undefined ? reader.len : reader.pos + length;
3558
+ const message = createBasePong();
3559
+ while (reader.pos < end) {
3560
+ const tag = reader.uint32();
3561
+ switch (tag >>> 3) {
3562
+ case 1:
3563
+ message.lastPingTimestamp = longToNumber(reader.int64() as Long);
3564
+ break;
3565
+ case 2:
3566
+ message.timestamp = longToNumber(reader.int64() as Long);
3567
+ break;
3568
+ default:
3569
+ reader.skipType(tag & 7);
3570
+ break;
3571
+ }
3572
+ }
3573
+ return message;
3574
+ },
3575
+
3576
+ fromJSON(object: any): Pong {
3577
+ return {
3578
+ lastPingTimestamp: isSet(object.lastPingTimestamp) ? Number(object.lastPingTimestamp) : 0,
3579
+ timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0,
3580
+ };
3581
+ },
3582
+
3583
+ toJSON(message: Pong): unknown {
3584
+ const obj: any = {};
3585
+ message.lastPingTimestamp !== undefined && (obj.lastPingTimestamp = Math.round(message.lastPingTimestamp));
3586
+ message.timestamp !== undefined && (obj.timestamp = Math.round(message.timestamp));
3587
+ return obj;
3588
+ },
3589
+
3590
+ fromPartial<I extends Exact<DeepPartial<Pong>, I>>(object: I): Pong {
3591
+ const message = createBasePong();
3592
+ message.lastPingTimestamp = object.lastPingTimestamp ?? 0;
3593
+ message.timestamp = object.timestamp ?? 0;
3594
+ return message;
3595
+ },
3596
+ };
3597
+
3391
3598
  declare var self: any | undefined;
3392
3599
  declare var window: any | undefined;
3393
3600
  declare var global: any | undefined;
@@ -9,6 +9,7 @@ import {
9
9
  DataPacket,
10
10
  DataPacket_Kind,
11
11
  DisconnectReason,
12
+ ReconnectReason,
12
13
  SpeakerInfo,
13
14
  TrackInfo,
14
15
  UserPacket,
@@ -305,7 +306,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
305
306
 
306
307
  let primaryPC = this.publisher.pc;
307
308
  let secondaryPC = this.subscriber.pc;
308
- if (joinResponse.subscriberPrimary) {
309
+ let subscriberPrimary = joinResponse.subscriberPrimary;
310
+ if (subscriberPrimary) {
309
311
  primaryPC = this.subscriber.pc;
310
312
  secondaryPC = this.publisher.pc;
311
313
  // in subscriber primary mode, server side opens sub data channels.
@@ -330,7 +332,13 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
330
332
  if (this.pcState === PCState.Connected) {
331
333
  this.pcState = PCState.Disconnected;
332
334
 
333
- this.handleDisconnect('primary peerconnection');
335
+ this.handleDisconnect(
336
+ 'primary peerconnection',
337
+ false,
338
+ subscriberPrimary
339
+ ? ReconnectReason.REASON_SUBSCRIBER_FAILED
340
+ : ReconnectReason.REASON_PUBLISHER_FAILED,
341
+ );
334
342
  }
335
343
  }
336
344
  };
@@ -338,7 +346,13 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
338
346
  log.debug(`secondary PC state changed ${secondaryPC.connectionState}`);
339
347
  // also reconnect if secondary peerconnection fails
340
348
  if (secondaryPC.connectionState === 'failed') {
341
- this.handleDisconnect('secondary peerconnection');
349
+ this.handleDisconnect(
350
+ 'secondary peerconnection',
351
+ false,
352
+ subscriberPrimary
353
+ ? ReconnectReason.REASON_PUBLISHER_FAILED
354
+ : ReconnectReason.REASON_SUBSCRIBER_FAILED,
355
+ );
342
356
  }
343
357
  };
344
358
 
@@ -405,7 +419,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
405
419
  };
406
420
 
407
421
  this.client.onClose = () => {
408
- this.handleDisconnect('signal');
422
+ this.handleDisconnect('signal', false, ReconnectReason.REASON_SIGNAL_DISCONNECTED);
409
423
  };
410
424
 
411
425
  this.client.onLeave = (leave?: LeaveRequest) => {
@@ -676,7 +690,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
676
690
  // websocket reconnect behavior. if websocket is interrupted, and the PeerConnection
677
691
  // continues to work, we can reconnect to websocket to continue the session
678
692
  // after a number of retries, we'll close and give up permanently
679
- private handleDisconnect = (connection: string, signalEvents: boolean = false) => {
693
+ private handleDisconnect = (
694
+ connection: string,
695
+ signalEvents: boolean = false,
696
+ disconnectReason?: ReconnectReason,
697
+ ) => {
680
698
  if (this._isClosed) {
681
699
  return;
682
700
  }
@@ -713,12 +731,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
713
731
 
714
732
  this.clearReconnectTimeout();
715
733
  this.reconnectTimeout = CriticalTimers.setTimeout(
716
- () => this.attemptReconnect(signalEvents),
734
+ () => this.attemptReconnect(signalEvents, disconnectReason),
717
735
  delay,
718
736
  );
719
737
  };
720
738
 
721
- private async attemptReconnect(signalEvents: boolean = false) {
739
+ private async attemptReconnect(signalEvents: boolean = false, reason?: ReconnectReason) {
722
740
  if (this._isClosed) {
723
741
  return;
724
742
  }
@@ -740,7 +758,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
740
758
  if (this.fullReconnectOnNext) {
741
759
  await this.restartConnection(signalEvents);
742
760
  } else {
743
- await this.resumeConnection(signalEvents);
761
+ await this.resumeConnection(signalEvents, reason);
744
762
  }
745
763
  this.clearPendingReconnect();
746
764
  this.fullReconnectOnNext = false;
@@ -766,7 +784,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
766
784
  }
767
785
 
768
786
  if (recoverable) {
769
- this.handleDisconnect('reconnect', requireSignalEvents);
787
+ this.handleDisconnect('reconnect', requireSignalEvents, ReconnectReason.REASON_UNKOWN);
770
788
  } else {
771
789
  log.info(
772
790
  `could not recover connection after ${this.reconnectAttempts} attempts, ${
@@ -831,7 +849,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
831
849
  this.emit(EngineEvent.Restarted, joinResponse);
832
850
  }
833
851
 
834
- private async resumeConnection(emitResuming: boolean = false): Promise<void> {
852
+ private async resumeConnection(
853
+ emitResuming: boolean = false,
854
+ reason?: ReconnectReason,
855
+ ): Promise<void> {
835
856
  if (!this.url || !this.token) {
836
857
  // permanent failure, don't attempt reconnection
837
858
  throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
@@ -847,7 +868,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
847
868
  }
848
869
 
849
870
  try {
850
- const res = await this.client.reconnect(this.url, this.token, this.participantSid);
871
+ const res = await this.client.reconnect(this.url, this.token, this.participantSid, reason);
851
872
  if (res) {
852
873
  const rtcConfig = this.makeRTCConfiguration(res);
853
874
  this.publisher.pc.setConfiguration(rtcConfig);
@@ -1001,7 +1022,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1001
1022
 
1002
1023
  const negotiationTimeout = setTimeout(() => {
1003
1024
  reject('negotiation timed out');
1004
- this.handleDisconnect('negotiation');
1025
+ this.handleDisconnect('negotiation', false, ReconnectReason.REASON_SIGNAL_DISCONNECTED);
1005
1026
  }, this.peerConnectionTimeout);
1006
1027
 
1007
1028
  const cleanup = () => {
@@ -1022,7 +1043,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1022
1043
  if (e instanceof NegotiationError) {
1023
1044
  this.fullReconnectOnNext = true;
1024
1045
  }
1025
- this.handleDisconnect('negotiation');
1046
+ this.handleDisconnect('negotiation', false, ReconnectReason.REASON_UNKOWN);
1026
1047
  });
1027
1048
  });
1028
1049
  }
@@ -1060,7 +1081,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1060
1081
  // in case the engine is currently reconnecting, attempt a reconnect immediately after the browser state has changed to 'onLine'
1061
1082
  if (this.client.isReconnecting) {
1062
1083
  this.clearReconnectTimeout();
1063
- this.attemptReconnect(true);
1084
+ this.attemptReconnect(true, ReconnectReason.REASON_SIGNAL_DISCONNECTED);
1064
1085
  }
1065
1086
  };
1066
1087