@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 +157 -9
- package/dist/index.mjs +157 -9
- package/dist/types/__tests__/web-rtc-client-multi-client.test.d.ts +2 -0
- package/dist/types/__tests__/web-rtc-client-multi-client.test.d.ts.map +1 -0
- package/dist/types/domain/CallSession.d.ts +4 -2
- package/dist/types/domain/CallSession.d.ts.map +1 -1
- package/dist/types/domain/Phone/WebRTCPhone.d.ts +3 -0
- package/dist/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
- package/dist/types/domain/types.d.ts +5 -0
- package/dist/types/domain/types.d.ts.map +1 -1
- package/dist/types/simple/Phone.d.ts +4 -1
- package/dist/types/simple/Phone.d.ts.map +1 -1
- package/dist/types/simple/__tests__/Phone.test.d.ts +2 -0
- package/dist/types/simple/__tests__/Phone.test.d.ts.map +1 -0
- package/dist/types/simple/room/Room.d.ts +2 -1
- package/dist/types/simple/room/Room.d.ts.map +1 -1
- package/dist/types/web-rtc-client.d.ts +10 -1
- package/dist/types/web-rtc-client.d.ts.map +1 -1
- package/dist/wazo-sdk.js +157 -9
- package/package.json +1 -1
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
|
|
5460
|
-
web_rtc_client_logger.info('sdk webrtc registering aborted,
|
|
5461
|
-
return
|
|
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
|
|
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
|
|
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
|
|
5374
|
-
web_rtc_client_logger.info('sdk webrtc registering aborted,
|
|
5375
|
-
return
|
|
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
|
|
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
|
|
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 @@
|
|
|
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":"AACA,OAAO,IAAI,EAAE,EAAmB,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAGxE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"CallSession.d.ts","sourceRoot":"","sources":["../../../src/domain/CallSession.ts"],"names":[],"mappings":"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"}
|