@koi-design/callkit 2.3.0-beta.9 → 2.3.1-beta.2

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/dist/index.js CHANGED
@@ -72,7 +72,7 @@ var Api = class {
72
72
  const res = await this.post({
73
73
  url: "/auth/agentUser/login",
74
74
  method: "post",
75
- data: params
75
+ data: { ...params, browserVersion: navigator.userAgent }
76
76
  });
77
77
  return res;
78
78
  } finally {
@@ -535,7 +535,11 @@ var SocketReceiveEvent = {
535
535
  ERROR: "ERROR",
536
536
  SESSION_ERROR: "SESSION_ERROR",
537
537
  WAITING_QUEUE: "WAITING_QUEUE",
538
- CUSTOMER_MATCH_BLACK_PHONE: "CUSTOMER_MATCH_BLACK_PHONE"
538
+ CUSTOMER_MATCH_BLACK_PHONE: "CUSTOMER_MATCH_BLACK_PHONE",
539
+ /**
540
+ * Agent RTP loss
541
+ */
542
+ AGENT_RTP_LOSS: "AGENT_RTP_LOSS"
539
543
  };
540
544
  var EncryptionMethod = {
541
545
  NONE: "NONE",
@@ -580,7 +584,9 @@ var SIP_RECONNECT_CONFIG = {
580
584
  delay: 1e3,
581
585
  registererOptions: {
582
586
  refreshFrequency: 90
583
- }
587
+ },
588
+ enableMessageKeepalive: true,
589
+ messageKeepaliveInterval: 30
584
590
  };
585
591
 
586
592
  // core/call.ts
@@ -724,13 +730,13 @@ var Call = class {
724
730
  // package.json
725
731
  var package_default = {
726
732
  name: "@koi-design/callkit",
727
- version: "2.3.0-beta.9",
733
+ version: "2.3.1-beta.2",
728
734
  description: "callkit",
729
735
  author: "koi",
730
736
  license: "ISC",
731
737
  scripts: {
732
738
  build: "tsup",
733
- start: "pnpm build && vite --host 0.0.0.0",
739
+ start: "vite --host 0.0.0.0",
734
740
  dev: "tsup --watch",
735
741
  lint: "eslint -c ../../.eslintrc.js --ext .jsx,.js,.tsx,.ts ./package --fix",
736
742
  release: "tsup && node scripts/pkg.js"
@@ -15565,7 +15571,15 @@ var Connect = class {
15565
15571
  this.callKit = callKit;
15566
15572
  }
15567
15573
  get reconnectConfig() {
15568
- return this.callKit.config.getReconnectConfig("sip");
15574
+ const { userInfo } = this.callKit.config.getConfig();
15575
+ const { enableMessageKeepalive } = userInfo;
15576
+ const { messageKeepaliveInterval } = userInfo;
15577
+ const defaultConfig = this.callKit.config.getReconnectConfig("sip");
15578
+ if (enableMessageKeepalive) {
15579
+ defaultConfig.enableMessageKeepalive = enableMessageKeepalive;
15580
+ defaultConfig.messageKeepaliveInterval = messageKeepaliveInterval;
15581
+ }
15582
+ return defaultConfig;
15569
15583
  }
15570
15584
  // current call id for invite data
15571
15585
  currentCallId = null;
@@ -15689,6 +15703,7 @@ var Connect = class {
15689
15703
  }
15690
15704
  }
15691
15705
  this.setConnectStatus(CallStatus.init);
15706
+ this.stopMessageKeepalive();
15692
15707
  }
15693
15708
  getAduioReference() {
15694
15709
  const { audioRef } = this.callKit.config.getConfig();
@@ -15824,8 +15839,6 @@ var Connect = class {
15824
15839
  });
15825
15840
  return;
15826
15841
  }
15827
- const { userInfo } = this.callKit.config.getConfig();
15828
- const { userPart, fsIp, fsPort } = userInfo;
15829
15842
  const { registererOptions = {} } = this.reconnectConfig;
15830
15843
  this.registerer = new Registerer(this.userAgent, registererOptions);
15831
15844
  this.registerer.stateChange.addListener((state) => {
@@ -15843,6 +15856,7 @@ var Connect = class {
15843
15856
  if (!this.isInCallRefering()) {
15844
15857
  this.setConnectStatus(CallStatus.init);
15845
15858
  }
15859
+ this.stopMessageKeepalive();
15846
15860
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
15847
15861
  registererState: state,
15848
15862
  isRegistered: this.isRegistered()
@@ -15859,27 +15873,26 @@ var Connect = class {
15859
15873
  });
15860
15874
  this.setRegister(true);
15861
15875
  if (this.isReConnected) {
15862
- if (this.currentSession && (this.currentSession.state === SessionState2.Established || this.currentSession.state === SessionState2.Establishing) && this.isCalling()) {
15863
- const selfUri = `sip:manualCallAgent${userPart}@${fsIp}:${fsPort}`;
15876
+ if (this.canReferInCallToSelf()) {
15864
15877
  this.callKit.logger.info(
15865
15878
  "Reconnected, referring active session to self",
15866
15879
  {
15867
15880
  caller: "Connect.setupRegisterer.registererStateChange",
15868
15881
  type: "SIP",
15869
15882
  content: {
15870
- selfUri,
15883
+ selfUri: this.getSelfReferUri(),
15871
15884
  sessionState: this.currentSession.state,
15872
15885
  connectStatus: this.connectStatus
15873
15886
  }
15874
15887
  }
15875
15888
  );
15876
- this.referInCall(selfUri).catch((err) => {
15889
+ this.referInCallToSelf().catch((err) => {
15877
15890
  this.callKit.logger.error(err, {
15878
15891
  caller: "Connect.setupRegisterer.registererStateChange",
15879
15892
  type: "SIP",
15880
15893
  content: {
15881
15894
  errCode: ErrorCode.WEBRTC_CALL_INVITE_ERROR,
15882
- selfUri
15895
+ selfUri: this.getSelfReferUri()
15883
15896
  }
15884
15897
  });
15885
15898
  });
@@ -15900,6 +15913,7 @@ var Connect = class {
15900
15913
  }
15901
15914
  this.setIsReConnected(false);
15902
15915
  }
15916
+ this.startMessageKeepalive();
15903
15917
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
15904
15918
  registererState: state,
15905
15919
  isRegistered: this.isRegistered()
@@ -15919,6 +15933,7 @@ var Connect = class {
15919
15933
  if (!this.isInCallRefering()) {
15920
15934
  this.setConnectStatus(CallStatus.init);
15921
15935
  }
15936
+ this.stopMessageKeepalive();
15922
15937
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
15923
15938
  registererState: state,
15924
15939
  isRegistered: this.isRegistered(),
@@ -15939,6 +15954,7 @@ var Connect = class {
15939
15954
  if (!this.isInCallRefering()) {
15940
15955
  this.setConnectStatus(CallStatus.init);
15941
15956
  }
15957
+ this.stopMessageKeepalive();
15942
15958
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
15943
15959
  registererState: state,
15944
15960
  isRegistered: this.isRegistered(),
@@ -15985,7 +16001,7 @@ var Connect = class {
15985
16001
  this.mediaStream = await navigator.mediaDevices.getUserMedia(constrains);
15986
16002
  return this.mediaStream;
15987
16003
  };
15988
- const { userPart, fsIp, fsPort, iceInfo, wsUrl } = userInfo;
16004
+ const { userPart, fsIp, fsPort, fsPassword, iceInfo, wsUrl } = userInfo;
15989
16005
  const connectConfig = {
15990
16006
  uri: UserAgent.makeURI(`sip:${userPart}@${fsIp}:${fsPort}`),
15991
16007
  displayName: userPart,
@@ -15994,6 +16010,8 @@ var Connect = class {
15994
16010
  traceSip: true
15995
16011
  },
15996
16012
  logLevel: "error",
16013
+ authorizationUsername: userPart,
16014
+ authorizationPassword: fsPassword,
15997
16015
  allowLegacyNotifications: true,
15998
16016
  contactName: userPart,
15999
16017
  contactParams: { transport: "wss" },
@@ -16249,7 +16267,10 @@ var Connect = class {
16249
16267
  }
16250
16268
  });
16251
16269
  this.setupRegisterer();
16252
- await this.registerer.register().catch(async (err) => {
16270
+ try {
16271
+ await this.registerer.register();
16272
+ this.startMessageKeepalive();
16273
+ } catch (err) {
16253
16274
  this.callKit.reset();
16254
16275
  this.callKit.logger.error(err?.message, {
16255
16276
  caller: "Connect.register",
@@ -16258,9 +16279,10 @@ var Connect = class {
16258
16279
  errCode: ErrorCode.WEBRTC_REGISTER_ERROR
16259
16280
  }
16260
16281
  });
16261
- });
16282
+ }
16262
16283
  },
16263
16284
  onDisconnect: (error) => {
16285
+ this.stopMessageKeepalive();
16264
16286
  if (error) {
16265
16287
  this.callKit.logger.warn("SIP User Agent Disconnected with error", {
16266
16288
  caller: "Connect.register",
@@ -16296,6 +16318,7 @@ var Connect = class {
16296
16318
  }
16297
16319
  reconnectTimer;
16298
16320
  reconnectAttempts = 0;
16321
+ messageKeepaliveTimer;
16299
16322
  startReconnectTimer() {
16300
16323
  if (this._isError || this.isReConnected)
16301
16324
  return;
@@ -16349,8 +16372,53 @@ var Connect = class {
16349
16372
  }
16350
16373
  }, this.reconnectConfig.delay);
16351
16374
  }
16375
+ stopMessageKeepalive() {
16376
+ if (this.messageKeepaliveTimer) {
16377
+ clearInterval(this.messageKeepaliveTimer);
16378
+ this.messageKeepaliveTimer = void 0;
16379
+ }
16380
+ }
16381
+ startMessageKeepalive() {
16382
+ const { enableMessageKeepalive, messageKeepaliveInterval } = this.reconnectConfig;
16383
+ if (!enableMessageKeepalive)
16384
+ return;
16385
+ this.stopMessageKeepalive();
16386
+ this.messageKeepaliveTimer = setInterval(() => {
16387
+ this.sendKeepaliveMessage();
16388
+ }, messageKeepaliveInterval * 1e3);
16389
+ }
16390
+ async sendKeepaliveMessage() {
16391
+ try {
16392
+ if (!this.isRegistered() || !this.userAgent)
16393
+ return;
16394
+ const { userInfo } = this.callKit.config.getConfig();
16395
+ const { userPart, fsIp, fsPort } = userInfo || {};
16396
+ const target = UserAgent.makeURI(`sip:${userPart}@${fsIp}:${fsPort}`);
16397
+ if (!target)
16398
+ return;
16399
+ const messager = new Messager(this.userAgent, target, "");
16400
+ await messager.message();
16401
+ this.callKit.logger.info("MESSAGE keepalive ok", {
16402
+ caller: "Connect.sendKeepaliveMessage",
16403
+ type: "SIP",
16404
+ content: {}
16405
+ });
16406
+ } catch (err) {
16407
+ this.callKit.logger.error(err, {
16408
+ caller: "Connect.sendKeepaliveMessage",
16409
+ type: "SIP",
16410
+ content: {}
16411
+ });
16412
+ this.stopMessageKeepalive();
16413
+ this.callKit.trigger(KitEvent.SIP_CONNECT_EVENT, {
16414
+ event: "MESSAGE_KEEPALIVE_FAILED"
16415
+ });
16416
+ this.startReconnectTimer();
16417
+ }
16418
+ }
16352
16419
  async stop() {
16353
16420
  await this.userAgent.stop();
16421
+ this.stopMessageKeepalive();
16354
16422
  }
16355
16423
  async unregister() {
16356
16424
  this.callKit.logger.info("connect unregister", {
@@ -16360,6 +16428,7 @@ var Connect = class {
16360
16428
  isRegistered: this.isRegistered()
16361
16429
  }
16362
16430
  });
16431
+ this.stopMessageKeepalive();
16363
16432
  if (!this.isRegistered() || !this.registerer) {
16364
16433
  this.callKit.logger.warn("No registerer to unregister.", {
16365
16434
  caller: "Connect.unregister",
@@ -16708,6 +16777,199 @@ var Connect = class {
16708
16777
  }
16709
16778
  this.currentSession.refer(target, extra?.sessionReferOptions);
16710
16779
  }
16780
+ /**
16781
+ * Get the SIP URI for "refer to self" (same as reconnection refer logic).
16782
+ * Shared by referInCallToSelf and internal reconnection refer.
16783
+ */
16784
+ getSelfReferUri() {
16785
+ const { userInfo } = this.callKit.config.getConfig();
16786
+ const { userPart, fsIp, fsPort } = userInfo;
16787
+ return `sip:manualCallAgent${userPart}@${fsIp}:${fsPort}`;
16788
+ }
16789
+ /**
16790
+ * Whether we can refer the current call to self (has active session in Established/Establishing and is calling).
16791
+ * Shared by reconnection logic and referInCallToSelf.
16792
+ */
16793
+ canReferInCallToSelf() {
16794
+ return !!this.currentSession && (this.currentSession.state === SessionState2.Established || this.currentSession.state === SessionState2.Establishing) && this.isCalling();
16795
+ }
16796
+ /**
16797
+ * Refer the current call to self (e.g. Agent RTP loss recovery, post-reconnect recovery).
16798
+ * Socket and other callers can use this without constructing referTo.
16799
+ */
16800
+ async referInCallToSelf(callUuid, extra) {
16801
+ if (callUuid && this.currentCallId !== callUuid) {
16802
+ this.callKit.logger.warn(
16803
+ "Cannot refer in call to self: callUuid mismatch",
16804
+ {
16805
+ caller: "Connect.referInCallToSelf",
16806
+ type: "SIP",
16807
+ content: {
16808
+ currentCallId: this.currentCallId,
16809
+ callUuid
16810
+ }
16811
+ }
16812
+ );
16813
+ return;
16814
+ }
16815
+ if (!this.canReferInCallToSelf()) {
16816
+ this.callKit.logger.warn(
16817
+ "Cannot refer in call to self: preconditions not met",
16818
+ {
16819
+ caller: "Connect.referInCallToSelf",
16820
+ type: "SIP",
16821
+ content: {
16822
+ hasCurrentSession: !!this.currentSession,
16823
+ sessionState: this.currentSession?.state,
16824
+ isCalling: this.isCalling()
16825
+ }
16826
+ }
16827
+ );
16828
+ return;
16829
+ }
16830
+ const selfUri = this.getSelfReferUri();
16831
+ return this.referInCall(selfUri, extra);
16832
+ }
16833
+ };
16834
+
16835
+ // core/heartbeat-worker.ts
16836
+ var workerCode = `
16837
+ let timer = null;
16838
+ let interval = 30000;
16839
+
16840
+ self.onmessage = function(e) {
16841
+ const { type, interval: newInterval } = e.data;
16842
+
16843
+ if (type === 'start') {
16844
+ if (timer) {
16845
+ clearInterval(timer);
16846
+ }
16847
+ interval = newInterval || interval;
16848
+ timer = setInterval(() => {
16849
+ self.postMessage({ type: 'tick' });
16850
+ }, interval);
16851
+ }
16852
+
16853
+ if (type === 'stop') {
16854
+ if (timer) {
16855
+ clearInterval(timer);
16856
+ timer = null;
16857
+ }
16858
+ }
16859
+
16860
+ if (type === 'updateInterval') {
16861
+ interval = newInterval;
16862
+ if (timer) {
16863
+ clearInterval(timer);
16864
+ timer = setInterval(() => {
16865
+ self.postMessage({ type: 'tick' });
16866
+ }, interval);
16867
+ }
16868
+ }
16869
+ };
16870
+ `;
16871
+ function createHeartbeatWorker() {
16872
+ try {
16873
+ const blob = new Blob([workerCode], { type: "application/javascript" });
16874
+ const workerUrl = URL.createObjectURL(blob);
16875
+ const worker = new Worker(workerUrl);
16876
+ URL.revokeObjectURL(workerUrl);
16877
+ return worker;
16878
+ } catch {
16879
+ return null;
16880
+ }
16881
+ }
16882
+ var HeartbeatManager = class {
16883
+ worker = null;
16884
+ fallbackTimer = null;
16885
+ interval = 3e4;
16886
+ onTick = null;
16887
+ isRunning = false;
16888
+ constructor() {
16889
+ this.worker = createHeartbeatWorker();
16890
+ if (this.worker) {
16891
+ this.worker.onmessage = (e) => {
16892
+ if (e.data.type === "tick" && this.onTick) {
16893
+ this.onTick();
16894
+ }
16895
+ };
16896
+ }
16897
+ }
16898
+ /**
16899
+ * Start the heartbeat
16900
+ * @param interval - Interval in milliseconds
16901
+ * @param onTick - Callback function to execute on each tick
16902
+ */
16903
+ start(interval, onTick) {
16904
+ this.stop();
16905
+ this.interval = interval;
16906
+ this.onTick = onTick;
16907
+ this.isRunning = true;
16908
+ if (this.worker) {
16909
+ this.worker.postMessage({
16910
+ type: "start",
16911
+ interval
16912
+ });
16913
+ } else {
16914
+ this.fallbackTimer = setInterval(() => {
16915
+ if (this.onTick) {
16916
+ this.onTick();
16917
+ }
16918
+ }, interval);
16919
+ }
16920
+ }
16921
+ /**
16922
+ * Stop the heartbeat
16923
+ */
16924
+ stop() {
16925
+ this.isRunning = false;
16926
+ this.onTick = null;
16927
+ if (this.worker) {
16928
+ this.worker.postMessage({ type: "stop" });
16929
+ }
16930
+ if (this.fallbackTimer) {
16931
+ clearInterval(this.fallbackTimer);
16932
+ this.fallbackTimer = null;
16933
+ }
16934
+ }
16935
+ /**
16936
+ * Update the heartbeat interval
16937
+ * @param interval - New interval in milliseconds
16938
+ */
16939
+ updateInterval(interval) {
16940
+ this.interval = interval;
16941
+ if (!this.isRunning)
16942
+ return;
16943
+ if (this.worker) {
16944
+ this.worker.postMessage({
16945
+ type: "updateInterval",
16946
+ interval
16947
+ });
16948
+ } else if (this.fallbackTimer && this.onTick) {
16949
+ clearInterval(this.fallbackTimer);
16950
+ this.fallbackTimer = setInterval(() => {
16951
+ if (this.onTick) {
16952
+ this.onTick();
16953
+ }
16954
+ }, interval);
16955
+ }
16956
+ }
16957
+ /**
16958
+ * Destroy the heartbeat manager and release resources
16959
+ */
16960
+ destroy() {
16961
+ this.stop();
16962
+ if (this.worker) {
16963
+ this.worker.terminate();
16964
+ this.worker = null;
16965
+ }
16966
+ }
16967
+ /**
16968
+ * Check if using Web Worker
16969
+ */
16970
+ isUsingWorker() {
16971
+ return this.worker !== null;
16972
+ }
16711
16973
  };
16712
16974
 
16713
16975
  // core/socket.ts
@@ -16715,7 +16977,7 @@ var Socket = class {
16715
16977
  callKit;
16716
16978
  ws;
16717
16979
  lastPingTime = void 0;
16718
- pingTimer;
16980
+ heartbeatManager;
16719
16981
  /**
16720
16982
  * @description reconnect timer
16721
16983
  */
@@ -16748,9 +17010,32 @@ var Socket = class {
16748
17010
  }
16749
17011
  constructor(callKit) {
16750
17012
  this.callKit = callKit;
17013
+ this.heartbeatManager = new HeartbeatManager();
17014
+ }
17015
+ get isUserSetPingTryCount() {
17016
+ const { userInfo } = this.callKit.config.getConfig();
17017
+ const { pingTryCount } = userInfo;
17018
+ return Number.isInteger(pingTryCount) && pingTryCount > 0;
16751
17019
  }
16752
17020
  get reconnectConfig() {
16753
- return this.callKit.config.getReconnectConfig("incall");
17021
+ const incallConfig = this.callKit.config.getReconnectConfig("incall");
17022
+ const { userInfo } = this.callKit.config.getConfig();
17023
+ const { pingTryCount, pingTryCountInterval } = userInfo;
17024
+ if (pingTryCount > 0) {
17025
+ return {
17026
+ ...incallConfig,
17027
+ maxAttempts: pingTryCount,
17028
+ interval: pingTryCountInterval * 1e3
17029
+ };
17030
+ }
17031
+ return incallConfig;
17032
+ }
17033
+ get pingInterval() {
17034
+ const { keepaliveInterval } = this.callKit.config.getConfig().userInfo;
17035
+ if (Number.isInteger(keepaliveInterval) && keepaliveInterval > 0) {
17036
+ return keepaliveInterval * 1e3;
17037
+ }
17038
+ return this.reconnectConfig.pingInterval;
16754
17039
  }
16755
17040
  isConnected() {
16756
17041
  return this.connectAuthState.isConnected;
@@ -16775,7 +17060,17 @@ var Socket = class {
16775
17060
  this.setConnectAuthState("isConnected", false);
16776
17061
  const { enabled } = this.reconnectConfig;
16777
17062
  if (!this.callKit.config.isLogin() || !enabled) {
16778
- this.callKit.reset();
17063
+ if (this.callKit.connect.isCalling()) {
17064
+ this.callKit.logger.warn("Disconnect during call, delay reset", {
17065
+ caller: "Socket.handleDisconnect",
17066
+ type: "INCALL",
17067
+ content: {
17068
+ connectStatus: this.callKit.connect.connectStatus
17069
+ }
17070
+ });
17071
+ } else {
17072
+ this.callKit.reset();
17073
+ }
16779
17074
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
16780
17075
  event: "INCALL_NOT_CONNECTED"
16781
17076
  });
@@ -16933,6 +17228,28 @@ var Socket = class {
16933
17228
  this.setConnectAuthState("startConfirm", true);
16934
17229
  this.cleanReconnectState();
16935
17230
  }
17231
+ if (data.event === SocketReceiveEvent.AGENT_RTP_LOSS) {
17232
+ this.callKit.logger.warn("Agent RTP loss", {
17233
+ caller: "Socket.onMessage",
17234
+ type: "INCALL",
17235
+ content: {
17236
+ data: {
17237
+ callUuid,
17238
+ ...content
17239
+ },
17240
+ event: SocketReceiveEvent.AGENT_RTP_LOSS
17241
+ }
17242
+ });
17243
+ if (callUuid) {
17244
+ this.callKit.connect.referInCallToSelf(callUuid).catch((err) => {
17245
+ this.callKit.logger.error(err, {
17246
+ caller: "Socket.onMessage:AGENT_RTP_LOSS",
17247
+ type: "INCALL",
17248
+ content: { callUuid, event: SocketReceiveEvent.AGENT_RTP_LOSS }
17249
+ });
17250
+ });
17251
+ }
17252
+ }
16936
17253
  if (data.event === SocketReceiveEvent.CUSTOMER_RINGING) {
16937
17254
  this.callKit.trigger(KitEvent.CALL_RINGING, {
16938
17255
  time: /* @__PURE__ */ new Date(),
@@ -16981,6 +17298,18 @@ var Socket = class {
16981
17298
  this.send(SocketSendEvent.END, { agentId: userInfo.agentId, callUuid });
16982
17299
  }
16983
17300
  if (data.event === SocketReceiveEvent.ERROR) {
17301
+ if (this.callKit.connect.isCalling()) {
17302
+ this.callKit.logger.warn("socket onMessage error during call, ignore", {
17303
+ caller: "Socket.onMessage",
17304
+ type: "INCALL",
17305
+ content: {
17306
+ errCode: ErrorCode.SOCKET_CONNECT_ERROR,
17307
+ isCalling: this.callKit.connect.isCalling(),
17308
+ data: content
17309
+ }
17310
+ });
17311
+ return;
17312
+ }
16984
17313
  this.setConnectAuthState("isError", true);
16985
17314
  this.callKit.reset();
16986
17315
  this.callKit.logger.error(data.msg, {
@@ -16989,20 +17318,24 @@ var Socket = class {
16989
17318
  content: {
16990
17319
  errCode: ErrorCode.SOKET_SERVER_ERROR,
16991
17320
  data: content,
16992
- callUuid
17321
+ callUuid,
17322
+ delayReset: this.callKit.connect.isCalling()
16993
17323
  }
16994
17324
  });
16995
17325
  }
16996
17326
  if (data.event === SocketReceiveEvent.SESSION_ERROR) {
16997
17327
  this.setConnectAuthState("isError", true);
16998
- this.callKit.reset();
17328
+ if (!this.callKit.connect.isCalling()) {
17329
+ this.callKit.reset();
17330
+ }
16999
17331
  this.callKit.logger.error(data.msg, {
17000
17332
  caller: `Socket.onMessage:${data.event}`,
17001
17333
  type: "INCALL",
17002
17334
  content: {
17003
17335
  data: content,
17004
17336
  event: SocketReceiveEvent.SESSION_ERROR,
17005
- callUuid
17337
+ callUuid,
17338
+ delayReset: this.callKit.connect.isCalling()
17006
17339
  }
17007
17340
  });
17008
17341
  }
@@ -17034,6 +17367,18 @@ var Socket = class {
17034
17367
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
17035
17368
  event: "INCALL_NOT_CONNECTED"
17036
17369
  });
17370
+ if (this.callKit.connect.isCalling()) {
17371
+ this.callKit.logger.warn("socket send during call, ignore", {
17372
+ caller: "Socket.onMessage",
17373
+ type: "INCALL",
17374
+ content: {
17375
+ errCode: ErrorCode.SOCKET_CONNECT_ERROR,
17376
+ isCalling: this.callKit.connect.isCalling(),
17377
+ data: message
17378
+ }
17379
+ });
17380
+ return;
17381
+ }
17037
17382
  this.callKit.reset();
17038
17383
  this.callKit.logger.error("socket not connected", {
17039
17384
  caller: "Socket.send",
@@ -17086,8 +17431,8 @@ var Socket = class {
17086
17431
  return;
17087
17432
  this.send(SocketSendEvent.PING);
17088
17433
  const now = Date.now();
17089
- const { pingInterval, pingTimeout } = this.reconnectConfig;
17090
- if (now - this.lastPingTime > pingInterval + pingTimeout) {
17434
+ const { pingTimeout } = this.reconnectConfig;
17435
+ if (now - this.lastPingTime > this.pingInterval + pingTimeout) {
17091
17436
  this.callKit.logger.warn("Ping timeout not connected", {
17092
17437
  caller: "Socket.ping",
17093
17438
  type: "INCALL",
@@ -17099,26 +17444,48 @@ var Socket = class {
17099
17444
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
17100
17445
  event: "INCALL_PING_TIMEOUT"
17101
17446
  });
17447
+ if (this.isUserSetPingTryCount) {
17448
+ this.handlePingTimeout();
17449
+ }
17102
17450
  }
17103
17451
  }
17452
+ handlePingTimeout() {
17453
+ const { userInfo } = this.callKit.config.getConfig();
17454
+ const { pingTryCount, pingTryCountInterval } = userInfo;
17455
+ this.callKit.logger.warn("Ping timeout, user set ping try count", {
17456
+ caller: "Socket.handlePingTimeout",
17457
+ type: "INCALL",
17458
+ content: {
17459
+ errCode: ErrorCode.SOCKET_PING_TIMEOUT,
17460
+ isUserSetPingTryCount: this.isUserSetPingTryCount,
17461
+ pingTryCount,
17462
+ pingTryCountInterval
17463
+ }
17464
+ });
17465
+ this.attemptReconnect();
17466
+ }
17104
17467
  checkPing() {
17105
- if (this.pingTimer) {
17106
- clearInterval(this.pingTimer);
17107
- }
17108
- const { pingInterval } = this.reconnectConfig;
17109
- this.pingTimer = setInterval(() => {
17468
+ this.heartbeatManager.start(this.pingInterval, () => {
17110
17469
  this.ping();
17111
- }, pingInterval);
17470
+ });
17471
+ this.callKit.logger.info(
17472
+ `Heartbeat started with Worker: ${this.heartbeatManager.isUsingWorker()}`,
17473
+ {
17474
+ caller: "Socket.checkPing",
17475
+ type: "INCALL",
17476
+ content: {
17477
+ pingInterval: this.pingInterval,
17478
+ usingWorker: this.heartbeatManager.isUsingWorker()
17479
+ }
17480
+ }
17481
+ );
17112
17482
  }
17113
17483
  /**
17114
17484
  * reset socket connection and all states
17115
17485
  */
17116
17486
  async reset(config) {
17117
17487
  const { force = false } = config || {};
17118
- if (this.pingTimer) {
17119
- clearInterval(this.pingTimer);
17120
- this.pingTimer = void 0;
17121
- }
17488
+ this.heartbeatManager.stop();
17122
17489
  if (force) {
17123
17490
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
17124
17491
  event: "INCALL_RESET"
@@ -17129,6 +17496,12 @@ var Socket = class {
17129
17496
  this.setConnectAuthState("startConfirm", false);
17130
17497
  this.clearWebSocket();
17131
17498
  }
17499
+ /**
17500
+ * Destroy the heartbeat manager
17501
+ */
17502
+ destroyHeartbeat() {
17503
+ this.heartbeatManager.destroy();
17504
+ }
17132
17505
  attemptReconnect() {
17133
17506
  if (this.reconnectTimer) {
17134
17507
  clearTimeout(this.reconnectTimer);
@@ -17136,19 +17509,40 @@ var Socket = class {
17136
17509
  }
17137
17510
  const { maxAttempts } = this.reconnectConfig;
17138
17511
  if (this.reconnectAttempts >= maxAttempts) {
17512
+ if (this.callKit.connect.isCalling()) {
17513
+ this.callKit.logger.warn("reconnect during call, ignore", {
17514
+ caller: "Socket.attemptReconnect",
17515
+ type: "INCALL",
17516
+ content: {
17517
+ errCode: ErrorCode.SOCKET_RECONNECT_FAILED,
17518
+ isCalling: this.callKit.connect.isCalling(),
17519
+ reconnectAttempts: this.reconnectAttempts
17520
+ }
17521
+ });
17522
+ return;
17523
+ }
17524
+ if (this.isUserSetPingTryCount) {
17525
+ this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
17526
+ event: "INCALL_PING_TIMEOUT_RECONNECT_FAILED_MAX_ATTEMPTS"
17527
+ });
17528
+ }
17139
17529
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
17140
17530
  event: "INCALL_RECONNECT_ERROR"
17141
17531
  });
17142
17532
  this.setConnectAuthState("isError", true);
17143
17533
  this.callKit.reset();
17144
- this.callKit.logger.error("Maximum reconnection attempts reached", {
17145
- caller: "Socket.attemptReconnect",
17146
- type: "INCALL",
17147
- content: {
17148
- errCode: ErrorCode.SOCKET_RECONNECT_FAILED,
17149
- reconnectAttempts: this.reconnectAttempts
17534
+ this.callKit.logger.warn(
17535
+ "Maximum reconnection attempts reached, trigger reset",
17536
+ {
17537
+ caller: "Socket.attemptReconnect",
17538
+ type: "INCALL",
17539
+ content: {
17540
+ errCode: ErrorCode.SOCKET_RECONNECT_FAILED,
17541
+ reconnectAttempts: this.reconnectAttempts,
17542
+ delayReset: this.callKit.connect.isCalling()
17543
+ }
17150
17544
  }
17151
- });
17545
+ );
17152
17546
  return;
17153
17547
  }
17154
17548
  if (this.reconnectAttempts === 0) {
@@ -17254,6 +17648,7 @@ var CallKit = class {
17254
17648
  content: {
17255
17649
  username,
17256
17650
  password,
17651
+ ua: navigator.userAgent,
17257
17652
  encryptionMethod,
17258
17653
  encryptionPassword
17259
17654
  }
@@ -17273,6 +17668,7 @@ var CallKit = class {
17273
17668
  });
17274
17669
  if (user) {
17275
17670
  this.config.setConfig("userInfo", {
17671
+ ...user,
17276
17672
  wsUrl: `wss://${user.wsUrl}`,
17277
17673
  sessionId: user.sessionId,
17278
17674
  username,
@@ -17287,6 +17683,9 @@ var CallKit = class {
17287
17683
  iceInfo: user.iceInfo,
17288
17684
  iceGatheringTimeout: user.iceGatheringTimeout,
17289
17685
  logGather: user.logGather,
17686
+ keepaliveInterval: user.keepaliveInterval,
17687
+ pingTryCount: user?.pingTryCount,
17688
+ pingTryCountInterval: user?.pingTryCountInterval,
17290
17689
  phoneType: user.phoneType,
17291
17690
  // encryptionType is in extra
17292
17691
  ...extra
@@ -17565,4 +17964,3 @@ var CallKit = class {
17565
17964
  0 && (module.exports = {
17566
17965
  CallKit
17567
17966
  });
17568
- //# sourceMappingURL=index.js.map