@wazo/sdk 0.37.28 → 0.37.32
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/README.md +2 -1
- package/dist/wazo-sdk.js +4 -4
- package/esm/__tests__/api-client.test.js +30 -0
- package/esm/__tests__/web-rtc-client.test.js +65 -6
- package/esm/api/calld.js +30 -0
- package/esm/api-client.js +30 -0
- package/esm/checker/Checker.js +65 -6
- package/esm/checker/checks/aor.js +30 -0
- package/esm/checker/checks/api.js +30 -0
- package/esm/checker/checks/index.js +65 -6
- package/esm/checker/checks/webrtc-transport.js +65 -6
- package/esm/checker/checks/webrtc.js +65 -6
- package/esm/domain/AdHocAPIConference.js +30 -0
- package/esm/domain/CallSession.js +15 -3
- package/esm/domain/Features.js +30 -0
- package/esm/domain/MeetingStatus.js +29 -0
- package/esm/domain/Phone/CTIPhone.js +45 -3
- package/esm/domain/Phone/WebRTCPhone.js +28 -6
- package/esm/domain/__tests__/CallSession.test.js +32 -3
- package/esm/domain/__tests__/IndirectTransfer.test.js +15 -3
- package/esm/domain/__tests__/Room.test.js +15 -3
- package/esm/index.js +93 -12
- package/esm/service/CallApi.js +30 -0
- package/esm/service/getApiClient.js +30 -0
- package/esm/simple/Auth.js +93 -12
- package/esm/simple/Configuration.js +93 -12
- package/esm/simple/Directory.js +30 -0
- package/esm/simple/Phone.js +93 -12
- package/esm/simple/index.js +93 -12
- package/esm/simple/room/LocalParticipant.js +93 -12
- package/esm/simple/room/Participant.js +93 -12
- package/esm/simple/room/RemoteParticipant.js +93 -12
- package/esm/simple/room/Room.js +93 -12
- package/esm/simple/room/SipRoom.js +93 -12
- package/esm/simple/room/Stream.js +93 -12
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +93 -12
- package/esm/simple/utils.js +93 -12
- package/esm/web-rtc-client.js +65 -6
- package/lib/__tests__/api-client.test.js +30 -0
- package/lib/__tests__/web-rtc-client.test.js +65 -6
- package/lib/api/calld.js +30 -0
- package/lib/api-client.js +30 -0
- package/lib/checker/Checker.js +65 -6
- package/lib/checker/checks/aor.js +30 -0
- package/lib/checker/checks/api.js +30 -0
- package/lib/checker/checks/index.js +65 -6
- package/lib/checker/checks/webrtc-transport.js +65 -6
- package/lib/checker/checks/webrtc.js +65 -6
- package/lib/domain/AdHocAPIConference.js +30 -0
- package/lib/domain/CallSession.js +15 -3
- package/lib/domain/Features.js +30 -0
- package/lib/domain/MeetingStatus.js +31 -0
- package/lib/domain/Phone/CTIPhone.js +45 -3
- package/lib/domain/Phone/WebRTCPhone.js +28 -6
- package/lib/domain/__tests__/CallSession.test.js +32 -3
- package/lib/domain/__tests__/IndirectTransfer.test.js +15 -3
- package/lib/domain/__tests__/Room.test.js +15 -3
- package/lib/index.js +93 -12
- package/lib/service/CallApi.js +30 -0
- package/lib/service/getApiClient.js +30 -0
- package/lib/simple/Auth.js +93 -12
- package/lib/simple/Configuration.js +93 -12
- package/lib/simple/Directory.js +30 -0
- package/lib/simple/Phone.js +93 -12
- package/lib/simple/index.js +93 -12
- package/lib/simple/room/LocalParticipant.js +93 -12
- package/lib/simple/room/Participant.js +93 -12
- package/lib/simple/room/RemoteParticipant.js +93 -12
- package/lib/simple/room/Room.js +93 -12
- package/lib/simple/room/SipRoom.js +93 -12
- package/lib/simple/room/Stream.js +93 -12
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +93 -12
- package/lib/simple/utils.js +93 -12
- package/lib/web-rtc-client.js +65 -6
- package/package.json +1 -1
- package/src/api/calld.js +3 -0
- package/src/domain/CallSession.js +16 -4
- package/src/domain/MeetingStatus.js +27 -0
- package/src/domain/Phone/WebRTCPhone.js +13 -3
- package/src/domain/__tests__/CallSession.test.js +17 -0
- package/src/web-rtc-client.js +35 -6
package/lib/simple/utils.js
CHANGED
|
@@ -3260,6 +3260,7 @@ var updateFrom = (instance , from ) => {
|
|
|
3260
3260
|
|
|
3261
3261
|
|
|
3262
3262
|
|
|
3263
|
+
|
|
3263
3264
|
|
|
3264
3265
|
|
|
3265
3266
|
|
|
@@ -3307,14 +3308,14 @@ class CallSession {
|
|
|
3307
3308
|
|
|
3308
3309
|
|
|
3309
3310
|
|
|
3311
|
+
// = creationTime
|
|
3312
|
+
|
|
3310
3313
|
|
|
3311
3314
|
|
|
3312
3315
|
|
|
3313
3316
|
|
|
3314
3317
|
|
|
3315
3318
|
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
3319
|
|
|
3319
3320
|
|
|
3320
3321
|
|
|
@@ -3378,6 +3379,7 @@ class CallSession {
|
|
|
3378
3379
|
recordingPaused,
|
|
3379
3380
|
videoRemotelyDowngraded,
|
|
3380
3381
|
sipSession,
|
|
3382
|
+
answerTime,
|
|
3381
3383
|
} ) {
|
|
3382
3384
|
this.callId = callId;
|
|
3383
3385
|
this.sipCallId = sipCallId;
|
|
@@ -3405,6 +3407,7 @@ class CallSession {
|
|
|
3405
3407
|
this.recordingPaused = recordingPaused || false;
|
|
3406
3408
|
this.videoRemotelyDowngraded = videoRemotelyDowngraded;
|
|
3407
3409
|
this.sipSession = sipSession;
|
|
3410
|
+
this.answerTime = answerTime || this.answerTime;
|
|
3408
3411
|
|
|
3409
3412
|
// Useful to compare instead of instanceof with minified code
|
|
3410
3413
|
this.type = 'CallSession';
|
|
@@ -3435,7 +3438,7 @@ class CallSession {
|
|
|
3435
3438
|
}
|
|
3436
3439
|
|
|
3437
3440
|
answer() {
|
|
3438
|
-
this.
|
|
3441
|
+
this.answerTime = new Date();
|
|
3439
3442
|
}
|
|
3440
3443
|
|
|
3441
3444
|
systemAnswer() {
|
|
@@ -3591,6 +3594,15 @@ class CallSession {
|
|
|
3591
3594
|
return newFrom(callSession, CallSession);
|
|
3592
3595
|
}
|
|
3593
3596
|
|
|
3597
|
+
// Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
|
|
3598
|
+
set answered(value ) {
|
|
3599
|
+
this.answerTime = value ? this.answerTime || new Date() : null;
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
get answered() {
|
|
3603
|
+
return !!this.answerTime;
|
|
3604
|
+
}
|
|
3605
|
+
|
|
3594
3606
|
static parseCall(call ) {
|
|
3595
3607
|
return new CallSession({
|
|
3596
3608
|
callId: call.id,
|
|
@@ -4842,6 +4854,34 @@ var chatdMethods = (client , baseUrl ) => ({
|
|
|
4842
4854
|
client.get(`${baseUrl}/users/me/rooms/messages`, options),
|
|
4843
4855
|
});
|
|
4844
4856
|
|
|
4857
|
+
//
|
|
4858
|
+
|
|
4859
|
+
|
|
4860
|
+
|
|
4861
|
+
|
|
4862
|
+
|
|
4863
|
+
class MeetingStatus {
|
|
4864
|
+
|
|
4865
|
+
|
|
4866
|
+
|
|
4867
|
+
|
|
4868
|
+
constructor({
|
|
4869
|
+
full,
|
|
4870
|
+
} = {}) {
|
|
4871
|
+
this.full = full;
|
|
4872
|
+
|
|
4873
|
+
// Useful to compare instead of instanceof with minified code
|
|
4874
|
+
this.type = 'MeetingStatus';
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4877
|
+
static parse(plain ) {
|
|
4878
|
+
return new MeetingStatus({
|
|
4879
|
+
full: plain.full,
|
|
4880
|
+
});
|
|
4881
|
+
}
|
|
4882
|
+
|
|
4883
|
+
}
|
|
4884
|
+
|
|
4845
4885
|
/* */
|
|
4846
4886
|
|
|
4847
4887
|
|
|
@@ -5036,6 +5076,8 @@ var calldMethods = (client , baseUrl ) => ({
|
|
|
5036
5076
|
client.put(`${baseUrl}/users/me/calls/${callId}/record/resume`, null, null,
|
|
5037
5077
|
ApiRequester.successResponseParser),
|
|
5038
5078
|
|
|
5079
|
+
guestGetMeetingStatus: (meetingUuid ) =>
|
|
5080
|
+
client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}/status`).then(MeetingStatus.parse),
|
|
5039
5081
|
});
|
|
5040
5082
|
|
|
5041
5083
|
//
|
|
@@ -6637,6 +6679,7 @@ const MAX_REGISTER_TRIES = 10;
|
|
|
6637
6679
|
|
|
6638
6680
|
|
|
6639
6681
|
|
|
6682
|
+
|
|
6640
6683
|
|
|
6641
6684
|
|
|
6642
6685
|
|
|
@@ -6678,6 +6721,7 @@ class WebRTCClient extends Emitter {
|
|
|
6678
6721
|
|
|
6679
6722
|
|
|
6680
6723
|
|
|
6724
|
+
|
|
6681
6725
|
|
|
6682
6726
|
// sugar
|
|
6683
6727
|
|
|
@@ -6740,6 +6784,7 @@ class WebRTCClient extends Emitter {
|
|
|
6740
6784
|
this.conferences = {};
|
|
6741
6785
|
this.networkMonitoringInterval = {};
|
|
6742
6786
|
this.sessionNetworkStats = {};
|
|
6787
|
+
this.forceClosed = false;
|
|
6743
6788
|
|
|
6744
6789
|
this._boundOnHeartbeat = this._onHeartbeat.bind(this);
|
|
6745
6790
|
this.heartbeat = new Heartbeat(config.heartbeatDelay, config.heartbeatTimeout, config.maxHeartbeats);
|
|
@@ -6861,6 +6906,8 @@ class WebRTCClient extends Emitter {
|
|
|
6861
6906
|
skipRegister: this.skipRegister,
|
|
6862
6907
|
};
|
|
6863
6908
|
|
|
6909
|
+
this.forceClosed = false;
|
|
6910
|
+
|
|
6864
6911
|
if (this.skipRegister) {
|
|
6865
6912
|
logger$8.info('sdk webrtc skip register...', logInfo);
|
|
6866
6913
|
return Promise.resolve();
|
|
@@ -6885,7 +6932,15 @@ class WebRTCClient extends Emitter {
|
|
|
6885
6932
|
const registerOptions = this._isWeb() ? {} : { extraContactHeaderParams: ['mobility=mobile'] };
|
|
6886
6933
|
|
|
6887
6934
|
const onRegisterFailed = () => {
|
|
6888
|
-
logger$8.info('sdk webrtc registering failed', {
|
|
6935
|
+
logger$8.info('sdk webrtc registering failed', {
|
|
6936
|
+
tries,
|
|
6937
|
+
registerer: !!this.registerer,
|
|
6938
|
+
forceClosed: this.forceClosed,
|
|
6939
|
+
});
|
|
6940
|
+
if (this.forceClosed) {
|
|
6941
|
+
return;
|
|
6942
|
+
}
|
|
6943
|
+
|
|
6889
6944
|
this.connectionPromise = null;
|
|
6890
6945
|
if (this.registerer && this.registerer.waiting) {
|
|
6891
6946
|
this.registerer.waitingToggle(false);
|
|
@@ -7163,8 +7218,9 @@ class WebRTCClient extends Emitter {
|
|
|
7163
7218
|
}
|
|
7164
7219
|
}
|
|
7165
7220
|
|
|
7166
|
-
async close() {
|
|
7167
|
-
logger$8.info('sdk webrtc closing client', { userAgent: !!this.userAgent });
|
|
7221
|
+
async close(force = false) {
|
|
7222
|
+
logger$8.info('sdk webrtc closing client', { userAgent: !!this.userAgent, force });
|
|
7223
|
+
this.forceClosed = force;
|
|
7168
7224
|
this._cleanupMedia();
|
|
7169
7225
|
this.connectionPromise = null;
|
|
7170
7226
|
|
|
@@ -7183,7 +7239,7 @@ class WebRTCClient extends Emitter {
|
|
|
7183
7239
|
this.userAgent.delegate = null;
|
|
7184
7240
|
this.userAgent.stateChange.removeAllListeners();
|
|
7185
7241
|
|
|
7186
|
-
await this._disconnectTransport();
|
|
7242
|
+
await this._disconnectTransport(force);
|
|
7187
7243
|
|
|
7188
7244
|
this._cleanupRegister();
|
|
7189
7245
|
|
|
@@ -8253,6 +8309,13 @@ class WebRTCClient extends Emitter {
|
|
|
8253
8309
|
}
|
|
8254
8310
|
|
|
8255
8311
|
_createWebRTCConfiguration(configOverrides = {}) {
|
|
8312
|
+
let { host } = this.config;
|
|
8313
|
+
let port = this.config.port || 443;
|
|
8314
|
+
|
|
8315
|
+
if (this.config.websocketSip) {
|
|
8316
|
+
[host, port = 443] = this.config.websocketSip.split(':');
|
|
8317
|
+
}
|
|
8318
|
+
|
|
8256
8319
|
const config = {
|
|
8257
8320
|
authorizationUsername: this.config.authorizationUser,
|
|
8258
8321
|
authorizationPassword: this.config.password,
|
|
@@ -8288,7 +8351,7 @@ class WebRTCClient extends Emitter {
|
|
|
8288
8351
|
},
|
|
8289
8352
|
transportOptions: {
|
|
8290
8353
|
traceSip: configOverrides.traceSip || false,
|
|
8291
|
-
wsServers: `wss://${
|
|
8354
|
+
wsServers: `wss://${host}:${port}/api/asterisk/ws`,
|
|
8292
8355
|
},
|
|
8293
8356
|
sessionDescriptionHandlerFactoryOptions: {
|
|
8294
8357
|
modifiers: [replaceLocalIpModifier],
|
|
@@ -8612,7 +8675,15 @@ class WebRTCClient extends Emitter {
|
|
|
8612
8675
|
return userAgent.UserAgent.makeURI(`sip:${target}@${this.config.host}`);
|
|
8613
8676
|
}
|
|
8614
8677
|
|
|
8615
|
-
async _disconnectTransport() {
|
|
8678
|
+
async _disconnectTransport(force = false) {
|
|
8679
|
+
if (force) {
|
|
8680
|
+
// Bypass sip.js state machine that prevent to close WS with the state `Connecting`
|
|
8681
|
+
this.userAgent.transport.disconnectResolve = () => {};
|
|
8682
|
+
// eslint-disable-next-line
|
|
8683
|
+
this.userAgent.transport._ws.close(1000);
|
|
8684
|
+
return;
|
|
8685
|
+
}
|
|
8686
|
+
|
|
8616
8687
|
// Check if `disconnectPromise` is not present to avoid `Disconnect promise must not be defined` errors.
|
|
8617
8688
|
if (this.userAgent && this.userAgent.transport && !this.userAgent.transport.disconnectPromise) {
|
|
8618
8689
|
try {
|
|
@@ -9348,6 +9419,8 @@ class WebRTCPhone extends Emitter {
|
|
|
9348
9419
|
this.removeIncomingSessions(sipSessionId);
|
|
9349
9420
|
}
|
|
9350
9421
|
|
|
9422
|
+
callSession.answerTime = new Date();
|
|
9423
|
+
this._updateCallSession(callSession);
|
|
9351
9424
|
this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
|
|
9352
9425
|
|
|
9353
9426
|
return callSession;
|
|
@@ -9563,6 +9636,8 @@ class WebRTCPhone extends Emitter {
|
|
|
9563
9636
|
}
|
|
9564
9637
|
|
|
9565
9638
|
this.shouldSendReinvite = false;
|
|
9639
|
+
callSession.answerTime = new Date();
|
|
9640
|
+
this._updateCallSession(callSession);
|
|
9566
9641
|
this.acceptedSessions[callSession.getId()] = true;
|
|
9567
9642
|
|
|
9568
9643
|
this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
|
|
@@ -9662,7 +9737,7 @@ class WebRTCPhone extends Emitter {
|
|
|
9662
9737
|
// Hold current session if different from the current one (we don't want 2 sessions active at the same time).
|
|
9663
9738
|
if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
|
|
9664
9739
|
logger$7.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
|
|
9665
|
-
this.holdSipSession(this.currentSipSession,
|
|
9740
|
+
this.holdSipSession(this.currentSipSession, this.currentCallSession);
|
|
9666
9741
|
}
|
|
9667
9742
|
|
|
9668
9743
|
const promise = this.unholdSipSession(sipSession, callSession, withEvent, isConference);
|
|
@@ -9873,6 +9948,7 @@ class WebRTCPhone extends Emitter {
|
|
|
9873
9948
|
}
|
|
9874
9949
|
const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
|
|
9875
9950
|
callSession.creationTime = new Date();
|
|
9951
|
+
this._updateCallSession(callSession);
|
|
9876
9952
|
|
|
9877
9953
|
this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
|
|
9878
9954
|
|
|
@@ -10014,7 +10090,7 @@ class WebRTCPhone extends Emitter {
|
|
|
10014
10090
|
return this.client && this.client.isConference(callSession.sipCallId);
|
|
10015
10091
|
}
|
|
10016
10092
|
|
|
10017
|
-
async close() {
|
|
10093
|
+
async close(force = false) {
|
|
10018
10094
|
logger$7.info('WebRTC close');
|
|
10019
10095
|
|
|
10020
10096
|
try {
|
|
@@ -10026,7 +10102,7 @@ class WebRTCPhone extends Emitter {
|
|
|
10026
10102
|
logger$7.error('WebRTC close, unregister error', e);
|
|
10027
10103
|
}
|
|
10028
10104
|
|
|
10029
|
-
this.client.close();
|
|
10105
|
+
this.client.close(force);
|
|
10030
10106
|
this.unbind();
|
|
10031
10107
|
|
|
10032
10108
|
this.incomingSessions = [];
|
|
@@ -10152,6 +10228,8 @@ class WebRTCPhone extends Emitter {
|
|
|
10152
10228
|
}
|
|
10153
10229
|
|
|
10154
10230
|
callSession.creationTime = new Date();
|
|
10231
|
+
this._updateCallSession(callSession);
|
|
10232
|
+
|
|
10155
10233
|
this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
|
|
10156
10234
|
});
|
|
10157
10235
|
|
|
@@ -10195,6 +10273,8 @@ class WebRTCPhone extends Emitter {
|
|
|
10195
10273
|
logger$7.info('WebRTC call rejected', session.id);
|
|
10196
10274
|
const callSession = this._createCallSession(session);
|
|
10197
10275
|
callSession.endTime = new Date();
|
|
10276
|
+
this._updateCallSession(callSession);
|
|
10277
|
+
|
|
10198
10278
|
this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
|
|
10199
10279
|
});
|
|
10200
10280
|
|
|
@@ -10419,6 +10499,7 @@ class WebRTCPhone extends Emitter {
|
|
|
10419
10499
|
displayName: identity ? identity.displayName || number : number,
|
|
10420
10500
|
startTime: fromSession ? fromSession.startTime : new Date(),
|
|
10421
10501
|
creationTime: fromSession ? fromSession.creationTime : null,
|
|
10502
|
+
answerTime: fromSession ? fromSession.answerTime : null,
|
|
10422
10503
|
endTime: fromSession ? fromSession.endTime : null,
|
|
10423
10504
|
answered: state === sessionState.SessionState.Established,
|
|
10424
10505
|
paused: this.client.isCallHeld(sipSession),
|
package/lib/web-rtc-client.js
CHANGED
|
@@ -4590,6 +4590,34 @@ var chatdMethods = (client , baseUrl ) => ({
|
|
|
4590
4590
|
client.get(`${baseUrl}/users/me/rooms/messages`, options),
|
|
4591
4591
|
});
|
|
4592
4592
|
|
|
4593
|
+
//
|
|
4594
|
+
|
|
4595
|
+
|
|
4596
|
+
|
|
4597
|
+
|
|
4598
|
+
|
|
4599
|
+
class MeetingStatus {
|
|
4600
|
+
|
|
4601
|
+
|
|
4602
|
+
|
|
4603
|
+
|
|
4604
|
+
constructor({
|
|
4605
|
+
full,
|
|
4606
|
+
} = {}) {
|
|
4607
|
+
this.full = full;
|
|
4608
|
+
|
|
4609
|
+
// Useful to compare instead of instanceof with minified code
|
|
4610
|
+
this.type = 'MeetingStatus';
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
static parse(plain ) {
|
|
4614
|
+
return new MeetingStatus({
|
|
4615
|
+
full: plain.full,
|
|
4616
|
+
});
|
|
4617
|
+
}
|
|
4618
|
+
|
|
4619
|
+
}
|
|
4620
|
+
|
|
4593
4621
|
/* */
|
|
4594
4622
|
|
|
4595
4623
|
|
|
@@ -4784,6 +4812,8 @@ var calldMethods = (client , baseUrl ) => ({
|
|
|
4784
4812
|
client.put(`${baseUrl}/users/me/calls/${callId}/record/resume`, null, null,
|
|
4785
4813
|
ApiRequester.successResponseParser),
|
|
4786
4814
|
|
|
4815
|
+
guestGetMeetingStatus: (meetingUuid ) =>
|
|
4816
|
+
client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}/status`).then(MeetingStatus.parse),
|
|
4787
4817
|
});
|
|
4788
4818
|
|
|
4789
4819
|
//
|
|
@@ -5358,6 +5388,7 @@ const MAX_REGISTER_TRIES = 10;
|
|
|
5358
5388
|
|
|
5359
5389
|
|
|
5360
5390
|
|
|
5391
|
+
|
|
5361
5392
|
|
|
5362
5393
|
|
|
5363
5394
|
|
|
@@ -5399,6 +5430,7 @@ class WebRTCClient extends Emitter {
|
|
|
5399
5430
|
|
|
5400
5431
|
|
|
5401
5432
|
|
|
5433
|
+
|
|
5402
5434
|
|
|
5403
5435
|
// sugar
|
|
5404
5436
|
|
|
@@ -5461,6 +5493,7 @@ class WebRTCClient extends Emitter {
|
|
|
5461
5493
|
this.conferences = {};
|
|
5462
5494
|
this.networkMonitoringInterval = {};
|
|
5463
5495
|
this.sessionNetworkStats = {};
|
|
5496
|
+
this.forceClosed = false;
|
|
5464
5497
|
|
|
5465
5498
|
this._boundOnHeartbeat = this._onHeartbeat.bind(this);
|
|
5466
5499
|
this.heartbeat = new Heartbeat(config.heartbeatDelay, config.heartbeatTimeout, config.maxHeartbeats);
|
|
@@ -5582,6 +5615,8 @@ class WebRTCClient extends Emitter {
|
|
|
5582
5615
|
skipRegister: this.skipRegister,
|
|
5583
5616
|
};
|
|
5584
5617
|
|
|
5618
|
+
this.forceClosed = false;
|
|
5619
|
+
|
|
5585
5620
|
if (this.skipRegister) {
|
|
5586
5621
|
logger.info('sdk webrtc skip register...', logInfo);
|
|
5587
5622
|
return Promise.resolve();
|
|
@@ -5606,7 +5641,15 @@ class WebRTCClient extends Emitter {
|
|
|
5606
5641
|
const registerOptions = this._isWeb() ? {} : { extraContactHeaderParams: ['mobility=mobile'] };
|
|
5607
5642
|
|
|
5608
5643
|
const onRegisterFailed = () => {
|
|
5609
|
-
logger.info('sdk webrtc registering failed', {
|
|
5644
|
+
logger.info('sdk webrtc registering failed', {
|
|
5645
|
+
tries,
|
|
5646
|
+
registerer: !!this.registerer,
|
|
5647
|
+
forceClosed: this.forceClosed,
|
|
5648
|
+
});
|
|
5649
|
+
if (this.forceClosed) {
|
|
5650
|
+
return;
|
|
5651
|
+
}
|
|
5652
|
+
|
|
5610
5653
|
this.connectionPromise = null;
|
|
5611
5654
|
if (this.registerer && this.registerer.waiting) {
|
|
5612
5655
|
this.registerer.waitingToggle(false);
|
|
@@ -5884,8 +5927,9 @@ class WebRTCClient extends Emitter {
|
|
|
5884
5927
|
}
|
|
5885
5928
|
}
|
|
5886
5929
|
|
|
5887
|
-
async close() {
|
|
5888
|
-
logger.info('sdk webrtc closing client', { userAgent: !!this.userAgent });
|
|
5930
|
+
async close(force = false) {
|
|
5931
|
+
logger.info('sdk webrtc closing client', { userAgent: !!this.userAgent, force });
|
|
5932
|
+
this.forceClosed = force;
|
|
5889
5933
|
this._cleanupMedia();
|
|
5890
5934
|
this.connectionPromise = null;
|
|
5891
5935
|
|
|
@@ -5904,7 +5948,7 @@ class WebRTCClient extends Emitter {
|
|
|
5904
5948
|
this.userAgent.delegate = null;
|
|
5905
5949
|
this.userAgent.stateChange.removeAllListeners();
|
|
5906
5950
|
|
|
5907
|
-
await this._disconnectTransport();
|
|
5951
|
+
await this._disconnectTransport(force);
|
|
5908
5952
|
|
|
5909
5953
|
this._cleanupRegister();
|
|
5910
5954
|
|
|
@@ -6974,6 +7018,13 @@ class WebRTCClient extends Emitter {
|
|
|
6974
7018
|
}
|
|
6975
7019
|
|
|
6976
7020
|
_createWebRTCConfiguration(configOverrides = {}) {
|
|
7021
|
+
let { host } = this.config;
|
|
7022
|
+
let port = this.config.port || 443;
|
|
7023
|
+
|
|
7024
|
+
if (this.config.websocketSip) {
|
|
7025
|
+
[host, port = 443] = this.config.websocketSip.split(':');
|
|
7026
|
+
}
|
|
7027
|
+
|
|
6977
7028
|
const config = {
|
|
6978
7029
|
authorizationUsername: this.config.authorizationUser,
|
|
6979
7030
|
authorizationPassword: this.config.password,
|
|
@@ -7009,7 +7060,7 @@ class WebRTCClient extends Emitter {
|
|
|
7009
7060
|
},
|
|
7010
7061
|
transportOptions: {
|
|
7011
7062
|
traceSip: configOverrides.traceSip || false,
|
|
7012
|
-
wsServers: `wss://${
|
|
7063
|
+
wsServers: `wss://${host}:${port}/api/asterisk/ws`,
|
|
7013
7064
|
},
|
|
7014
7065
|
sessionDescriptionHandlerFactoryOptions: {
|
|
7015
7066
|
modifiers: [replaceLocalIpModifier],
|
|
@@ -7333,7 +7384,15 @@ class WebRTCClient extends Emitter {
|
|
|
7333
7384
|
return userAgent.UserAgent.makeURI(`sip:${target}@${this.config.host}`);
|
|
7334
7385
|
}
|
|
7335
7386
|
|
|
7336
|
-
async _disconnectTransport() {
|
|
7387
|
+
async _disconnectTransport(force = false) {
|
|
7388
|
+
if (force) {
|
|
7389
|
+
// Bypass sip.js state machine that prevent to close WS with the state `Connecting`
|
|
7390
|
+
this.userAgent.transport.disconnectResolve = () => {};
|
|
7391
|
+
// eslint-disable-next-line
|
|
7392
|
+
this.userAgent.transport._ws.close(1000);
|
|
7393
|
+
return;
|
|
7394
|
+
}
|
|
7395
|
+
|
|
7337
7396
|
// Check if `disconnectPromise` is not present to avoid `Disconnect promise must not be defined` errors.
|
|
7338
7397
|
if (this.userAgent && this.userAgent.transport && !this.userAgent.transport.disconnectPromise) {
|
|
7339
7398
|
try {
|
package/package.json
CHANGED
package/src/api/calld.js
CHANGED
|
@@ -7,6 +7,7 @@ import ChatMessage from '../domain/ChatMessage';
|
|
|
7
7
|
import Voicemail from '../domain/Voicemail';
|
|
8
8
|
import Call from '../domain/Call';
|
|
9
9
|
import IndirectTransfer from '../domain/IndirectTransfer';
|
|
10
|
+
import MeetingStatus from '../domain/MeetingStatus';
|
|
10
11
|
|
|
11
12
|
type CallQuery = {
|
|
12
13
|
from_mobile: boolean,
|
|
@@ -200,4 +201,6 @@ export default (client: ApiRequester, baseUrl: string) => ({
|
|
|
200
201
|
client.put(`${baseUrl}/users/me/calls/${callId}/record/resume`, null, null,
|
|
201
202
|
ApiRequester.successResponseParser),
|
|
202
203
|
|
|
204
|
+
guestGetMeetingStatus: (meetingUuid: string): Promise<MeetingStatus> =>
|
|
205
|
+
client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}/status`).then(MeetingStatus.parse),
|
|
203
206
|
});
|
|
@@ -8,6 +8,7 @@ import updateFrom from '../utils/update-from';
|
|
|
8
8
|
|
|
9
9
|
type CallSessionArguments = {
|
|
10
10
|
answered: boolean,
|
|
11
|
+
answerTime?: ?Date,
|
|
11
12
|
answeredBySystem: boolean,
|
|
12
13
|
call: ?Call,
|
|
13
14
|
callId: string,
|
|
@@ -55,14 +56,14 @@ export default class CallSession {
|
|
|
55
56
|
|
|
56
57
|
creationTime: ?Date;
|
|
57
58
|
|
|
58
|
-
startTime: number;
|
|
59
|
+
startTime: number; // = creationTime
|
|
60
|
+
|
|
61
|
+
answerTime: ?Date;
|
|
59
62
|
|
|
60
63
|
endTime: ?Date;
|
|
61
64
|
|
|
62
65
|
isCaller: boolean;
|
|
63
66
|
|
|
64
|
-
answered: boolean;
|
|
65
|
-
|
|
66
67
|
answeredBySystem: boolean;
|
|
67
68
|
|
|
68
69
|
dialedExtension: string;
|
|
@@ -126,6 +127,7 @@ export default class CallSession {
|
|
|
126
127
|
recordingPaused,
|
|
127
128
|
videoRemotelyDowngraded,
|
|
128
129
|
sipSession,
|
|
130
|
+
answerTime,
|
|
129
131
|
}: CallSessionArguments) {
|
|
130
132
|
this.callId = callId;
|
|
131
133
|
this.sipCallId = sipCallId;
|
|
@@ -153,6 +155,7 @@ export default class CallSession {
|
|
|
153
155
|
this.recordingPaused = recordingPaused || false;
|
|
154
156
|
this.videoRemotelyDowngraded = videoRemotelyDowngraded;
|
|
155
157
|
this.sipSession = sipSession;
|
|
158
|
+
this.answerTime = answerTime || this.answerTime;
|
|
156
159
|
|
|
157
160
|
// Useful to compare instead of instanceof with minified code
|
|
158
161
|
this.type = 'CallSession';
|
|
@@ -183,7 +186,7 @@ export default class CallSession {
|
|
|
183
186
|
}
|
|
184
187
|
|
|
185
188
|
answer() {
|
|
186
|
-
this.
|
|
189
|
+
this.answerTime = new Date();
|
|
187
190
|
}
|
|
188
191
|
|
|
189
192
|
systemAnswer() {
|
|
@@ -339,6 +342,15 @@ export default class CallSession {
|
|
|
339
342
|
return newFrom(callSession, CallSession);
|
|
340
343
|
}
|
|
341
344
|
|
|
345
|
+
// Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
|
|
346
|
+
set answered(value: boolean) {
|
|
347
|
+
this.answerTime = value ? this.answerTime || new Date() : null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
get answered(): boolean {
|
|
351
|
+
return !!this.answerTime;
|
|
352
|
+
}
|
|
353
|
+
|
|
342
354
|
static parseCall(call: Call): CallSession {
|
|
343
355
|
return new CallSession({
|
|
344
356
|
callId: call.id,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
export type MeetingStatusResponse = {
|
|
4
|
+
full: boolean
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export default class MeetingStatus {
|
|
8
|
+
type: string;
|
|
9
|
+
|
|
10
|
+
full: boolean;
|
|
11
|
+
|
|
12
|
+
constructor({
|
|
13
|
+
full,
|
|
14
|
+
}: Object = {}) {
|
|
15
|
+
this.full = full;
|
|
16
|
+
|
|
17
|
+
// Useful to compare instead of instanceof with minified code
|
|
18
|
+
this.type = 'MeetingStatus';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static parse(plain: MeetingStatusResponse): MeetingStatus {
|
|
22
|
+
return new MeetingStatus({
|
|
23
|
+
full: plain.full,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
@@ -630,6 +630,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
630
630
|
this.removeIncomingSessions(sipSessionId);
|
|
631
631
|
}
|
|
632
632
|
|
|
633
|
+
callSession.answerTime = new Date();
|
|
634
|
+
this._updateCallSession(callSession);
|
|
633
635
|
this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
|
|
634
636
|
|
|
635
637
|
return callSession;
|
|
@@ -845,6 +847,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
845
847
|
}
|
|
846
848
|
|
|
847
849
|
this.shouldSendReinvite = false;
|
|
850
|
+
callSession.answerTime = new Date();
|
|
851
|
+
this._updateCallSession(callSession);
|
|
848
852
|
this.acceptedSessions[callSession.getId()] = true;
|
|
849
853
|
|
|
850
854
|
this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
|
|
@@ -944,7 +948,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
944
948
|
// Hold current session if different from the current one (we don't want 2 sessions active at the same time).
|
|
945
949
|
if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
|
|
946
950
|
logger.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
|
|
947
|
-
this.holdSipSession(this.currentSipSession,
|
|
951
|
+
this.holdSipSession(this.currentSipSession, this.currentCallSession);
|
|
948
952
|
}
|
|
949
953
|
|
|
950
954
|
const promise = this.unholdSipSession(sipSession, callSession, withEvent, isConference);
|
|
@@ -1155,6 +1159,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1155
1159
|
}
|
|
1156
1160
|
const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
|
|
1157
1161
|
callSession.creationTime = new Date();
|
|
1162
|
+
this._updateCallSession(callSession);
|
|
1158
1163
|
|
|
1159
1164
|
this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
|
|
1160
1165
|
|
|
@@ -1296,7 +1301,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1296
1301
|
return this.client && this.client.isConference(callSession.sipCallId);
|
|
1297
1302
|
}
|
|
1298
1303
|
|
|
1299
|
-
async close(): Promise<void> {
|
|
1304
|
+
async close(force: boolean = false): Promise<void> {
|
|
1300
1305
|
logger.info('WebRTC close');
|
|
1301
1306
|
|
|
1302
1307
|
try {
|
|
@@ -1308,7 +1313,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1308
1313
|
logger.error('WebRTC close, unregister error', e);
|
|
1309
1314
|
}
|
|
1310
1315
|
|
|
1311
|
-
this.client.close();
|
|
1316
|
+
this.client.close(force);
|
|
1312
1317
|
this.unbind();
|
|
1313
1318
|
|
|
1314
1319
|
this.incomingSessions = [];
|
|
@@ -1434,6 +1439,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1434
1439
|
}
|
|
1435
1440
|
|
|
1436
1441
|
callSession.creationTime = new Date();
|
|
1442
|
+
this._updateCallSession(callSession);
|
|
1443
|
+
|
|
1437
1444
|
this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
|
|
1438
1445
|
});
|
|
1439
1446
|
|
|
@@ -1477,6 +1484,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1477
1484
|
logger.info('WebRTC call rejected', session.id);
|
|
1478
1485
|
const callSession = this._createCallSession(session);
|
|
1479
1486
|
callSession.endTime = new Date();
|
|
1487
|
+
this._updateCallSession(callSession);
|
|
1488
|
+
|
|
1480
1489
|
this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
|
|
1481
1490
|
});
|
|
1482
1491
|
|
|
@@ -1703,6 +1712,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1703
1712
|
displayName: identity ? identity.displayName || number : number,
|
|
1704
1713
|
startTime: fromSession ? fromSession.startTime : new Date(),
|
|
1705
1714
|
creationTime: fromSession ? fromSession.creationTime : null,
|
|
1715
|
+
answerTime: fromSession ? fromSession.answerTime : null,
|
|
1706
1716
|
endTime: fromSession ? fromSession.endTime : null,
|
|
1707
1717
|
answered: state === SessionState.Established,
|
|
1708
1718
|
paused: this.client.isCallHeld(sipSession),
|
|
@@ -37,4 +37,21 @@ describe('CallSession domain', () => {
|
|
|
37
37
|
expect(cs1.is(cs2)).toBeTruthy();
|
|
38
38
|
expect(cs2.is(cs1)).toBeTruthy();
|
|
39
39
|
});
|
|
40
|
+
|
|
41
|
+
it('should set answerTime when setting answered', () => {
|
|
42
|
+
const cs1 = new CallSession({});
|
|
43
|
+
cs1.answered = true;
|
|
44
|
+
|
|
45
|
+
const cs2 = new CallSession({});
|
|
46
|
+
cs2.answer();
|
|
47
|
+
|
|
48
|
+
const cs3 = new CallSession({ answered: true });
|
|
49
|
+
|
|
50
|
+
expect(cs1.answered).toBeTruthy();
|
|
51
|
+
expect(cs1.answerTime).not.toBeNull();
|
|
52
|
+
expect(cs2.answered).toBeTruthy();
|
|
53
|
+
expect(cs2.answerTime).not.toBeNull();
|
|
54
|
+
expect(cs3.answered).toBeTruthy();
|
|
55
|
+
expect(cs3.answerTime).not.toBeNull();
|
|
56
|
+
});
|
|
40
57
|
});
|