@wazo/sdk 0.48.2 → 0.49.0

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
@@ -1743,6 +1743,7 @@ class CallSession {
1743
1743
  answeredBySystem;
1744
1744
  dialedExtension;
1745
1745
  diversion;
1746
+ assertedIdentity;
1746
1747
  ringing;
1747
1748
  paused;
1748
1749
  sipCallId;
@@ -1760,7 +1761,7 @@ class CallSession {
1760
1761
  recordingState;
1761
1762
  sipSession;
1762
1763
  conference;
1763
- constructor({ answered, answeredBySystem, isCaller, displayName, callId, muted, videoMuted, number, paused, ringing, startTime, creationTime, endTime, cameraEnabled, dialedExtension, diversion, sipCallId, sipStatus, callerNumber, call, autoAnswer, ignored, screensharing, recording, recordingPaused, recordingState, videoRemotelyDowngraded, sipSession, answerTime, conference }){
1764
+ constructor({ answered, answeredBySystem, isCaller, displayName, callId, muted, videoMuted, number, paused, ringing, startTime, creationTime, endTime, cameraEnabled, dialedExtension, diversion, assertedIdentity, sipCallId, sipStatus, callerNumber, call, autoAnswer, ignored, screensharing, recording, recordingPaused, recordingState, videoRemotelyDowngraded, sipSession, answerTime, conference }){
1764
1765
  this.callId = callId;
1765
1766
  this.sipCallId = sipCallId;
1766
1767
  this.displayName = displayName;
@@ -1779,6 +1780,7 @@ class CallSession {
1779
1780
  this.cameraEnabled = cameraEnabled;
1780
1781
  this.dialedExtension = dialedExtension || '';
1781
1782
  this.diversion = diversion;
1783
+ this.assertedIdentity = assertedIdentity || void 0;
1782
1784
  this.call = call;
1783
1785
  this.sipStatus = sipStatus;
1784
1786
  this.autoAnswer = autoAnswer || false;
@@ -5228,10 +5230,24 @@ const transportEvents = [
5228
5230
  ];
5229
5231
  class CanceledCallError extends Error {
5230
5232
  }
5233
+ const toAssertedIdentity = (identity)=>{
5234
+ if (!identity) return null;
5235
+ const number = identity.uri?.user || void 0;
5236
+ const displayName = identity.displayName || number;
5237
+ if (!displayName) return null;
5238
+ return {
5239
+ displayName,
5240
+ number
5241
+ };
5242
+ };
5231
5243
  const MAX_REGISTER_TRIES = 5;
5232
5244
  const NO_ANSWER_TIMEOUT = 86400;
5245
+ let liveClientCount = 0;
5233
5246
  class WebRTCClient extends Emitter {
5234
5247
  clientId;
5248
+ _countedAsLive;
5249
+ _closed;
5250
+ lastTransportMessageAt;
5235
5251
  config;
5236
5252
  uaConfigOverrides;
5237
5253
  userAgent;
@@ -5302,11 +5318,32 @@ class WebRTCClient extends Emitter {
5302
5318
  web_rtc_client_logger.info('sdk webrtc constructor', {
5303
5319
  clientId: this.clientId
5304
5320
  });
5321
+ liveClientCount += 1;
5322
+ this._countedAsLive = true;
5323
+ this._closed = false;
5324
+ this.lastTransportMessageAt = null;
5325
+ if (liveClientCount > 1) web_rtc_client_logger.info('sdk webrtc multiple clients alive', {
5326
+ liveClientCount,
5327
+ clientId: this.clientId
5328
+ });
5305
5329
  this.uaConfigOverrides = uaConfigOverrides;
5306
5330
  this.config = config;
5307
5331
  this.skipRegister = config.skipRegister;
5308
5332
  this._buildConfig(config, session).then((newConfig)=>{
5309
5333
  this.config = newConfig;
5334
+ if (this._closed) {
5335
+ web_rtc_client_logger.info('sdk webrtc constructor, client closed during config build, skipping UA creation', {
5336
+ clientId: this.clientId
5337
+ });
5338
+ return;
5339
+ }
5340
+ if (this.userAgent && !session) {
5341
+ web_rtc_client_logger.info('sdk webrtc constructor, userAgent already created, skipping', {
5342
+ clientId: this.clientId
5343
+ });
5344
+ return;
5345
+ }
5346
+ if (this.registerer) this._cleanupRegister();
5310
5347
  this.userAgent = this.createUserAgent(uaConfigOverrides);
5311
5348
  });
5312
5349
  this.audioOutputDeviceId = config.audioDeviceOutput;
@@ -5365,6 +5402,19 @@ class WebRTCClient extends Emitter {
5365
5402
  this.audio = media.audio;
5366
5403
  }
5367
5404
  createUserAgent(uaConfigOverrides) {
5405
+ this.lastTransportMessageAt = null;
5406
+ if (this.userAgent) {
5407
+ web_rtc_client_logger.warn('sdk webrtc, stopping existing UA before creating a new one', {
5408
+ clientId: this.clientId
5409
+ });
5410
+ this.userAgent.stop().catch((error)=>{
5411
+ web_rtc_client_logger.error('sdk webrtc, error stopping previous UA', {
5412
+ error: error?.message,
5413
+ clientId: this.clientId
5414
+ });
5415
+ });
5416
+ this.userAgent = null;
5417
+ }
5368
5418
  const uaOptions = this._createUaOptions(uaConfigOverrides);
5369
5419
  web_rtc_client_logger.info('sdk webrtc, creating UA', {
5370
5420
  uaOptions: {
@@ -5394,6 +5444,7 @@ class WebRTCClient extends Emitter {
5394
5444
  web_rtc_client_logger.warn('Transport connect error', e);
5395
5445
  });
5396
5446
  ua.transport.onMessage = (rawMessage)=>{
5447
+ this.lastTransportMessageAt = Date.now();
5397
5448
  const message = parser_namespaceObject.Parser.parseMessage(rawMessage, ua.transport.logger);
5398
5449
  ua.onTransportMessage(rawMessage);
5399
5450
  this.eventEmitter.emit(MESSAGE, message);
@@ -5412,6 +5463,16 @@ class WebRTCClient extends Emitter {
5412
5463
  isRegistered() {
5413
5464
  return Boolean(this.registerer && this.registerer.state === registerer_state_namespaceObject.RegistererState.Registered);
5414
5465
  }
5466
+ getLastTransportMessageAt() {
5467
+ return this.lastTransportMessageAt;
5468
+ }
5469
+ isTransportSuspect() {
5470
+ if (!this.isConnected()) return true;
5471
+ if (Object.keys(this.sipSessions).length > 0) return false;
5472
+ const threshold = this.config.transportSilenceThresholdMs;
5473
+ if (!threshold || !this.lastTransportMessageAt) return false;
5474
+ return Date.now() - this.lastTransportMessageAt > threshold;
5475
+ }
5415
5476
  onConnect() {
5416
5477
  web_rtc_client_logger.info('sdk webrtc connected', {
5417
5478
  method: 'delegate.onConnect',
@@ -5435,6 +5496,23 @@ class WebRTCClient extends Emitter {
5435
5496
  this.eventEmitter.emit(UNREGISTERED);
5436
5497
  }
5437
5498
  }
5499
+ async _isRegistrationHealthy() {
5500
+ if (!this.isTransportSuspect()) return true;
5501
+ web_rtc_client_logger.warn('sdk webrtc registered but transport suspect, re-registering', {
5502
+ clientId: this.clientId,
5503
+ connected: this.isConnected(),
5504
+ lastTransportMessageAt: this.lastTransportMessageAt
5505
+ });
5506
+ this._cleanupRegister();
5507
+ if (this.isConnected()) {
5508
+ this.connectionPromise = this._disconnectTransport(true);
5509
+ await this.connectionPromise;
5510
+ this.connectionPromise = null;
5511
+ const transport = this.userAgent?.transport;
5512
+ if (transport && transport.state !== transport_state_namespaceObject.TransportState.Disconnected) transport.transitionState(transport_state_namespaceObject.TransportState.Disconnected);
5513
+ }
5514
+ return false;
5515
+ }
5438
5516
  async register(tries = 0) {
5439
5517
  const logInfo = {
5440
5518
  clientId: this.clientId,
@@ -5447,6 +5525,11 @@ class WebRTCClient extends Emitter {
5447
5525
  skipRegister: this.skipRegister
5448
5526
  };
5449
5527
  this.forceClosed = false;
5528
+ this._closed = false;
5529
+ if (!this._countedAsLive) {
5530
+ this._countedAsLive = true;
5531
+ liveClientCount += 1;
5532
+ }
5450
5533
  if (this.skipRegister) {
5451
5534
  web_rtc_client_logger.info('sdk webrtc skip register...', logInfo);
5452
5535
  return Promise.resolve();
@@ -5456,15 +5539,19 @@ class WebRTCClient extends Emitter {
5456
5539
  web_rtc_client_logger.info('sdk webrtc recreating User Agent');
5457
5540
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
5458
5541
  }
5459
- if (!this.userAgent || this.isRegistered()) {
5460
- web_rtc_client_logger.info('sdk webrtc registering aborted, already registered or no UA can be created');
5461
- return Promise.resolve();
5542
+ if (!this.userAgent) {
5543
+ web_rtc_client_logger.info('sdk webrtc registering aborted, no UA can be created');
5544
+ return;
5545
+ }
5546
+ if (this.isRegistered() && await this._isRegistrationHealthy()) {
5547
+ web_rtc_client_logger.info('sdk webrtc registering aborted, already registered');
5548
+ return;
5462
5549
  }
5463
5550
  if (this.connectionPromise || this.registerer?.waiting) {
5464
5551
  web_rtc_client_logger.info('sdk webrtc registering aborted due to a registration in progress.', {
5465
5552
  clientId: this.clientId
5466
5553
  });
5467
- return Promise.resolve();
5554
+ return;
5468
5555
  }
5469
5556
  const registerOptions = this._isWeb() ? {} : {
5470
5557
  extraContactHeaderParams: [
@@ -5565,7 +5652,6 @@ class WebRTCClient extends Emitter {
5565
5652
  web_rtc_client_logger.info('sdk webrtc unregistered', {
5566
5653
  clientId: this.clientId
5567
5654
  });
5568
- if (this.registerer) this.registerer.stateChange.addListener(onRegisterStateChange);
5569
5655
  this._cleanupRegister();
5570
5656
  resolve();
5571
5657
  }
@@ -5759,6 +5845,11 @@ class WebRTCClient extends Emitter {
5759
5845
  force
5760
5846
  });
5761
5847
  this.forceClosed = force;
5848
+ this._closed = true;
5849
+ if (this._countedAsLive) {
5850
+ this._countedAsLive = false;
5851
+ liveClientCount = Math.max(0, liveClientCount - 1);
5852
+ }
5762
5853
  this._cleanupMedia();
5763
5854
  this.connectionPromise = null;
5764
5855
  Object.values(this.audioElements).forEach((audioElement)=>{
@@ -8647,6 +8738,15 @@ class WebRTCPhone extends Emitter {
8647
8738
  isRegistered() {
8648
8739
  return this.client && this.client.isRegistered();
8649
8740
  }
8741
+ isConnected() {
8742
+ return Boolean(this.client?.isConnected());
8743
+ }
8744
+ isTransportSuspect() {
8745
+ return !this.client || this.client.isTransportSuspect();
8746
+ }
8747
+ getLastTransportMessageAt() {
8748
+ return this.client?.getLastTransportMessageAt() ?? null;
8749
+ }
8650
8750
  enableRinging() {
8651
8751
  WebRTCPhone_logger.info('WebRTC enable ringing');
8652
8752
  this.ringingEnabled = true;
@@ -8966,8 +9066,9 @@ class WebRTCPhone extends Emitter {
8966
9066
  const { state } = sipSession || {};
8967
9067
  const sessionId = this.getSipSessionId(sipSession);
8968
9068
  fromSession = fromSession || this.callSessions[sessionId];
9069
+ const headerCallId = sipSession?.request?.getHeader?.('X-Wazo-Call-ID');
8969
9070
  const callSession = new CallSession({
8970
- callId: fromSession && fromSession.callId,
9071
+ callId: fromSession?.callId || headerCallId || '',
8971
9072
  sipCallId: sessionId,
8972
9073
  sipStatus: state,
8973
9074
  displayName: identity ? identity.displayName || number : number,
@@ -8988,6 +9089,7 @@ class WebRTCPhone extends Emitter {
8988
9089
  recordingState: fromSession ? fromSession.recordingState : RECORDING_STATE.INACTIVE,
8989
9090
  sipSession,
8990
9091
  diversion: sipSession?.diversion,
9092
+ assertedIdentity: toAssertedIdentity(sipSession?.assertedIdentity) || void 0,
8991
9093
  conference: !!fromSession && fromSession.isConference(),
8992
9094
  ...extra
8993
9095
  });
@@ -9601,6 +9703,7 @@ const protocolDebugMessages = [
9601
9703
  class Phone_Phone extends Emitter {
9602
9704
  client;
9603
9705
  phone;
9706
+ connectInFlight;
9604
9707
  session;
9605
9708
  sipLine;
9606
9709
  SessionState;
@@ -9670,10 +9773,37 @@ class Phone_Phone extends Emitter {
9670
9773
  this.sipLine = sipLine || this.getPrimaryWebRtcLine();
9671
9774
  if (!this.sipLine) throw new Error('Sorry, no sip lines found for this user');
9672
9775
  options.userUuid = session.uuid || '';
9673
- this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
9776
+ return this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
9674
9777
  }
9675
- connectWithCredentials(server, sipLine, displayName, rawOptions = {}) {
9778
+ async connectWithCredentials(server, sipLine, displayName, rawOptions = {}) {
9676
9779
  if (this.phone) return;
9780
+ if (this.connectInFlight) {
9781
+ Phone_logger.info('connectWithCredentials: connection already in progress, reusing it and ignoring this call\'s arguments', {
9782
+ server,
9783
+ sipLineId: sipLine?.id
9784
+ });
9785
+ return this.connectInFlight;
9786
+ }
9787
+ this.connectInFlight = this._connectWithCredentials(server, sipLine, displayName, rawOptions).finally(()=>{
9788
+ this.connectInFlight = null;
9789
+ });
9790
+ return this.connectInFlight;
9791
+ }
9792
+ async _connectWithCredentials(server, sipLine, displayName, rawOptions = {}) {
9793
+ if (this.client) {
9794
+ Phone_logger.warn('connectWithCredentials: closing previous client before creating a new one');
9795
+ try {
9796
+ await this.client.close();
9797
+ } catch (error) {
9798
+ Phone_logger.error('connectWithCredentials: error while closing previous client', {
9799
+ message: error?.message
9800
+ });
9801
+ }
9802
+ if (this.phone) {
9803
+ Phone_logger.info('connectWithCredentials: phone connected while closing previous client, keeping it');
9804
+ return;
9805
+ }
9806
+ }
9677
9807
  const [host, port = 443] = server.split(':');
9678
9808
  const options = rawOptions;
9679
9809
  options.media = options.media || {
@@ -9710,6 +9840,24 @@ class Phone_Phone extends Emitter {
9710
9840
  }
9711
9841
  this.phone = null;
9712
9842
  }
9843
+ async reset() {
9844
+ Phone_logger.info('phone reset', {
9845
+ phone: !!this.phone,
9846
+ client: !!this.client
9847
+ });
9848
+ await this.disconnect().catch((error)=>{
9849
+ Phone_logger.error('reset: error while disconnecting phone', {
9850
+ message: error?.message
9851
+ });
9852
+ });
9853
+ if (this.client) await this.client.close().catch((error)=>{
9854
+ Phone_logger.error('reset: error while closing client', {
9855
+ message: error?.message
9856
+ });
9857
+ });
9858
+ this.phone = null;
9859
+ this.client = null;
9860
+ }
9713
9861
  async call(extension, withCamera = false, rawSipLine = null, audioOnly = false, conference = false) {
9714
9862
  if (!this.phone) return;
9715
9863
  const sipLine = rawSipLine || this.getPrimaryWebRtcLine();
package/dist/index.mjs CHANGED
@@ -1681,6 +1681,7 @@ class CallSession {
1681
1681
  answeredBySystem;
1682
1682
  dialedExtension;
1683
1683
  diversion;
1684
+ assertedIdentity;
1684
1685
  ringing;
1685
1686
  paused;
1686
1687
  sipCallId;
@@ -1698,7 +1699,7 @@ class CallSession {
1698
1699
  recordingState;
1699
1700
  sipSession;
1700
1701
  conference;
1701
- constructor({ answered, answeredBySystem, isCaller, displayName, callId, muted, videoMuted, number, paused, ringing, startTime, creationTime, endTime, cameraEnabled, dialedExtension, diversion, sipCallId, sipStatus, callerNumber, call, autoAnswer, ignored, screensharing, recording, recordingPaused, recordingState, videoRemotelyDowngraded, sipSession, answerTime, conference }){
1702
+ constructor({ answered, answeredBySystem, isCaller, displayName, callId, muted, videoMuted, number, paused, ringing, startTime, creationTime, endTime, cameraEnabled, dialedExtension, diversion, assertedIdentity, sipCallId, sipStatus, callerNumber, call, autoAnswer, ignored, screensharing, recording, recordingPaused, recordingState, videoRemotelyDowngraded, sipSession, answerTime, conference }){
1702
1703
  this.callId = callId;
1703
1704
  this.sipCallId = sipCallId;
1704
1705
  this.displayName = displayName;
@@ -1717,6 +1718,7 @@ class CallSession {
1717
1718
  this.cameraEnabled = cameraEnabled;
1718
1719
  this.dialedExtension = dialedExtension || '';
1719
1720
  this.diversion = diversion;
1721
+ this.assertedIdentity = assertedIdentity || void 0;
1720
1722
  this.call = call;
1721
1723
  this.sipStatus = sipStatus;
1722
1724
  this.autoAnswer = autoAnswer || false;
@@ -5142,10 +5144,24 @@ const transportEvents = [
5142
5144
  ];
5143
5145
  class CanceledCallError extends Error {
5144
5146
  }
5147
+ const toAssertedIdentity = (identity)=>{
5148
+ if (!identity) return null;
5149
+ const number = identity.uri?.user || void 0;
5150
+ const displayName = identity.displayName || number;
5151
+ if (!displayName) return null;
5152
+ return {
5153
+ displayName,
5154
+ number
5155
+ };
5156
+ };
5145
5157
  const MAX_REGISTER_TRIES = 5;
5146
5158
  const NO_ANSWER_TIMEOUT = 86400;
5159
+ let liveClientCount = 0;
5147
5160
  class WebRTCClient extends Emitter {
5148
5161
  clientId;
5162
+ _countedAsLive;
5163
+ _closed;
5164
+ lastTransportMessageAt;
5149
5165
  config;
5150
5166
  uaConfigOverrides;
5151
5167
  userAgent;
@@ -5216,11 +5232,32 @@ class WebRTCClient extends Emitter {
5216
5232
  web_rtc_client_logger.info('sdk webrtc constructor', {
5217
5233
  clientId: this.clientId
5218
5234
  });
5235
+ liveClientCount += 1;
5236
+ this._countedAsLive = true;
5237
+ this._closed = false;
5238
+ this.lastTransportMessageAt = null;
5239
+ if (liveClientCount > 1) web_rtc_client_logger.info('sdk webrtc multiple clients alive', {
5240
+ liveClientCount,
5241
+ clientId: this.clientId
5242
+ });
5219
5243
  this.uaConfigOverrides = uaConfigOverrides;
5220
5244
  this.config = config;
5221
5245
  this.skipRegister = config.skipRegister;
5222
5246
  this._buildConfig(config, session).then((newConfig)=>{
5223
5247
  this.config = newConfig;
5248
+ if (this._closed) {
5249
+ web_rtc_client_logger.info('sdk webrtc constructor, client closed during config build, skipping UA creation', {
5250
+ clientId: this.clientId
5251
+ });
5252
+ return;
5253
+ }
5254
+ if (this.userAgent && !session) {
5255
+ web_rtc_client_logger.info('sdk webrtc constructor, userAgent already created, skipping', {
5256
+ clientId: this.clientId
5257
+ });
5258
+ return;
5259
+ }
5260
+ if (this.registerer) this._cleanupRegister();
5224
5261
  this.userAgent = this.createUserAgent(uaConfigOverrides);
5225
5262
  });
5226
5263
  this.audioOutputDeviceId = config.audioDeviceOutput;
@@ -5279,6 +5316,19 @@ class WebRTCClient extends Emitter {
5279
5316
  this.audio = media.audio;
5280
5317
  }
5281
5318
  createUserAgent(uaConfigOverrides) {
5319
+ this.lastTransportMessageAt = null;
5320
+ if (this.userAgent) {
5321
+ web_rtc_client_logger.warn('sdk webrtc, stopping existing UA before creating a new one', {
5322
+ clientId: this.clientId
5323
+ });
5324
+ this.userAgent.stop().catch((error)=>{
5325
+ web_rtc_client_logger.error('sdk webrtc, error stopping previous UA', {
5326
+ error: error?.message,
5327
+ clientId: this.clientId
5328
+ });
5329
+ });
5330
+ this.userAgent = null;
5331
+ }
5282
5332
  const uaOptions = this._createUaOptions(uaConfigOverrides);
5283
5333
  web_rtc_client_logger.info('sdk webrtc, creating UA', {
5284
5334
  uaOptions: {
@@ -5308,6 +5358,7 @@ class WebRTCClient extends Emitter {
5308
5358
  web_rtc_client_logger.warn('Transport connect error', e);
5309
5359
  });
5310
5360
  ua.transport.onMessage = (rawMessage)=>{
5361
+ this.lastTransportMessageAt = Date.now();
5311
5362
  const message = __WEBPACK_EXTERNAL_MODULE_sip_js_lib_core_messages_parser_9974076a__.Parser.parseMessage(rawMessage, ua.transport.logger);
5312
5363
  ua.onTransportMessage(rawMessage);
5313
5364
  this.eventEmitter.emit(MESSAGE, message);
@@ -5326,6 +5377,16 @@ class WebRTCClient extends Emitter {
5326
5377
  isRegistered() {
5327
5378
  return Boolean(this.registerer && this.registerer.state === __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_registerer_state_6e58ddd6__.RegistererState.Registered);
5328
5379
  }
5380
+ getLastTransportMessageAt() {
5381
+ return this.lastTransportMessageAt;
5382
+ }
5383
+ isTransportSuspect() {
5384
+ if (!this.isConnected()) return true;
5385
+ if (Object.keys(this.sipSessions).length > 0) return false;
5386
+ const threshold = this.config.transportSilenceThresholdMs;
5387
+ if (!threshold || !this.lastTransportMessageAt) return false;
5388
+ return Date.now() - this.lastTransportMessageAt > threshold;
5389
+ }
5329
5390
  onConnect() {
5330
5391
  web_rtc_client_logger.info('sdk webrtc connected', {
5331
5392
  method: 'delegate.onConnect',
@@ -5349,6 +5410,23 @@ class WebRTCClient extends Emitter {
5349
5410
  this.eventEmitter.emit(UNREGISTERED);
5350
5411
  }
5351
5412
  }
5413
+ async _isRegistrationHealthy() {
5414
+ if (!this.isTransportSuspect()) return true;
5415
+ web_rtc_client_logger.warn('sdk webrtc registered but transport suspect, re-registering', {
5416
+ clientId: this.clientId,
5417
+ connected: this.isConnected(),
5418
+ lastTransportMessageAt: this.lastTransportMessageAt
5419
+ });
5420
+ this._cleanupRegister();
5421
+ if (this.isConnected()) {
5422
+ this.connectionPromise = this._disconnectTransport(true);
5423
+ await this.connectionPromise;
5424
+ this.connectionPromise = null;
5425
+ const transport = this.userAgent?.transport;
5426
+ if (transport && transport.state !== __WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_transport_state_2606bc5d__.TransportState.Disconnected) transport.transitionState(__WEBPACK_EXTERNAL_MODULE_sip_js_lib_api_transport_state_2606bc5d__.TransportState.Disconnected);
5427
+ }
5428
+ return false;
5429
+ }
5352
5430
  async register(tries = 0) {
5353
5431
  const logInfo = {
5354
5432
  clientId: this.clientId,
@@ -5361,6 +5439,11 @@ class WebRTCClient extends Emitter {
5361
5439
  skipRegister: this.skipRegister
5362
5440
  };
5363
5441
  this.forceClosed = false;
5442
+ this._closed = false;
5443
+ if (!this._countedAsLive) {
5444
+ this._countedAsLive = true;
5445
+ liveClientCount += 1;
5446
+ }
5364
5447
  if (this.skipRegister) {
5365
5448
  web_rtc_client_logger.info('sdk webrtc skip register...', logInfo);
5366
5449
  return Promise.resolve();
@@ -5370,15 +5453,19 @@ class WebRTCClient extends Emitter {
5370
5453
  web_rtc_client_logger.info('sdk webrtc recreating User Agent');
5371
5454
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
5372
5455
  }
5373
- if (!this.userAgent || this.isRegistered()) {
5374
- web_rtc_client_logger.info('sdk webrtc registering aborted, already registered or no UA can be created');
5375
- return Promise.resolve();
5456
+ if (!this.userAgent) {
5457
+ web_rtc_client_logger.info('sdk webrtc registering aborted, no UA can be created');
5458
+ return;
5459
+ }
5460
+ if (this.isRegistered() && await this._isRegistrationHealthy()) {
5461
+ web_rtc_client_logger.info('sdk webrtc registering aborted, already registered');
5462
+ return;
5376
5463
  }
5377
5464
  if (this.connectionPromise || this.registerer?.waiting) {
5378
5465
  web_rtc_client_logger.info('sdk webrtc registering aborted due to a registration in progress.', {
5379
5466
  clientId: this.clientId
5380
5467
  });
5381
- return Promise.resolve();
5468
+ return;
5382
5469
  }
5383
5470
  const registerOptions = this._isWeb() ? {} : {
5384
5471
  extraContactHeaderParams: [
@@ -5479,7 +5566,6 @@ class WebRTCClient extends Emitter {
5479
5566
  web_rtc_client_logger.info('sdk webrtc unregistered', {
5480
5567
  clientId: this.clientId
5481
5568
  });
5482
- if (this.registerer) this.registerer.stateChange.addListener(onRegisterStateChange);
5483
5569
  this._cleanupRegister();
5484
5570
  resolve();
5485
5571
  }
@@ -5673,6 +5759,11 @@ class WebRTCClient extends Emitter {
5673
5759
  force
5674
5760
  });
5675
5761
  this.forceClosed = force;
5762
+ this._closed = true;
5763
+ if (this._countedAsLive) {
5764
+ this._countedAsLive = false;
5765
+ liveClientCount = Math.max(0, liveClientCount - 1);
5766
+ }
5676
5767
  this._cleanupMedia();
5677
5768
  this.connectionPromise = null;
5678
5769
  Object.values(this.audioElements).forEach((audioElement)=>{
@@ -8561,6 +8652,15 @@ class WebRTCPhone extends Emitter {
8561
8652
  isRegistered() {
8562
8653
  return this.client && this.client.isRegistered();
8563
8654
  }
8655
+ isConnected() {
8656
+ return Boolean(this.client?.isConnected());
8657
+ }
8658
+ isTransportSuspect() {
8659
+ return !this.client || this.client.isTransportSuspect();
8660
+ }
8661
+ getLastTransportMessageAt() {
8662
+ return this.client?.getLastTransportMessageAt() ?? null;
8663
+ }
8564
8664
  enableRinging() {
8565
8665
  WebRTCPhone_logger.info('WebRTC enable ringing');
8566
8666
  this.ringingEnabled = true;
@@ -8880,8 +8980,9 @@ class WebRTCPhone extends Emitter {
8880
8980
  const { state } = sipSession || {};
8881
8981
  const sessionId = this.getSipSessionId(sipSession);
8882
8982
  fromSession = fromSession || this.callSessions[sessionId];
8983
+ const headerCallId = sipSession?.request?.getHeader?.('X-Wazo-Call-ID');
8883
8984
  const callSession = new CallSession({
8884
- callId: fromSession && fromSession.callId,
8985
+ callId: fromSession?.callId || headerCallId || '',
8885
8986
  sipCallId: sessionId,
8886
8987
  sipStatus: state,
8887
8988
  displayName: identity ? identity.displayName || number : number,
@@ -8902,6 +9003,7 @@ class WebRTCPhone extends Emitter {
8902
9003
  recordingState: fromSession ? fromSession.recordingState : RECORDING_STATE.INACTIVE,
8903
9004
  sipSession,
8904
9005
  diversion: sipSession?.diversion,
9006
+ assertedIdentity: toAssertedIdentity(sipSession?.assertedIdentity) || void 0,
8905
9007
  conference: !!fromSession && fromSession.isConference(),
8906
9008
  ...extra
8907
9009
  });
@@ -9515,6 +9617,7 @@ const protocolDebugMessages = [
9515
9617
  class Phone_Phone extends Emitter {
9516
9618
  client;
9517
9619
  phone;
9620
+ connectInFlight;
9518
9621
  session;
9519
9622
  sipLine;
9520
9623
  SessionState;
@@ -9584,10 +9687,37 @@ class Phone_Phone extends Emitter {
9584
9687
  this.sipLine = sipLine || this.getPrimaryWebRtcLine();
9585
9688
  if (!this.sipLine) throw new Error('Sorry, no sip lines found for this user');
9586
9689
  options.userUuid = session.uuid || '';
9587
- this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
9690
+ return this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
9588
9691
  }
9589
- connectWithCredentials(server, sipLine, displayName, rawOptions = {}) {
9692
+ async connectWithCredentials(server, sipLine, displayName, rawOptions = {}) {
9590
9693
  if (this.phone) return;
9694
+ if (this.connectInFlight) {
9695
+ Phone_logger.info('connectWithCredentials: connection already in progress, reusing it and ignoring this call\'s arguments', {
9696
+ server,
9697
+ sipLineId: sipLine?.id
9698
+ });
9699
+ return this.connectInFlight;
9700
+ }
9701
+ this.connectInFlight = this._connectWithCredentials(server, sipLine, displayName, rawOptions).finally(()=>{
9702
+ this.connectInFlight = null;
9703
+ });
9704
+ return this.connectInFlight;
9705
+ }
9706
+ async _connectWithCredentials(server, sipLine, displayName, rawOptions = {}) {
9707
+ if (this.client) {
9708
+ Phone_logger.warn('connectWithCredentials: closing previous client before creating a new one');
9709
+ try {
9710
+ await this.client.close();
9711
+ } catch (error) {
9712
+ Phone_logger.error('connectWithCredentials: error while closing previous client', {
9713
+ message: error?.message
9714
+ });
9715
+ }
9716
+ if (this.phone) {
9717
+ Phone_logger.info('connectWithCredentials: phone connected while closing previous client, keeping it');
9718
+ return;
9719
+ }
9720
+ }
9591
9721
  const [host, port = 443] = server.split(':');
9592
9722
  const options = rawOptions;
9593
9723
  options.media = options.media || {
@@ -9624,6 +9754,24 @@ class Phone_Phone extends Emitter {
9624
9754
  }
9625
9755
  this.phone = null;
9626
9756
  }
9757
+ async reset() {
9758
+ Phone_logger.info('phone reset', {
9759
+ phone: !!this.phone,
9760
+ client: !!this.client
9761
+ });
9762
+ await this.disconnect().catch((error)=>{
9763
+ Phone_logger.error('reset: error while disconnecting phone', {
9764
+ message: error?.message
9765
+ });
9766
+ });
9767
+ if (this.client) await this.client.close().catch((error)=>{
9768
+ Phone_logger.error('reset: error while closing client', {
9769
+ message: error?.message
9770
+ });
9771
+ });
9772
+ this.phone = null;
9773
+ this.client = null;
9774
+ }
9627
9775
  async call(extension, withCamera = false, rawSipLine = null, audioOnly = false, conference = false) {
9628
9776
  if (!this.phone) return;
9629
9777
  const sipLine = rawSipLine || this.getPrimaryWebRtcLine();
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=web-rtc-client-multi-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-rtc-client-multi-client.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/web-rtc-client-multi-client.test.ts"],"names":[],"mappings":""}
@@ -1,9 +1,10 @@
1
1
  import Call, { type RecordingStateType } from './Call';
2
- import { WazoSession } from './types';
2
+ import { WazoSession, AssertedIdentity } from './types';
3
3
  type CallSessionArguments = {
4
4
  answered: boolean;
5
5
  answerTime?: Date | null | undefined;
6
6
  answeredBySystem: boolean;
7
+ assertedIdentity?: AssertedIdentity;
7
8
  call: Call | null | undefined;
8
9
  callId: string;
9
10
  callerNumber: string;
@@ -49,6 +50,7 @@ export default class CallSession {
49
50
  answeredBySystem: boolean;
50
51
  dialedExtension: string;
51
52
  diversion?: string[];
53
+ assertedIdentity?: AssertedIdentity;
52
54
  ringing: boolean;
53
55
  paused: boolean;
54
56
  sipCallId: string;
@@ -66,7 +68,7 @@ export default class CallSession {
66
68
  recordingState: RecordingStateType;
67
69
  sipSession: WazoSession | undefined;
68
70
  conference: boolean;
69
- constructor({ answered, answeredBySystem, isCaller, displayName, callId, muted, videoMuted, number, paused, ringing, startTime, creationTime, endTime, cameraEnabled, dialedExtension, diversion, sipCallId, sipStatus, callerNumber, call, autoAnswer, ignored, screensharing, recording, recordingPaused, recordingState, videoRemotelyDowngraded, sipSession, answerTime, conference, }: CallSessionArguments);
71
+ constructor({ answered, answeredBySystem, isCaller, displayName, callId, muted, videoMuted, number, paused, ringing, startTime, creationTime, endTime, cameraEnabled, dialedExtension, diversion, assertedIdentity, sipCallId, sipStatus, callerNumber, call, autoAnswer, ignored, screensharing, recording, recordingPaused, recordingState, videoRemotelyDowngraded, sipSession, answerTime, conference, }: CallSessionArguments);
70
72
  resume(): void;
71
73
  hold(): void;
72
74
  mute(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"CallSession.d.ts","sourceRoot":"","sources":["../../../src/domain/CallSession.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CallSession.d.ts","sourceRoot":"","sources":["../../../src/domain/CallSession.ts"],"names":[],"mappings":"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"}