@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.
@@ -1736,7 +1736,7 @@ var WebCall = (() => {
1736
1736
  var require_follow_redirects = __commonJS({
1737
1737
  "../../node_modules/.pnpm/follow-redirects@1.15.9/node_modules/follow-redirects/index.js"(exports, module) {
1738
1738
  var url = __require("url");
1739
- var URL = url.URL;
1739
+ var URL2 = url.URL;
1740
1740
  var http = __require("http");
1741
1741
  var https = __require("https");
1742
1742
  var Writable = __require("stream").Writable;
@@ -1752,7 +1752,7 @@ var WebCall = (() => {
1752
1752
  })();
1753
1753
  var useNativeURL = false;
1754
1754
  try {
1755
- assert(new URL(""));
1755
+ assert(new URL2(""));
1756
1756
  } catch (error) {
1757
1757
  useNativeURL = error.code === "ERR_INVALID_URL";
1758
1758
  }
@@ -2132,7 +2132,7 @@ var WebCall = (() => {
2132
2132
  function parseUrl(input) {
2133
2133
  var parsed;
2134
2134
  if (useNativeURL) {
2135
- parsed = new URL(input);
2135
+ parsed = new URL2(input);
2136
2136
  } else {
2137
2137
  parsed = validateUrl(url.parse(input));
2138
2138
  if (!isString(parsed.protocol)) {
@@ -2142,7 +2142,7 @@ var WebCall = (() => {
2142
2142
  return parsed;
2143
2143
  }
2144
2144
  function resolveUrl(relative, base) {
2145
- return useNativeURL ? new URL(relative, base) : parseUrl(url.resolve(base, relative));
2145
+ return useNativeURL ? new URL2(relative, base) : parseUrl(url.resolve(base, relative));
2146
2146
  }
2147
2147
  function validateUrl(input) {
2148
2148
  if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
@@ -2221,7 +2221,7 @@ var WebCall = (() => {
2221
2221
  return typeof value === "object" && "length" in value;
2222
2222
  }
2223
2223
  function isURL(value) {
2224
- return URL && value instanceof URL;
2224
+ return URL2 && value instanceof URL2;
2225
2225
  }
2226
2226
  module.exports = wrap({ http, https });
2227
2227
  module.exports.wrap = wrap;
@@ -3237,7 +3237,7 @@ var WebCall = (() => {
3237
3237
  const res = await this.post({
3238
3238
  url: "/auth/agentUser/login",
3239
3239
  method: "post",
3240
- data: params
3240
+ data: { ...params, browserVersion: navigator.userAgent }
3241
3241
  });
3242
3242
  return res;
3243
3243
  } finally {
@@ -3700,7 +3700,11 @@ var WebCall = (() => {
3700
3700
  ERROR: "ERROR",
3701
3701
  SESSION_ERROR: "SESSION_ERROR",
3702
3702
  WAITING_QUEUE: "WAITING_QUEUE",
3703
- CUSTOMER_MATCH_BLACK_PHONE: "CUSTOMER_MATCH_BLACK_PHONE"
3703
+ CUSTOMER_MATCH_BLACK_PHONE: "CUSTOMER_MATCH_BLACK_PHONE",
3704
+ /**
3705
+ * Agent RTP loss
3706
+ */
3707
+ AGENT_RTP_LOSS: "AGENT_RTP_LOSS"
3704
3708
  };
3705
3709
  var EncryptionMethod = {
3706
3710
  NONE: "NONE",
@@ -3745,7 +3749,9 @@ var WebCall = (() => {
3745
3749
  delay: 1e3,
3746
3750
  registererOptions: {
3747
3751
  refreshFrequency: 90
3748
- }
3752
+ },
3753
+ enableMessageKeepalive: true,
3754
+ messageKeepaliveInterval: 30
3749
3755
  };
3750
3756
 
3751
3757
  // core/call.ts
@@ -3889,13 +3895,13 @@ var WebCall = (() => {
3889
3895
  // package.json
3890
3896
  var package_default = {
3891
3897
  name: "@koi-design/callkit",
3892
- version: "2.3.0-beta.9",
3898
+ version: "2.3.1-beta.2",
3893
3899
  description: "callkit",
3894
3900
  author: "koi",
3895
3901
  license: "ISC",
3896
3902
  scripts: {
3897
3903
  build: "tsup",
3898
- start: "pnpm build && vite --host 0.0.0.0",
3904
+ start: "vite --host 0.0.0.0",
3899
3905
  dev: "tsup --watch",
3900
3906
  lint: "eslint -c ../../.eslintrc.js --ext .jsx,.js,.tsx,.ts ./package --fix",
3901
3907
  release: "tsup && node scripts/pkg.js"
@@ -18730,7 +18736,15 @@ ${log}` : log;
18730
18736
  this.callKit = callKit;
18731
18737
  }
18732
18738
  get reconnectConfig() {
18733
- return this.callKit.config.getReconnectConfig("sip");
18739
+ const { userInfo } = this.callKit.config.getConfig();
18740
+ const { enableMessageKeepalive } = userInfo;
18741
+ const { messageKeepaliveInterval } = userInfo;
18742
+ const defaultConfig = this.callKit.config.getReconnectConfig("sip");
18743
+ if (enableMessageKeepalive) {
18744
+ defaultConfig.enableMessageKeepalive = enableMessageKeepalive;
18745
+ defaultConfig.messageKeepaliveInterval = messageKeepaliveInterval;
18746
+ }
18747
+ return defaultConfig;
18734
18748
  }
18735
18749
  // current call id for invite data
18736
18750
  currentCallId = null;
@@ -18854,6 +18868,7 @@ ${log}` : log;
18854
18868
  }
18855
18869
  }
18856
18870
  this.setConnectStatus(CallStatus.init);
18871
+ this.stopMessageKeepalive();
18857
18872
  }
18858
18873
  getAduioReference() {
18859
18874
  const { audioRef } = this.callKit.config.getConfig();
@@ -18989,8 +19004,6 @@ ${log}` : log;
18989
19004
  });
18990
19005
  return;
18991
19006
  }
18992
- const { userInfo } = this.callKit.config.getConfig();
18993
- const { userPart, fsIp, fsPort } = userInfo;
18994
19007
  const { registererOptions = {} } = this.reconnectConfig;
18995
19008
  this.registerer = new Registerer(this.userAgent, registererOptions);
18996
19009
  this.registerer.stateChange.addListener((state) => {
@@ -19008,6 +19021,7 @@ ${log}` : log;
19008
19021
  if (!this.isInCallRefering()) {
19009
19022
  this.setConnectStatus(CallStatus.init);
19010
19023
  }
19024
+ this.stopMessageKeepalive();
19011
19025
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
19012
19026
  registererState: state,
19013
19027
  isRegistered: this.isRegistered()
@@ -19024,27 +19038,26 @@ ${log}` : log;
19024
19038
  });
19025
19039
  this.setRegister(true);
19026
19040
  if (this.isReConnected) {
19027
- if (this.currentSession && (this.currentSession.state === SessionState2.Established || this.currentSession.state === SessionState2.Establishing) && this.isCalling()) {
19028
- const selfUri = `sip:manualCallAgent${userPart}@${fsIp}:${fsPort}`;
19041
+ if (this.canReferInCallToSelf()) {
19029
19042
  this.callKit.logger.info(
19030
19043
  "Reconnected, referring active session to self",
19031
19044
  {
19032
19045
  caller: "Connect.setupRegisterer.registererStateChange",
19033
19046
  type: "SIP",
19034
19047
  content: {
19035
- selfUri,
19048
+ selfUri: this.getSelfReferUri(),
19036
19049
  sessionState: this.currentSession.state,
19037
19050
  connectStatus: this.connectStatus
19038
19051
  }
19039
19052
  }
19040
19053
  );
19041
- this.referInCall(selfUri).catch((err) => {
19054
+ this.referInCallToSelf().catch((err) => {
19042
19055
  this.callKit.logger.error(err, {
19043
19056
  caller: "Connect.setupRegisterer.registererStateChange",
19044
19057
  type: "SIP",
19045
19058
  content: {
19046
19059
  errCode: ErrorCode.WEBRTC_CALL_INVITE_ERROR,
19047
- selfUri
19060
+ selfUri: this.getSelfReferUri()
19048
19061
  }
19049
19062
  });
19050
19063
  });
@@ -19065,6 +19078,7 @@ ${log}` : log;
19065
19078
  }
19066
19079
  this.setIsReConnected(false);
19067
19080
  }
19081
+ this.startMessageKeepalive();
19068
19082
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
19069
19083
  registererState: state,
19070
19084
  isRegistered: this.isRegistered()
@@ -19084,6 +19098,7 @@ ${log}` : log;
19084
19098
  if (!this.isInCallRefering()) {
19085
19099
  this.setConnectStatus(CallStatus.init);
19086
19100
  }
19101
+ this.stopMessageKeepalive();
19087
19102
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
19088
19103
  registererState: state,
19089
19104
  isRegistered: this.isRegistered(),
@@ -19104,6 +19119,7 @@ ${log}` : log;
19104
19119
  if (!this.isInCallRefering()) {
19105
19120
  this.setConnectStatus(CallStatus.init);
19106
19121
  }
19122
+ this.stopMessageKeepalive();
19107
19123
  this.callKit.trigger(KitEvent.SIP_REGISTERER_EVENT, {
19108
19124
  registererState: state,
19109
19125
  isRegistered: this.isRegistered(),
@@ -19150,7 +19166,7 @@ ${log}` : log;
19150
19166
  this.mediaStream = await navigator.mediaDevices.getUserMedia(constrains);
19151
19167
  return this.mediaStream;
19152
19168
  };
19153
- const { userPart, fsIp, fsPort, iceInfo, wsUrl } = userInfo;
19169
+ const { userPart, fsIp, fsPort, fsPassword, iceInfo, wsUrl } = userInfo;
19154
19170
  const connectConfig = {
19155
19171
  uri: UserAgent.makeURI(`sip:${userPart}@${fsIp}:${fsPort}`),
19156
19172
  displayName: userPart,
@@ -19159,6 +19175,8 @@ ${log}` : log;
19159
19175
  traceSip: true
19160
19176
  },
19161
19177
  logLevel: "error",
19178
+ authorizationUsername: userPart,
19179
+ authorizationPassword: fsPassword,
19162
19180
  allowLegacyNotifications: true,
19163
19181
  contactName: userPart,
19164
19182
  contactParams: { transport: "wss" },
@@ -19414,7 +19432,10 @@ ${log}` : log;
19414
19432
  }
19415
19433
  });
19416
19434
  this.setupRegisterer();
19417
- await this.registerer.register().catch(async (err) => {
19435
+ try {
19436
+ await this.registerer.register();
19437
+ this.startMessageKeepalive();
19438
+ } catch (err) {
19418
19439
  this.callKit.reset();
19419
19440
  this.callKit.logger.error(err?.message, {
19420
19441
  caller: "Connect.register",
@@ -19423,9 +19444,10 @@ ${log}` : log;
19423
19444
  errCode: ErrorCode.WEBRTC_REGISTER_ERROR
19424
19445
  }
19425
19446
  });
19426
- });
19447
+ }
19427
19448
  },
19428
19449
  onDisconnect: (error) => {
19450
+ this.stopMessageKeepalive();
19429
19451
  if (error) {
19430
19452
  this.callKit.logger.warn("SIP User Agent Disconnected with error", {
19431
19453
  caller: "Connect.register",
@@ -19461,6 +19483,7 @@ ${log}` : log;
19461
19483
  }
19462
19484
  reconnectTimer;
19463
19485
  reconnectAttempts = 0;
19486
+ messageKeepaliveTimer;
19464
19487
  startReconnectTimer() {
19465
19488
  if (this._isError || this.isReConnected)
19466
19489
  return;
@@ -19514,8 +19537,53 @@ ${log}` : log;
19514
19537
  }
19515
19538
  }, this.reconnectConfig.delay);
19516
19539
  }
19540
+ stopMessageKeepalive() {
19541
+ if (this.messageKeepaliveTimer) {
19542
+ clearInterval(this.messageKeepaliveTimer);
19543
+ this.messageKeepaliveTimer = void 0;
19544
+ }
19545
+ }
19546
+ startMessageKeepalive() {
19547
+ const { enableMessageKeepalive, messageKeepaliveInterval } = this.reconnectConfig;
19548
+ if (!enableMessageKeepalive)
19549
+ return;
19550
+ this.stopMessageKeepalive();
19551
+ this.messageKeepaliveTimer = setInterval(() => {
19552
+ this.sendKeepaliveMessage();
19553
+ }, messageKeepaliveInterval * 1e3);
19554
+ }
19555
+ async sendKeepaliveMessage() {
19556
+ try {
19557
+ if (!this.isRegistered() || !this.userAgent)
19558
+ return;
19559
+ const { userInfo } = this.callKit.config.getConfig();
19560
+ const { userPart, fsIp, fsPort } = userInfo || {};
19561
+ const target = UserAgent.makeURI(`sip:${userPart}@${fsIp}:${fsPort}`);
19562
+ if (!target)
19563
+ return;
19564
+ const messager = new Messager(this.userAgent, target, "");
19565
+ await messager.message();
19566
+ this.callKit.logger.info("MESSAGE keepalive ok", {
19567
+ caller: "Connect.sendKeepaliveMessage",
19568
+ type: "SIP",
19569
+ content: {}
19570
+ });
19571
+ } catch (err) {
19572
+ this.callKit.logger.error(err, {
19573
+ caller: "Connect.sendKeepaliveMessage",
19574
+ type: "SIP",
19575
+ content: {}
19576
+ });
19577
+ this.stopMessageKeepalive();
19578
+ this.callKit.trigger(KitEvent.SIP_CONNECT_EVENT, {
19579
+ event: "MESSAGE_KEEPALIVE_FAILED"
19580
+ });
19581
+ this.startReconnectTimer();
19582
+ }
19583
+ }
19517
19584
  async stop() {
19518
19585
  await this.userAgent.stop();
19586
+ this.stopMessageKeepalive();
19519
19587
  }
19520
19588
  async unregister() {
19521
19589
  this.callKit.logger.info("connect unregister", {
@@ -19525,6 +19593,7 @@ ${log}` : log;
19525
19593
  isRegistered: this.isRegistered()
19526
19594
  }
19527
19595
  });
19596
+ this.stopMessageKeepalive();
19528
19597
  if (!this.isRegistered() || !this.registerer) {
19529
19598
  this.callKit.logger.warn("No registerer to unregister.", {
19530
19599
  caller: "Connect.unregister",
@@ -19873,6 +19942,199 @@ ${log}` : log;
19873
19942
  }
19874
19943
  this.currentSession.refer(target, extra?.sessionReferOptions);
19875
19944
  }
19945
+ /**
19946
+ * Get the SIP URI for "refer to self" (same as reconnection refer logic).
19947
+ * Shared by referInCallToSelf and internal reconnection refer.
19948
+ */
19949
+ getSelfReferUri() {
19950
+ const { userInfo } = this.callKit.config.getConfig();
19951
+ const { userPart, fsIp, fsPort } = userInfo;
19952
+ return `sip:manualCallAgent${userPart}@${fsIp}:${fsPort}`;
19953
+ }
19954
+ /**
19955
+ * Whether we can refer the current call to self (has active session in Established/Establishing and is calling).
19956
+ * Shared by reconnection logic and referInCallToSelf.
19957
+ */
19958
+ canReferInCallToSelf() {
19959
+ return !!this.currentSession && (this.currentSession.state === SessionState2.Established || this.currentSession.state === SessionState2.Establishing) && this.isCalling();
19960
+ }
19961
+ /**
19962
+ * Refer the current call to self (e.g. Agent RTP loss recovery, post-reconnect recovery).
19963
+ * Socket and other callers can use this without constructing referTo.
19964
+ */
19965
+ async referInCallToSelf(callUuid, extra) {
19966
+ if (callUuid && this.currentCallId !== callUuid) {
19967
+ this.callKit.logger.warn(
19968
+ "Cannot refer in call to self: callUuid mismatch",
19969
+ {
19970
+ caller: "Connect.referInCallToSelf",
19971
+ type: "SIP",
19972
+ content: {
19973
+ currentCallId: this.currentCallId,
19974
+ callUuid
19975
+ }
19976
+ }
19977
+ );
19978
+ return;
19979
+ }
19980
+ if (!this.canReferInCallToSelf()) {
19981
+ this.callKit.logger.warn(
19982
+ "Cannot refer in call to self: preconditions not met",
19983
+ {
19984
+ caller: "Connect.referInCallToSelf",
19985
+ type: "SIP",
19986
+ content: {
19987
+ hasCurrentSession: !!this.currentSession,
19988
+ sessionState: this.currentSession?.state,
19989
+ isCalling: this.isCalling()
19990
+ }
19991
+ }
19992
+ );
19993
+ return;
19994
+ }
19995
+ const selfUri = this.getSelfReferUri();
19996
+ return this.referInCall(selfUri, extra);
19997
+ }
19998
+ };
19999
+
20000
+ // core/heartbeat-worker.ts
20001
+ var workerCode = `
20002
+ let timer = null;
20003
+ let interval = 30000;
20004
+
20005
+ self.onmessage = function(e) {
20006
+ const { type, interval: newInterval } = e.data;
20007
+
20008
+ if (type === 'start') {
20009
+ if (timer) {
20010
+ clearInterval(timer);
20011
+ }
20012
+ interval = newInterval || interval;
20013
+ timer = setInterval(() => {
20014
+ self.postMessage({ type: 'tick' });
20015
+ }, interval);
20016
+ }
20017
+
20018
+ if (type === 'stop') {
20019
+ if (timer) {
20020
+ clearInterval(timer);
20021
+ timer = null;
20022
+ }
20023
+ }
20024
+
20025
+ if (type === 'updateInterval') {
20026
+ interval = newInterval;
20027
+ if (timer) {
20028
+ clearInterval(timer);
20029
+ timer = setInterval(() => {
20030
+ self.postMessage({ type: 'tick' });
20031
+ }, interval);
20032
+ }
20033
+ }
20034
+ };
20035
+ `;
20036
+ function createHeartbeatWorker() {
20037
+ try {
20038
+ const blob = new Blob([workerCode], { type: "application/javascript" });
20039
+ const workerUrl = URL.createObjectURL(blob);
20040
+ const worker = new Worker(workerUrl);
20041
+ URL.revokeObjectURL(workerUrl);
20042
+ return worker;
20043
+ } catch {
20044
+ return null;
20045
+ }
20046
+ }
20047
+ var HeartbeatManager = class {
20048
+ worker = null;
20049
+ fallbackTimer = null;
20050
+ interval = 3e4;
20051
+ onTick = null;
20052
+ isRunning = false;
20053
+ constructor() {
20054
+ this.worker = createHeartbeatWorker();
20055
+ if (this.worker) {
20056
+ this.worker.onmessage = (e) => {
20057
+ if (e.data.type === "tick" && this.onTick) {
20058
+ this.onTick();
20059
+ }
20060
+ };
20061
+ }
20062
+ }
20063
+ /**
20064
+ * Start the heartbeat
20065
+ * @param interval - Interval in milliseconds
20066
+ * @param onTick - Callback function to execute on each tick
20067
+ */
20068
+ start(interval, onTick) {
20069
+ this.stop();
20070
+ this.interval = interval;
20071
+ this.onTick = onTick;
20072
+ this.isRunning = true;
20073
+ if (this.worker) {
20074
+ this.worker.postMessage({
20075
+ type: "start",
20076
+ interval
20077
+ });
20078
+ } else {
20079
+ this.fallbackTimer = setInterval(() => {
20080
+ if (this.onTick) {
20081
+ this.onTick();
20082
+ }
20083
+ }, interval);
20084
+ }
20085
+ }
20086
+ /**
20087
+ * Stop the heartbeat
20088
+ */
20089
+ stop() {
20090
+ this.isRunning = false;
20091
+ this.onTick = null;
20092
+ if (this.worker) {
20093
+ this.worker.postMessage({ type: "stop" });
20094
+ }
20095
+ if (this.fallbackTimer) {
20096
+ clearInterval(this.fallbackTimer);
20097
+ this.fallbackTimer = null;
20098
+ }
20099
+ }
20100
+ /**
20101
+ * Update the heartbeat interval
20102
+ * @param interval - New interval in milliseconds
20103
+ */
20104
+ updateInterval(interval) {
20105
+ this.interval = interval;
20106
+ if (!this.isRunning)
20107
+ return;
20108
+ if (this.worker) {
20109
+ this.worker.postMessage({
20110
+ type: "updateInterval",
20111
+ interval
20112
+ });
20113
+ } else if (this.fallbackTimer && this.onTick) {
20114
+ clearInterval(this.fallbackTimer);
20115
+ this.fallbackTimer = setInterval(() => {
20116
+ if (this.onTick) {
20117
+ this.onTick();
20118
+ }
20119
+ }, interval);
20120
+ }
20121
+ }
20122
+ /**
20123
+ * Destroy the heartbeat manager and release resources
20124
+ */
20125
+ destroy() {
20126
+ this.stop();
20127
+ if (this.worker) {
20128
+ this.worker.terminate();
20129
+ this.worker = null;
20130
+ }
20131
+ }
20132
+ /**
20133
+ * Check if using Web Worker
20134
+ */
20135
+ isUsingWorker() {
20136
+ return this.worker !== null;
20137
+ }
19876
20138
  };
19877
20139
 
19878
20140
  // core/socket.ts
@@ -19880,7 +20142,7 @@ ${log}` : log;
19880
20142
  callKit;
19881
20143
  ws;
19882
20144
  lastPingTime = void 0;
19883
- pingTimer;
20145
+ heartbeatManager;
19884
20146
  /**
19885
20147
  * @description reconnect timer
19886
20148
  */
@@ -19913,9 +20175,32 @@ ${log}` : log;
19913
20175
  }
19914
20176
  constructor(callKit) {
19915
20177
  this.callKit = callKit;
20178
+ this.heartbeatManager = new HeartbeatManager();
20179
+ }
20180
+ get isUserSetPingTryCount() {
20181
+ const { userInfo } = this.callKit.config.getConfig();
20182
+ const { pingTryCount } = userInfo;
20183
+ return Number.isInteger(pingTryCount) && pingTryCount > 0;
19916
20184
  }
19917
20185
  get reconnectConfig() {
19918
- return this.callKit.config.getReconnectConfig("incall");
20186
+ const incallConfig = this.callKit.config.getReconnectConfig("incall");
20187
+ const { userInfo } = this.callKit.config.getConfig();
20188
+ const { pingTryCount, pingTryCountInterval } = userInfo;
20189
+ if (pingTryCount > 0) {
20190
+ return {
20191
+ ...incallConfig,
20192
+ maxAttempts: pingTryCount,
20193
+ interval: pingTryCountInterval * 1e3
20194
+ };
20195
+ }
20196
+ return incallConfig;
20197
+ }
20198
+ get pingInterval() {
20199
+ const { keepaliveInterval } = this.callKit.config.getConfig().userInfo;
20200
+ if (Number.isInteger(keepaliveInterval) && keepaliveInterval > 0) {
20201
+ return keepaliveInterval * 1e3;
20202
+ }
20203
+ return this.reconnectConfig.pingInterval;
19919
20204
  }
19920
20205
  isConnected() {
19921
20206
  return this.connectAuthState.isConnected;
@@ -19940,7 +20225,17 @@ ${log}` : log;
19940
20225
  this.setConnectAuthState("isConnected", false);
19941
20226
  const { enabled } = this.reconnectConfig;
19942
20227
  if (!this.callKit.config.isLogin() || !enabled) {
19943
- this.callKit.reset();
20228
+ if (this.callKit.connect.isCalling()) {
20229
+ this.callKit.logger.warn("Disconnect during call, delay reset", {
20230
+ caller: "Socket.handleDisconnect",
20231
+ type: "INCALL",
20232
+ content: {
20233
+ connectStatus: this.callKit.connect.connectStatus
20234
+ }
20235
+ });
20236
+ } else {
20237
+ this.callKit.reset();
20238
+ }
19944
20239
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
19945
20240
  event: "INCALL_NOT_CONNECTED"
19946
20241
  });
@@ -20098,6 +20393,28 @@ ${log}` : log;
20098
20393
  this.setConnectAuthState("startConfirm", true);
20099
20394
  this.cleanReconnectState();
20100
20395
  }
20396
+ if (data.event === SocketReceiveEvent.AGENT_RTP_LOSS) {
20397
+ this.callKit.logger.warn("Agent RTP loss", {
20398
+ caller: "Socket.onMessage",
20399
+ type: "INCALL",
20400
+ content: {
20401
+ data: {
20402
+ callUuid,
20403
+ ...content
20404
+ },
20405
+ event: SocketReceiveEvent.AGENT_RTP_LOSS
20406
+ }
20407
+ });
20408
+ if (callUuid) {
20409
+ this.callKit.connect.referInCallToSelf(callUuid).catch((err) => {
20410
+ this.callKit.logger.error(err, {
20411
+ caller: "Socket.onMessage:AGENT_RTP_LOSS",
20412
+ type: "INCALL",
20413
+ content: { callUuid, event: SocketReceiveEvent.AGENT_RTP_LOSS }
20414
+ });
20415
+ });
20416
+ }
20417
+ }
20101
20418
  if (data.event === SocketReceiveEvent.CUSTOMER_RINGING) {
20102
20419
  this.callKit.trigger(KitEvent.CALL_RINGING, {
20103
20420
  time: /* @__PURE__ */ new Date(),
@@ -20146,6 +20463,18 @@ ${log}` : log;
20146
20463
  this.send(SocketSendEvent.END, { agentId: userInfo.agentId, callUuid });
20147
20464
  }
20148
20465
  if (data.event === SocketReceiveEvent.ERROR) {
20466
+ if (this.callKit.connect.isCalling()) {
20467
+ this.callKit.logger.warn("socket onMessage error during call, ignore", {
20468
+ caller: "Socket.onMessage",
20469
+ type: "INCALL",
20470
+ content: {
20471
+ errCode: ErrorCode.SOCKET_CONNECT_ERROR,
20472
+ isCalling: this.callKit.connect.isCalling(),
20473
+ data: content
20474
+ }
20475
+ });
20476
+ return;
20477
+ }
20149
20478
  this.setConnectAuthState("isError", true);
20150
20479
  this.callKit.reset();
20151
20480
  this.callKit.logger.error(data.msg, {
@@ -20154,20 +20483,24 @@ ${log}` : log;
20154
20483
  content: {
20155
20484
  errCode: ErrorCode.SOKET_SERVER_ERROR,
20156
20485
  data: content,
20157
- callUuid
20486
+ callUuid,
20487
+ delayReset: this.callKit.connect.isCalling()
20158
20488
  }
20159
20489
  });
20160
20490
  }
20161
20491
  if (data.event === SocketReceiveEvent.SESSION_ERROR) {
20162
20492
  this.setConnectAuthState("isError", true);
20163
- this.callKit.reset();
20493
+ if (!this.callKit.connect.isCalling()) {
20494
+ this.callKit.reset();
20495
+ }
20164
20496
  this.callKit.logger.error(data.msg, {
20165
20497
  caller: `Socket.onMessage:${data.event}`,
20166
20498
  type: "INCALL",
20167
20499
  content: {
20168
20500
  data: content,
20169
20501
  event: SocketReceiveEvent.SESSION_ERROR,
20170
- callUuid
20502
+ callUuid,
20503
+ delayReset: this.callKit.connect.isCalling()
20171
20504
  }
20172
20505
  });
20173
20506
  }
@@ -20199,6 +20532,18 @@ ${log}` : log;
20199
20532
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
20200
20533
  event: "INCALL_NOT_CONNECTED"
20201
20534
  });
20535
+ if (this.callKit.connect.isCalling()) {
20536
+ this.callKit.logger.warn("socket send during call, ignore", {
20537
+ caller: "Socket.onMessage",
20538
+ type: "INCALL",
20539
+ content: {
20540
+ errCode: ErrorCode.SOCKET_CONNECT_ERROR,
20541
+ isCalling: this.callKit.connect.isCalling(),
20542
+ data: message
20543
+ }
20544
+ });
20545
+ return;
20546
+ }
20202
20547
  this.callKit.reset();
20203
20548
  this.callKit.logger.error("socket not connected", {
20204
20549
  caller: "Socket.send",
@@ -20251,8 +20596,8 @@ ${log}` : log;
20251
20596
  return;
20252
20597
  this.send(SocketSendEvent.PING);
20253
20598
  const now = Date.now();
20254
- const { pingInterval, pingTimeout } = this.reconnectConfig;
20255
- if (now - this.lastPingTime > pingInterval + pingTimeout) {
20599
+ const { pingTimeout } = this.reconnectConfig;
20600
+ if (now - this.lastPingTime > this.pingInterval + pingTimeout) {
20256
20601
  this.callKit.logger.warn("Ping timeout not connected", {
20257
20602
  caller: "Socket.ping",
20258
20603
  type: "INCALL",
@@ -20264,26 +20609,48 @@ ${log}` : log;
20264
20609
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
20265
20610
  event: "INCALL_PING_TIMEOUT"
20266
20611
  });
20612
+ if (this.isUserSetPingTryCount) {
20613
+ this.handlePingTimeout();
20614
+ }
20267
20615
  }
20268
20616
  }
20617
+ handlePingTimeout() {
20618
+ const { userInfo } = this.callKit.config.getConfig();
20619
+ const { pingTryCount, pingTryCountInterval } = userInfo;
20620
+ this.callKit.logger.warn("Ping timeout, user set ping try count", {
20621
+ caller: "Socket.handlePingTimeout",
20622
+ type: "INCALL",
20623
+ content: {
20624
+ errCode: ErrorCode.SOCKET_PING_TIMEOUT,
20625
+ isUserSetPingTryCount: this.isUserSetPingTryCount,
20626
+ pingTryCount,
20627
+ pingTryCountInterval
20628
+ }
20629
+ });
20630
+ this.attemptReconnect();
20631
+ }
20269
20632
  checkPing() {
20270
- if (this.pingTimer) {
20271
- clearInterval(this.pingTimer);
20272
- }
20273
- const { pingInterval } = this.reconnectConfig;
20274
- this.pingTimer = setInterval(() => {
20633
+ this.heartbeatManager.start(this.pingInterval, () => {
20275
20634
  this.ping();
20276
- }, pingInterval);
20635
+ });
20636
+ this.callKit.logger.info(
20637
+ `Heartbeat started with Worker: ${this.heartbeatManager.isUsingWorker()}`,
20638
+ {
20639
+ caller: "Socket.checkPing",
20640
+ type: "INCALL",
20641
+ content: {
20642
+ pingInterval: this.pingInterval,
20643
+ usingWorker: this.heartbeatManager.isUsingWorker()
20644
+ }
20645
+ }
20646
+ );
20277
20647
  }
20278
20648
  /**
20279
20649
  * reset socket connection and all states
20280
20650
  */
20281
20651
  async reset(config) {
20282
20652
  const { force = false } = config || {};
20283
- if (this.pingTimer) {
20284
- clearInterval(this.pingTimer);
20285
- this.pingTimer = void 0;
20286
- }
20653
+ this.heartbeatManager.stop();
20287
20654
  if (force) {
20288
20655
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
20289
20656
  event: "INCALL_RESET"
@@ -20294,6 +20661,12 @@ ${log}` : log;
20294
20661
  this.setConnectAuthState("startConfirm", false);
20295
20662
  this.clearWebSocket();
20296
20663
  }
20664
+ /**
20665
+ * Destroy the heartbeat manager
20666
+ */
20667
+ destroyHeartbeat() {
20668
+ this.heartbeatManager.destroy();
20669
+ }
20297
20670
  attemptReconnect() {
20298
20671
  if (this.reconnectTimer) {
20299
20672
  clearTimeout(this.reconnectTimer);
@@ -20301,19 +20674,40 @@ ${log}` : log;
20301
20674
  }
20302
20675
  const { maxAttempts } = this.reconnectConfig;
20303
20676
  if (this.reconnectAttempts >= maxAttempts) {
20677
+ if (this.callKit.connect.isCalling()) {
20678
+ this.callKit.logger.warn("reconnect during call, ignore", {
20679
+ caller: "Socket.attemptReconnect",
20680
+ type: "INCALL",
20681
+ content: {
20682
+ errCode: ErrorCode.SOCKET_RECONNECT_FAILED,
20683
+ isCalling: this.callKit.connect.isCalling(),
20684
+ reconnectAttempts: this.reconnectAttempts
20685
+ }
20686
+ });
20687
+ return;
20688
+ }
20689
+ if (this.isUserSetPingTryCount) {
20690
+ this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
20691
+ event: "INCALL_PING_TIMEOUT_RECONNECT_FAILED_MAX_ATTEMPTS"
20692
+ });
20693
+ }
20304
20694
  this.callKit.trigger(KitEvent.INCALL_CONNECT_EVENT, {
20305
20695
  event: "INCALL_RECONNECT_ERROR"
20306
20696
  });
20307
20697
  this.setConnectAuthState("isError", true);
20308
20698
  this.callKit.reset();
20309
- this.callKit.logger.error("Maximum reconnection attempts reached", {
20310
- caller: "Socket.attemptReconnect",
20311
- type: "INCALL",
20312
- content: {
20313
- errCode: ErrorCode.SOCKET_RECONNECT_FAILED,
20314
- reconnectAttempts: this.reconnectAttempts
20699
+ this.callKit.logger.warn(
20700
+ "Maximum reconnection attempts reached, trigger reset",
20701
+ {
20702
+ caller: "Socket.attemptReconnect",
20703
+ type: "INCALL",
20704
+ content: {
20705
+ errCode: ErrorCode.SOCKET_RECONNECT_FAILED,
20706
+ reconnectAttempts: this.reconnectAttempts,
20707
+ delayReset: this.callKit.connect.isCalling()
20708
+ }
20315
20709
  }
20316
- });
20710
+ );
20317
20711
  return;
20318
20712
  }
20319
20713
  if (this.reconnectAttempts === 0) {
@@ -20419,6 +20813,7 @@ ${log}` : log;
20419
20813
  content: {
20420
20814
  username,
20421
20815
  password,
20816
+ ua: navigator.userAgent,
20422
20817
  encryptionMethod,
20423
20818
  encryptionPassword
20424
20819
  }
@@ -20438,6 +20833,7 @@ ${log}` : log;
20438
20833
  });
20439
20834
  if (user) {
20440
20835
  this.config.setConfig("userInfo", {
20836
+ ...user,
20441
20837
  wsUrl: `wss://${user.wsUrl}`,
20442
20838
  sessionId: user.sessionId,
20443
20839
  username,
@@ -20452,6 +20848,9 @@ ${log}` : log;
20452
20848
  iceInfo: user.iceInfo,
20453
20849
  iceGatheringTimeout: user.iceGatheringTimeout,
20454
20850
  logGather: user.logGather,
20851
+ keepaliveInterval: user.keepaliveInterval,
20852
+ pingTryCount: user?.pingTryCount,
20853
+ pingTryCountInterval: user?.pingTryCountInterval,
20455
20854
  phoneType: user.phoneType,
20456
20855
  // encryptionType is in extra
20457
20856
  ...extra
@@ -20728,4 +21127,3 @@ ${log}` : log;
20728
21127
  };
20729
21128
  return __toCommonJS(core_exports);
20730
21129
  })();
20731
- //# sourceMappingURL=index.global.js.map