@wazo/sdk 1.0.0-alpha.2 → 1.0.0-alpha.20
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 +16 -7
- package/dist/wazo-sdk.js +2 -2
- package/esm/__tests__/__voice__/call.test.js +52 -3
- package/esm/api/auth.js +3 -0
- package/esm/checker/checks/webrtc.js +2 -2
- package/esm/domain/CallLog.js +2 -3
- package/esm/domain/Phone/CTIPhone.js +2 -2
- package/esm/domain/Phone/WebRTCPhone.js +59 -57
- package/esm/index.js +3 -1
- package/esm/service/CallApi.js +4 -4
- package/esm/simple/Auth.js +13 -3
- package/esm/simple/Phone.js +5 -5
- package/esm/simple/index.js +2 -1
- package/esm/simple/room/Room.js +2 -2
- package/esm/simple/room/SipRoom.js +2 -2
- package/esm/state-machine/call-state-machine.js +34 -19
- package/esm/state-machine/softphone-state-machine.js +1 -2
- package/esm/state-machine/utils.js +10 -4
- package/esm/types/api/auth.d.ts +3 -0
- package/esm/types/api/auth.d.ts.map +1 -1
- package/esm/types/checker/checks/index.d.ts +1 -1
- package/esm/types/checker/checks/webrtc-transport.d.ts +2 -2
- package/esm/types/checker/checks/webrtc-transport.d.ts.map +1 -1
- package/esm/types/domain/CallLog.d.ts.map +1 -1
- package/esm/types/domain/CallSession.d.ts +3 -3
- package/esm/types/domain/CallSession.d.ts.map +1 -1
- package/esm/types/domain/Phone/CTIPhone.d.ts.map +1 -1
- package/esm/types/domain/Phone/WebRTCPhone.d.ts +22 -22
- package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
- package/esm/types/domain/types.d.ts +0 -4
- package/esm/types/domain/types.d.ts.map +1 -1
- package/esm/types/index.d.ts +3 -1
- package/esm/types/index.d.ts.map +1 -1
- package/esm/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
- package/esm/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
- package/esm/types/service/CallApi.d.ts +5 -5
- package/esm/types/service/CallApi.d.ts.map +1 -1
- package/esm/types/simple/Auth.d.ts +6 -1
- package/esm/types/simple/Auth.d.ts.map +1 -1
- package/esm/types/simple/Phone.d.ts +8 -8
- package/esm/types/simple/Phone.d.ts.map +1 -1
- package/esm/types/simple/index.d.ts +3 -1
- package/esm/types/simple/index.d.ts.map +1 -1
- package/esm/types/state-machine/call-state-machine.d.ts +12 -1
- package/esm/types/state-machine/call-state-machine.d.ts.map +1 -1
- package/esm/types/state-machine/softphone-state-machine.d.ts +1 -2
- package/esm/types/state-machine/softphone-state-machine.d.ts.map +1 -1
- package/esm/types/state-machine/utils.d.ts +1 -1
- package/esm/types/state-machine/utils.d.ts.map +1 -1
- package/esm/types/utils/sdp.d.ts +1 -2
- package/esm/types/utils/sdp.d.ts.map +1 -1
- package/esm/types/utils/update-from.d.ts +1 -1
- package/esm/types/utils/update-from.d.ts.map +1 -1
- package/esm/types/utils/webrtc.d.ts.map +1 -1
- package/esm/types/voice/call.d.ts +15 -3
- package/esm/types/voice/call.d.ts.map +1 -1
- package/esm/types/voice/softphone.d.ts +7 -0
- package/esm/types/voice/softphone.d.ts.map +1 -1
- package/esm/types/web-rtc-client.d.ts +39 -38
- package/esm/types/web-rtc-client.d.ts.map +1 -1
- package/esm/utils/sdp.js +16 -9
- package/esm/utils/update-from.js +2 -2
- package/esm/utils/webrtc.js +10 -4
- package/esm/voice/call.js +86 -28
- package/esm/voice/softphone.js +58 -17
- package/esm/web-rtc-client.js +67 -58
- package/lib/__tests__/__voice__/call.test.js +51 -2
- package/lib/api/auth.js +3 -0
- package/lib/checker/checks/webrtc.js +1 -1
- package/lib/domain/CallLog.js +2 -3
- package/lib/domain/Phone/CTIPhone.js +2 -2
- package/lib/domain/Phone/WebRTCPhone.js +58 -56
- package/lib/index.js +7 -3
- package/lib/service/CallApi.js +2 -2
- package/lib/simple/Auth.js +15 -3
- package/lib/simple/Phone.js +2 -2
- package/lib/simple/index.js +2 -1
- package/lib/simple/room/Room.js +1 -1
- package/lib/simple/room/SipRoom.js +1 -1
- package/lib/state-machine/call-state-machine.js +35 -20
- package/lib/state-machine/softphone-state-machine.js +1 -2
- package/lib/state-machine/utils.js +10 -4
- package/lib/types/api/auth.d.ts +3 -0
- package/lib/types/api/auth.d.ts.map +1 -1
- package/lib/types/checker/checks/index.d.ts +1 -1
- package/lib/types/checker/checks/webrtc-transport.d.ts +2 -2
- package/lib/types/checker/checks/webrtc-transport.d.ts.map +1 -1
- package/lib/types/domain/CallLog.d.ts.map +1 -1
- package/lib/types/domain/CallSession.d.ts +3 -3
- package/lib/types/domain/CallSession.d.ts.map +1 -1
- package/lib/types/domain/Phone/CTIPhone.d.ts.map +1 -1
- package/lib/types/domain/Phone/WebRTCPhone.d.ts +22 -22
- package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
- package/lib/types/domain/types.d.ts +0 -4
- package/lib/types/domain/types.d.ts.map +1 -1
- package/lib/types/index.d.ts +3 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
- package/lib/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
- package/lib/types/service/CallApi.d.ts +5 -5
- package/lib/types/service/CallApi.d.ts.map +1 -1
- package/lib/types/simple/Auth.d.ts +6 -1
- package/lib/types/simple/Auth.d.ts.map +1 -1
- package/lib/types/simple/Phone.d.ts +8 -8
- package/lib/types/simple/Phone.d.ts.map +1 -1
- package/lib/types/simple/index.d.ts +3 -1
- package/lib/types/simple/index.d.ts.map +1 -1
- package/lib/types/state-machine/call-state-machine.d.ts +12 -1
- package/lib/types/state-machine/call-state-machine.d.ts.map +1 -1
- package/lib/types/state-machine/softphone-state-machine.d.ts +1 -2
- package/lib/types/state-machine/softphone-state-machine.d.ts.map +1 -1
- package/lib/types/state-machine/utils.d.ts +1 -1
- package/lib/types/state-machine/utils.d.ts.map +1 -1
- package/lib/types/utils/sdp.d.ts +1 -2
- package/lib/types/utils/sdp.d.ts.map +1 -1
- package/lib/types/utils/update-from.d.ts +1 -1
- package/lib/types/utils/update-from.d.ts.map +1 -1
- package/lib/types/utils/webrtc.d.ts.map +1 -1
- package/lib/types/voice/call.d.ts +15 -3
- package/lib/types/voice/call.d.ts.map +1 -1
- package/lib/types/voice/softphone.d.ts +7 -0
- package/lib/types/voice/softphone.d.ts.map +1 -1
- package/lib/types/web-rtc-client.d.ts +39 -38
- package/lib/types/web-rtc-client.d.ts.map +1 -1
- package/lib/utils/sdp.js +17 -10
- package/lib/utils/update-from.js +2 -2
- package/lib/utils/webrtc.js +11 -4
- package/lib/voice/call.js +89 -27
- package/lib/voice/softphone.js +62 -17
- package/lib/web-rtc-client.js +66 -57
- package/package.json +1 -1
- package/src/__tests__/__voice__/call.test.ts +61 -3
- package/src/api/auth.ts +5 -0
- package/src/checker/checks/webrtc-transport.ts +2 -2
- package/src/checker/checks/webrtc.ts +2 -2
- package/src/domain/CallLog.ts +2 -3
- package/src/domain/CallSession.ts +3 -3
- package/src/domain/Phone/CTIPhone.ts +3 -2
- package/src/domain/Phone/WebRTCPhone.ts +87 -85
- package/src/domain/__tests__/CallSession.test.ts +4 -0
- package/src/domain/types.ts +0 -5
- package/src/index.ts +4 -1
- package/src/lib/WazoSessionDescriptionHandler.ts +3 -3
- package/src/service/CallApi.ts +7 -7
- package/src/simple/Auth.ts +15 -3
- package/src/simple/Phone.ts +11 -11
- package/src/simple/index.ts +2 -1
- package/src/simple/room/Room.ts +3 -3
- package/src/simple/room/SipRoom.ts +3 -3
- package/src/state-machine/call-state-machine.ts +38 -19
- package/src/state-machine/softphone-state-machine.ts +1 -2
- package/src/state-machine/utils.ts +12 -4
- package/src/utils/sdp.ts +18 -11
- package/src/utils/update-from.ts +2 -2
- package/src/utils/webrtc.ts +11 -4
- package/src/voice/call.ts +109 -36
- package/src/voice/softphone.ts +75 -18
- package/src/web-rtc-client.ts +112 -98
package/esm/web-rtc-client.js
CHANGED
|
@@ -17,7 +17,7 @@ import Emitter from './utils/Emitter';
|
|
|
17
17
|
import ApiClient from './api-client';
|
|
18
18
|
import IssueReporter from './service/IssueReporter';
|
|
19
19
|
import Heartbeat from './utils/Heartbeat';
|
|
20
|
-
import {
|
|
20
|
+
import { getSipCallId, makeURI, replaceLocalIpModifier } from './utils/sdp';
|
|
21
21
|
import { cleanupStream, createUaOptions, fetchNetworkStats, getAudioConstraints, getLocalStream, getLocalTracks, getLocalVideoStream, getMediaConfiguration, getPeerConnection, getRemoteStream, getRemoteTracks, getRemoteVideoStream, getRemoteVideoStreamFromPc, getVideoConstraints, hasALocalVideoTrack, hasARemoteVideoTrack, hasAVideoTrack, hasLocalVideo, hasRemoteVideo, hasVideoTrack, isAudioOnly, isVideoRemotelyHeld, isWeb, sessionWantsToDoVideo, setLocalMediaStream, toggleAudio, toggleVideo, updateRemoteStream } from './utils/webrtc';
|
|
22
22
|
const SEND_STATS_DELAY = 5000;
|
|
23
23
|
const states = ['STATUS_NULL', 'STATUS_NEW', 'STATUS_CONNECTING', 'STATUS_CONNECTED', 'STATUS_COMPLETED'];
|
|
@@ -25,6 +25,7 @@ const logger = IssueReporter ? IssueReporter.loggerFor('webrtc-client') : consol
|
|
|
25
25
|
const statsLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-stats') : console;
|
|
26
26
|
// events
|
|
27
27
|
const REGISTERED = 'registered';
|
|
28
|
+
const REGISTERING = 'registering';
|
|
28
29
|
const UNREGISTERED = 'unregistered';
|
|
29
30
|
const REGISTRATION_FAILED = 'registrationFailed';
|
|
30
31
|
const INVITE = 'invite';
|
|
@@ -42,7 +43,7 @@ const ON_ERROR = 'onError';
|
|
|
42
43
|
const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
|
|
43
44
|
const ON_NETWORK_STATS = 'onNetworkStats';
|
|
44
45
|
const ON_DISCONNECTED = 'onDisconnected';
|
|
45
|
-
export const events = [REGISTERED, UNREGISTERED, REGISTRATION_FAILED, INVITE];
|
|
46
|
+
export const events = [REGISTERED, REGISTERING, UNREGISTERED, REGISTRATION_FAILED, INVITE];
|
|
46
47
|
export const transportEvents = [CONNECTED, DISCONNECTED, TRANSPORT_ERROR, MESSAGE];
|
|
47
48
|
export class CanceledCallError extends Error {
|
|
48
49
|
}
|
|
@@ -76,6 +77,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
76
77
|
// sugar
|
|
77
78
|
ON_USER_AGENT;
|
|
78
79
|
REGISTERED;
|
|
80
|
+
REGISTERING;
|
|
79
81
|
UNREGISTERED;
|
|
80
82
|
REGISTRATION_FAILED;
|
|
81
83
|
INVITE;
|
|
@@ -103,7 +105,9 @@ export default class WebRTCClient extends Emitter {
|
|
|
103
105
|
this.skipRegister = config.skipRegister;
|
|
104
106
|
this._buildConfig(config, session).then((newConfig) => {
|
|
105
107
|
this.config = newConfig;
|
|
106
|
-
this.userAgent
|
|
108
|
+
if (!this.userAgent) {
|
|
109
|
+
this.userAgent = this.createUserAgent(uaConfigOverrides);
|
|
110
|
+
}
|
|
107
111
|
});
|
|
108
112
|
this.audioOutputDeviceId = config.audioDeviceOutput;
|
|
109
113
|
this.audioOutputVolume = config.audioOutputVolume || 1;
|
|
@@ -128,6 +132,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
128
132
|
this.heartbeat.setOnHeartbeatTimeout(this._onHeartbeatTimeout.bind(this));
|
|
129
133
|
// sugar
|
|
130
134
|
this.REGISTERED = REGISTERED;
|
|
135
|
+
this.REGISTERING = REGISTERING;
|
|
131
136
|
this.UNREGISTERED = UNREGISTERED;
|
|
132
137
|
this.REGISTRATION_FAILED = REGISTRATION_FAILED;
|
|
133
138
|
this.INVITE = INVITE;
|
|
@@ -168,7 +173,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
168
173
|
logger.info('sdk webrtc on invite', {
|
|
169
174
|
method: 'delegate.onInvite',
|
|
170
175
|
clientId: this.clientId,
|
|
171
|
-
id: invitation
|
|
176
|
+
id: getSipCallId(invitation),
|
|
172
177
|
remoteURI: invitation.remoteURI,
|
|
173
178
|
});
|
|
174
179
|
this._setupSession(invitation);
|
|
@@ -230,7 +235,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
230
235
|
// @ts-ignore: private
|
|
231
236
|
this.registerer.waitingToggle(false);
|
|
232
237
|
}
|
|
233
|
-
this.eventEmitter.emit(UNREGISTERED);
|
|
238
|
+
this.eventEmitter.emit(UNREGISTERED, error);
|
|
234
239
|
}
|
|
235
240
|
}
|
|
236
241
|
async register(tries = 0) {
|
|
@@ -251,6 +256,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
251
256
|
return Promise.resolve();
|
|
252
257
|
}
|
|
253
258
|
logger.info('sdk webrtc registering...', logInfo);
|
|
259
|
+
this.eventEmitter.emit(REGISTERING);
|
|
254
260
|
if (!this.userAgent) {
|
|
255
261
|
logger.info('sdk webrtc recreating User Agent');
|
|
256
262
|
this.userAgent = this.createUserAgent(this.uaConfigOverrides);
|
|
@@ -358,6 +364,12 @@ export default class WebRTCClient extends Emitter {
|
|
|
358
364
|
userAgent: !!this.userAgent,
|
|
359
365
|
registerer: !!this.registerer,
|
|
360
366
|
});
|
|
367
|
+
// @ts-ignore: private
|
|
368
|
+
if (this.registerer?.waiting) {
|
|
369
|
+
logger.info('sdk webrtc unregistering, waiting for register to finish...');
|
|
370
|
+
// We have to wait for the register phase to finish
|
|
371
|
+
await this.waitForRegister();
|
|
372
|
+
}
|
|
361
373
|
try {
|
|
362
374
|
return new Promise((resolve, reject) => {
|
|
363
375
|
if (!this.registerer) {
|
|
@@ -435,7 +447,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
435
447
|
this._setupSession(session);
|
|
436
448
|
}
|
|
437
449
|
if (conference) {
|
|
438
|
-
this.conferences[
|
|
450
|
+
this.conferences[getSipCallId(session)] = true;
|
|
439
451
|
}
|
|
440
452
|
const inviteOptions = {
|
|
441
453
|
requestDelegate: {
|
|
@@ -450,7 +462,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
450
462
|
},
|
|
451
463
|
onReject: (response) => {
|
|
452
464
|
logger.info('on call rejected', {
|
|
453
|
-
id: session
|
|
465
|
+
id: getSipCallId(session),
|
|
454
466
|
// @ts-ignore: fromTag does not exist
|
|
455
467
|
fromTag: session?.fromTag,
|
|
456
468
|
});
|
|
@@ -480,7 +492,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
480
492
|
answer(session, enableVideo) {
|
|
481
493
|
logger.info('sdk webrtc answer call', {
|
|
482
494
|
clientId: this.clientId,
|
|
483
|
-
id: session
|
|
495
|
+
id: getSipCallId(session),
|
|
484
496
|
enableVideo,
|
|
485
497
|
});
|
|
486
498
|
if (!session || !session.accept) {
|
|
@@ -496,7 +508,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
496
508
|
if (session.isCanceled) {
|
|
497
509
|
const message = 'accepted a canceled session (or was canceled during the accept phase).';
|
|
498
510
|
logger.error(message, {
|
|
499
|
-
id: session
|
|
511
|
+
id: getSipCallId(session),
|
|
500
512
|
});
|
|
501
513
|
this.onCallEnded(session);
|
|
502
514
|
throw new CanceledCallError(message);
|
|
@@ -504,7 +516,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
504
516
|
logger.info('sdk webrtc answer, accepted.');
|
|
505
517
|
this._onAccepted(session);
|
|
506
518
|
}).catch(e => {
|
|
507
|
-
logger.error(`answer call error for ${session
|
|
519
|
+
logger.error(`answer call error for ${getSipCallId(session)}`, e);
|
|
508
520
|
throw e;
|
|
509
521
|
});
|
|
510
522
|
}
|
|
@@ -514,7 +526,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
514
526
|
try {
|
|
515
527
|
this._stopSendingStats(session);
|
|
516
528
|
this._cleanupMedia(session);
|
|
517
|
-
delete this.sipSessions[
|
|
529
|
+
delete this.sipSessions[getSipCallId(session)];
|
|
518
530
|
// Check if Invitation or Inviter (Invitation = incoming call)
|
|
519
531
|
const isInviter = session instanceof Inviter;
|
|
520
532
|
// @see github.com/onsip/SIP.js/blob/f11dfd584bc9788ccfc94e03034020672b738975/src/platform/web/simple-user/simple-user.ts#L1004
|
|
@@ -536,7 +548,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
536
548
|
}
|
|
537
549
|
// Fetch and emit an event at `interval` with session network stats
|
|
538
550
|
startNetworkMonitoring(session, interval = 1000) {
|
|
539
|
-
const sessionId =
|
|
551
|
+
const sessionId = getSipCallId(session);
|
|
540
552
|
logger.info('starting network inspection', {
|
|
541
553
|
id: sessionId,
|
|
542
554
|
clientId: this.clientId,
|
|
@@ -545,7 +557,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
545
557
|
this.networkMonitoringInterval[sessionId] = setInterval(() => this._fetchNetworkStats(sessionId), interval);
|
|
546
558
|
}
|
|
547
559
|
stopNetworkMonitoring(session) {
|
|
548
|
-
const sessionId =
|
|
560
|
+
const sessionId = getSipCallId(session);
|
|
549
561
|
const exists = (sessionId in this.networkMonitoringInterval);
|
|
550
562
|
logger.info('stopping network inspection', {
|
|
551
563
|
clientId: this.clientId,
|
|
@@ -561,7 +573,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
561
573
|
async reject(session) {
|
|
562
574
|
logger.info('sdk webrtc reject call', {
|
|
563
575
|
clientId: this.clientId,
|
|
564
|
-
id: session
|
|
576
|
+
id: getSipCallId(session),
|
|
565
577
|
});
|
|
566
578
|
try {
|
|
567
579
|
if (session instanceof Invitation) {
|
|
@@ -615,13 +627,13 @@ export default class WebRTCClient extends Emitter {
|
|
|
615
627
|
}
|
|
616
628
|
mute(session) {
|
|
617
629
|
logger.info('sdk webrtc mute', {
|
|
618
|
-
id: session
|
|
630
|
+
id: getSipCallId(session),
|
|
619
631
|
});
|
|
620
632
|
toggleAudio(session, true);
|
|
621
633
|
}
|
|
622
634
|
unmute(session) {
|
|
623
635
|
logger.info('sdk webrtc unmute', {
|
|
624
|
-
id: session
|
|
636
|
+
id: getSipCallId(session),
|
|
625
637
|
});
|
|
626
638
|
toggleAudio(session, false);
|
|
627
639
|
}
|
|
@@ -658,18 +670,18 @@ export default class WebRTCClient extends Emitter {
|
|
|
658
670
|
}
|
|
659
671
|
toggleCameraOn(session) {
|
|
660
672
|
logger.info('sdk webrtc toggle camera on', {
|
|
661
|
-
id: session
|
|
673
|
+
id: getSipCallId(session),
|
|
662
674
|
});
|
|
663
675
|
toggleVideo(session, false);
|
|
664
676
|
}
|
|
665
677
|
toggleCameraOff(session) {
|
|
666
678
|
logger.info('sdk webrtc toggle camera off', {
|
|
667
|
-
id: session
|
|
679
|
+
id: getSipCallId(session),
|
|
668
680
|
});
|
|
669
681
|
toggleVideo(session, true);
|
|
670
682
|
}
|
|
671
683
|
hold(session, isConference = false, hadVideo = false) {
|
|
672
|
-
const sessionId =
|
|
684
|
+
const sessionId = getSipCallId(session);
|
|
673
685
|
const hasVideo = hadVideo || this.hasLocalVideo(sessionId);
|
|
674
686
|
logger.info('sdk webrtc hold', {
|
|
675
687
|
sessionId,
|
|
@@ -717,7 +729,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
717
729
|
});
|
|
718
730
|
}
|
|
719
731
|
unhold(session, isConference = false) {
|
|
720
|
-
const sessionId =
|
|
732
|
+
const sessionId = getSipCallId(session);
|
|
721
733
|
const hasVideo = sessionId in this.heldSessions && this.heldSessions[sessionId].hasVideo;
|
|
722
734
|
logger.info('sdk webrtc unhold', {
|
|
723
735
|
sessionId,
|
|
@@ -732,7 +744,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
732
744
|
return Promise.resolve();
|
|
733
745
|
}
|
|
734
746
|
this.unmute(session);
|
|
735
|
-
delete this.heldSessions[
|
|
747
|
+
delete this.heldSessions[getSipCallId(session)];
|
|
736
748
|
session.sessionDescriptionHandlerOptionsReInvite = {
|
|
737
749
|
hold: false,
|
|
738
750
|
conference: isConference,
|
|
@@ -757,7 +769,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
757
769
|
return this.heldSessions[sessionId];
|
|
758
770
|
}
|
|
759
771
|
isCallHeld(session) {
|
|
760
|
-
return
|
|
772
|
+
return getSipCallId(session) in this.heldSessions;
|
|
761
773
|
}
|
|
762
774
|
isVideoRemotelyHeld(sessionId) {
|
|
763
775
|
return isVideoRemotelyHeld(this.heldSessions[sessionId]);
|
|
@@ -767,7 +779,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
767
779
|
return false;
|
|
768
780
|
}
|
|
769
781
|
logger.info('Sending DTMF', {
|
|
770
|
-
id:
|
|
782
|
+
id: getSipCallId(session),
|
|
771
783
|
tone,
|
|
772
784
|
});
|
|
773
785
|
return session.sessionDescriptionHandler.sendDtmf(tone);
|
|
@@ -784,7 +796,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
784
796
|
transfer(session, target) {
|
|
785
797
|
this.hold(session);
|
|
786
798
|
logger.info('Transfering a session', {
|
|
787
|
-
id:
|
|
799
|
+
id: getSipCallId(session),
|
|
788
800
|
target,
|
|
789
801
|
});
|
|
790
802
|
const options = {
|
|
@@ -807,21 +819,21 @@ export default class WebRTCClient extends Emitter {
|
|
|
807
819
|
atxfer(session) {
|
|
808
820
|
this.hold(session);
|
|
809
821
|
logger.info('webrtc transfer started', {
|
|
810
|
-
id:
|
|
822
|
+
id: getSipCallId(session),
|
|
811
823
|
});
|
|
812
824
|
const result = {
|
|
813
825
|
newSession: null,
|
|
814
826
|
init: async (target) => {
|
|
815
827
|
logger.info('webrtc transfer initialized', {
|
|
816
|
-
id:
|
|
828
|
+
id: getSipCallId(session),
|
|
817
829
|
target,
|
|
818
830
|
});
|
|
819
831
|
result.newSession = await this.call(target);
|
|
820
832
|
},
|
|
821
833
|
complete: () => {
|
|
822
834
|
logger.info('webrtc transfer completed', {
|
|
823
|
-
id:
|
|
824
|
-
referId:
|
|
835
|
+
id: getSipCallId(session),
|
|
836
|
+
referId: getSipCallId(result.newSession),
|
|
825
837
|
});
|
|
826
838
|
session.refer(result.newSession);
|
|
827
839
|
},
|
|
@@ -838,7 +850,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
838
850
|
return;
|
|
839
851
|
}
|
|
840
852
|
logger.info('send WebRTC message', {
|
|
841
|
-
sipId: sipSession
|
|
853
|
+
sipId: getSipCallId(sipSession),
|
|
842
854
|
contentType,
|
|
843
855
|
});
|
|
844
856
|
try {
|
|
@@ -988,7 +1000,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
988
1000
|
}
|
|
989
1001
|
const sdh = session.sessionDescriptionHandler;
|
|
990
1002
|
const pc = sdh.peerConnection;
|
|
991
|
-
const sessionId =
|
|
1003
|
+
const sessionId = getSipCallId(session);
|
|
992
1004
|
const localStream = this.getLocalStream(sessionId);
|
|
993
1005
|
logger.info('changing video input device', {
|
|
994
1006
|
id,
|
|
@@ -1049,7 +1061,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1049
1061
|
const desktop = newConstraints && newConstraints.desktop;
|
|
1050
1062
|
logger.info('Sending reinvite', {
|
|
1051
1063
|
clientId: this.clientId,
|
|
1052
|
-
id:
|
|
1064
|
+
id: getSipCallId(sipSession),
|
|
1053
1065
|
newConstraints,
|
|
1054
1066
|
conference,
|
|
1055
1067
|
audioOnly,
|
|
@@ -1083,7 +1095,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1083
1095
|
sipSession.incomingInviteRequest.message.body = response.message.body;
|
|
1084
1096
|
}
|
|
1085
1097
|
logger.info('on re-INVITE accepted', {
|
|
1086
|
-
id:
|
|
1098
|
+
id: getSipCallId(sipSession),
|
|
1087
1099
|
wasMuted,
|
|
1088
1100
|
shouldDoScreenSharing,
|
|
1089
1101
|
});
|
|
@@ -1194,7 +1206,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1194
1206
|
}
|
|
1195
1207
|
onCallEnded(session) {
|
|
1196
1208
|
this._cleanupMedia(session);
|
|
1197
|
-
delete this.sipSessions[
|
|
1209
|
+
delete this.sipSessions[getSipCallId(session)];
|
|
1198
1210
|
this._stopSendingStats(session);
|
|
1199
1211
|
this.stopNetworkMonitoring(session);
|
|
1200
1212
|
}
|
|
@@ -1207,14 +1219,14 @@ export default class WebRTCClient extends Emitter {
|
|
|
1207
1219
|
this.userAgent.attemptReconnection();
|
|
1208
1220
|
}
|
|
1209
1221
|
storeSipSession(session) {
|
|
1210
|
-
const id =
|
|
1222
|
+
const id = getSipCallId(session);
|
|
1211
1223
|
logger.info('storing sip session', { id, clientId: this.clientId });
|
|
1212
1224
|
this.sipSessions[id] = session;
|
|
1213
1225
|
}
|
|
1214
1226
|
getSipSession(id) {
|
|
1215
|
-
return id in this.sipSessions ? this.sipSessions[id
|
|
1227
|
+
return id in this.sipSessions ? this.sipSessions[id] : null;
|
|
1216
1228
|
}
|
|
1217
|
-
|
|
1229
|
+
getSipCallIds() {
|
|
1218
1230
|
return Object.keys(this.sipSessions);
|
|
1219
1231
|
}
|
|
1220
1232
|
async updateLocalStream(sipSessionId, newStream) {
|
|
@@ -1253,8 +1265,8 @@ export default class WebRTCClient extends Emitter {
|
|
|
1253
1265
|
audio.autoplay = true;
|
|
1254
1266
|
return audio;
|
|
1255
1267
|
}
|
|
1256
|
-
_onTransportError() {
|
|
1257
|
-
logger.
|
|
1268
|
+
_onTransportError(reason) {
|
|
1269
|
+
logger.warn('on transport error', { reason });
|
|
1258
1270
|
this.eventEmitter.emit(TRANSPORT_ERROR);
|
|
1259
1271
|
this.attemptReconnection();
|
|
1260
1272
|
}
|
|
@@ -1307,7 +1319,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1307
1319
|
}
|
|
1308
1320
|
}
|
|
1309
1321
|
// We can invoke disconnect() with an error that can be catcher by `onDisconnect`, so we have to trigger it here.
|
|
1310
|
-
this._onTransportError();
|
|
1322
|
+
this._onTransportError('heartbeat timeout');
|
|
1311
1323
|
}
|
|
1312
1324
|
}
|
|
1313
1325
|
_hasAudio() {
|
|
@@ -1369,7 +1381,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1369
1381
|
}
|
|
1370
1382
|
// Invitation and Inviter extends Session
|
|
1371
1383
|
_setupSession(session) {
|
|
1372
|
-
const sipSessionId =
|
|
1384
|
+
const sipSessionId = getSipCallId(session);
|
|
1373
1385
|
// When receiving an Invitation, the delegate is not defined.
|
|
1374
1386
|
if (!session.delegate) {
|
|
1375
1387
|
session.delegate = {};
|
|
@@ -1432,17 +1444,14 @@ export default class WebRTCClient extends Emitter {
|
|
|
1432
1444
|
}
|
|
1433
1445
|
async _onProgress(session, early = false) {
|
|
1434
1446
|
await this._setupMedias(session);
|
|
1435
|
-
const sessionId =
|
|
1447
|
+
const sessionId = getSipCallId(session);
|
|
1436
1448
|
updateRemoteStream(session);
|
|
1437
|
-
logger.info('progress received', {
|
|
1438
|
-
sessionId,
|
|
1439
|
-
early,
|
|
1440
|
-
});
|
|
1449
|
+
logger.info('progress received', { sessionId, early });
|
|
1441
1450
|
this.eventEmitter.emit(early ? ON_EARLY_MEDIA : ON_PROGRESS, session);
|
|
1442
1451
|
}
|
|
1443
1452
|
async _onAccepted(session, sessionDialog, withEvent = true, initAllTracks = true) {
|
|
1444
1453
|
logger.info('on call accepted', {
|
|
1445
|
-
id: session
|
|
1454
|
+
id: getSipCallId(session),
|
|
1446
1455
|
clientId: this.clientId,
|
|
1447
1456
|
remoteTag: session.remoteTag,
|
|
1448
1457
|
});
|
|
@@ -1486,7 +1495,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1486
1495
|
return;
|
|
1487
1496
|
}
|
|
1488
1497
|
// Safari hack, because you cannot call .play() from a non user action
|
|
1489
|
-
const sessionId =
|
|
1498
|
+
const sessionId = getSipCallId(session);
|
|
1490
1499
|
const isConference = this.isConference(sessionId);
|
|
1491
1500
|
if (sessionId in this.audioElements) {
|
|
1492
1501
|
logger.info('html element already exists for session', {
|
|
@@ -1531,7 +1540,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1531
1540
|
audioElement.play().catch(() => { });
|
|
1532
1541
|
}
|
|
1533
1542
|
_cleanupMedia(session) {
|
|
1534
|
-
const sessionId =
|
|
1543
|
+
const sessionId = getSipCallId(session);
|
|
1535
1544
|
const localStream = this.getLocalStream(sessionId);
|
|
1536
1545
|
if (localStream) {
|
|
1537
1546
|
cleanupStream(localStream);
|
|
@@ -1550,7 +1559,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1550
1559
|
};
|
|
1551
1560
|
if (this._hasAudio() && isWeb()) {
|
|
1552
1561
|
if (session) {
|
|
1553
|
-
cleanLocalElement(
|
|
1562
|
+
cleanLocalElement(getSipCallId(session));
|
|
1554
1563
|
}
|
|
1555
1564
|
else {
|
|
1556
1565
|
Object.keys(this.audioElements).forEach(id => cleanLocalElement(id));
|
|
@@ -1570,7 +1579,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1570
1579
|
if (!pc) {
|
|
1571
1580
|
return;
|
|
1572
1581
|
}
|
|
1573
|
-
const sessionId =
|
|
1582
|
+
const sessionId = getSipCallId(session);
|
|
1574
1583
|
getStats(pc, (result) => {
|
|
1575
1584
|
const { results, internal, nomore, ...stats } = result;
|
|
1576
1585
|
this.statsIntervals[sessionId] = nomore;
|
|
@@ -1581,7 +1590,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1581
1590
|
}, SEND_STATS_DELAY);
|
|
1582
1591
|
}
|
|
1583
1592
|
_stopSendingStats(session) {
|
|
1584
|
-
const sessionId =
|
|
1593
|
+
const sessionId = getSipCallId(session);
|
|
1585
1594
|
logger.trace('Check for stopping stats', {
|
|
1586
1595
|
sessionId,
|
|
1587
1596
|
ids: Object.keys(this.statsIntervals),
|
|
@@ -1632,18 +1641,18 @@ export default class WebRTCClient extends Emitter {
|
|
|
1632
1641
|
async _accept(session, options = {}) {
|
|
1633
1642
|
if (session.state === SessionState.Terminated || session.state === SessionState.Terminating) {
|
|
1634
1643
|
const error = 'Trying to accept a terminated sipSession.';
|
|
1635
|
-
logger.warn(error, { state: session.state, sessionId: session
|
|
1644
|
+
logger.warn(error, { state: session.state, sessionId: getSipCallId(session) });
|
|
1636
1645
|
throw new Error(error);
|
|
1637
1646
|
}
|
|
1638
1647
|
if (session.state !== SessionState.Initial) {
|
|
1639
1648
|
const error = 'Trying to accept a non Initial sipSession.';
|
|
1640
|
-
logger.warn(error, { state: session.state, sessionId: session
|
|
1649
|
+
logger.warn(error, { state: session.state, sessionId: getSipCallId(session) });
|
|
1641
1650
|
throw new Error(error);
|
|
1642
1651
|
}
|
|
1643
1652
|
// @ts-ignore: private
|
|
1644
1653
|
if (!session.incomingInviteRequest.acceptable) {
|
|
1645
1654
|
const error = 'Trying to reject a non `acceptable` session';
|
|
1646
|
-
logger.warn(error, { state: session.state, sessionId: session
|
|
1655
|
+
logger.warn(error, { state: session.state, sessionId: getSipCallId(session) });
|
|
1647
1656
|
throw new Error(error);
|
|
1648
1657
|
}
|
|
1649
1658
|
try {
|
|
@@ -1655,12 +1664,12 @@ export default class WebRTCClient extends Emitter {
|
|
|
1655
1664
|
}
|
|
1656
1665
|
async _reject(session, options = {}) {
|
|
1657
1666
|
if (session.state !== SessionState.Initial && session.state !== SessionState.Establishing) {
|
|
1658
|
-
logger.warn('Trying to reject a session in a wrong state', { state: session.state, sessionId: session
|
|
1667
|
+
logger.warn('Trying to reject a session in a wrong state', { state: session.state, sessionId: getSipCallId(session) });
|
|
1659
1668
|
return;
|
|
1660
1669
|
}
|
|
1661
1670
|
// @ts-ignore: private
|
|
1662
1671
|
if (!session.incomingInviteRequest.rejectable) {
|
|
1663
|
-
logger.warn('Trying to reject a non `rejectable` session', { state: session.state, sessionId: session
|
|
1672
|
+
logger.warn('Trying to reject a non `rejectable` session', { state: session.state, sessionId: getSipCallId(session) });
|
|
1664
1673
|
return;
|
|
1665
1674
|
}
|
|
1666
1675
|
try {
|
|
@@ -1672,7 +1681,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1672
1681
|
}
|
|
1673
1682
|
async _cancel(session, options = {}) {
|
|
1674
1683
|
if (session.state !== SessionState.Initial && session.state !== SessionState.Establishing) {
|
|
1675
|
-
logger.warn('Trying to cancel a session in a wrong state', { state: session.state, sessionId: session
|
|
1684
|
+
logger.warn('Trying to cancel a session in a wrong state', { state: session.state, sessionId: getSipCallId(session) });
|
|
1676
1685
|
return;
|
|
1677
1686
|
}
|
|
1678
1687
|
try {
|
|
@@ -1684,7 +1693,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1684
1693
|
}
|
|
1685
1694
|
async _bye(session, options = {}) {
|
|
1686
1695
|
if (session.state !== SessionState.Established) {
|
|
1687
|
-
logger.warn('Trying to end a session in a wrong state', { state: session.state, sessionId: session
|
|
1696
|
+
logger.warn('Trying to end a session in a wrong state', { state: session.state, sessionId: getSipCallId(session) });
|
|
1688
1697
|
return null;
|
|
1689
1698
|
}
|
|
1690
1699
|
try {
|
|
@@ -41,6 +41,9 @@ jest.mock('../..', () => ({
|
|
|
41
41
|
}));
|
|
42
42
|
jest.mock('../../web-rtc-client', () => jest.fn().mockImplementation(() => ({
|
|
43
43
|
answer: jest.fn(() => Promise.resolve()),
|
|
44
|
+
mute: jest.fn(() => Promise.resolve()),
|
|
45
|
+
hold: jest.fn(() => Promise.resolve()),
|
|
46
|
+
unhold: jest.fn(() => Promise.resolve()),
|
|
44
47
|
hangup: jest.fn(() => Promise.resolve()),
|
|
45
48
|
register: jest.fn(() => Promise.resolve()),
|
|
46
49
|
onCallEnded: jest.fn(() => Promise.resolve()),
|
|
@@ -80,9 +83,17 @@ describe('Call', () => {
|
|
|
80
83
|
expect(call.id).toBe(apiCall.sipCallId);
|
|
81
84
|
expect(call.apiId).toBe(apiCall.id);
|
|
82
85
|
expect(call.number).toBe(apiCall.calleeNumber);
|
|
83
|
-
expect(call.answerTime).toStrictEqual(
|
|
86
|
+
expect(call.answerTime).toStrictEqual(undefined);
|
|
87
|
+
expect(call.creationTime).toStrictEqual(apiCall.startingTime);
|
|
84
88
|
expect(call.isMuted()).toBeTruthy();
|
|
85
|
-
expect(call.state).toStrictEqual({
|
|
89
|
+
expect(call.state).toStrictEqual({
|
|
90
|
+
[call_state_machine_1.States.ESTABLISHED]: {
|
|
91
|
+
[call_state_machine_1.EstablishedStates.ONGOING]: {},
|
|
92
|
+
[call_state_machine_1.EstablishedSubStates.MUTE]: call_state_machine_1.EstablishedStates.MUTED,
|
|
93
|
+
[call_state_machine_1.EstablishedSubStates.HOLD]: call_state_machine_1.EstablishedStates.UN_HELD,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
expect(call.isEstablished()).toBeTruthy();
|
|
86
97
|
}));
|
|
87
98
|
});
|
|
88
99
|
describe('accept', () => {
|
|
@@ -125,4 +136,42 @@ describe('Call', () => {
|
|
|
125
136
|
expect(softphone_1.default.client.hangup).toHaveBeenCalled();
|
|
126
137
|
}));
|
|
127
138
|
});
|
|
139
|
+
describe('state propagation', () => {
|
|
140
|
+
it('Should update the call state in events', (done) => {
|
|
141
|
+
const call = new call_1.default(sipCall, softphone_1.default);
|
|
142
|
+
// @ts-ignore: private method
|
|
143
|
+
call._sendAction(call_state_machine_1.Actions.MAKE_CALL);
|
|
144
|
+
call.on('remotelyAccepted', () => {
|
|
145
|
+
expect(call.state).toStrictEqual({
|
|
146
|
+
[call_state_machine_1.States.ESTABLISHED]: {
|
|
147
|
+
[call_state_machine_1.EstablishedStates.ONGOING]: {},
|
|
148
|
+
[call_state_machine_1.EstablishedSubStates.MUTE]: call_state_machine_1.EstablishedStates.UN_MUTED,
|
|
149
|
+
[call_state_machine_1.EstablishedSubStates.HOLD]: call_state_machine_1.EstablishedStates.UN_HELD,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
done();
|
|
153
|
+
});
|
|
154
|
+
call.onAccepted();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe('Multiple sub state', () => {
|
|
158
|
+
it('Should mute and hold a call', () => {
|
|
159
|
+
const call = new call_1.default(sipCall, softphone_1.default);
|
|
160
|
+
// @ts-ignore: private method
|
|
161
|
+
call._sendAction(call_state_machine_1.Actions.MAKE_CALL);
|
|
162
|
+
expect(call.isMuted()).toBeFalsy();
|
|
163
|
+
expect(call.isHeld()).toBeFalsy();
|
|
164
|
+
// @ts-ignore: private method
|
|
165
|
+
call._sendAction(call_state_machine_1.Actions.REMOTLY_ACCEPTED);
|
|
166
|
+
call.mute();
|
|
167
|
+
expect(call.isMuted()).toBeTruthy();
|
|
168
|
+
expect(call.isHeld()).toBeFalsy();
|
|
169
|
+
call.hold();
|
|
170
|
+
expect(call.isMuted()).toBeTruthy();
|
|
171
|
+
expect(call.isHeld()).toBeTruthy();
|
|
172
|
+
call.resume();
|
|
173
|
+
expect(call.isMuted()).toBeTruthy();
|
|
174
|
+
expect(call.isHeld()).toBeFalsy();
|
|
175
|
+
});
|
|
176
|
+
});
|
|
128
177
|
});
|
package/lib/api/auth.js
CHANGED
|
@@ -64,6 +64,9 @@ exports.default = ((client, baseUrl) => ({
|
|
|
64
64
|
}
|
|
65
65
|
return client.post(`${baseUrl}/token`, body, headers).then(Session_1.default.parse);
|
|
66
66
|
}),
|
|
67
|
+
samlLogOut() {
|
|
68
|
+
return client.get(`${baseUrl}/saml/logout`, null, null);
|
|
69
|
+
},
|
|
67
70
|
initiateIdpAuthentication: (domain, redirectUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
68
71
|
const body = {
|
|
69
72
|
domain,
|
|
@@ -43,7 +43,7 @@ exports.default = {
|
|
|
43
43
|
});
|
|
44
44
|
client.on(client.REGISTERED, () => {
|
|
45
45
|
const sipSession = client.call('*10');
|
|
46
|
-
if (!sipSession || !(0, sdp_1.
|
|
46
|
+
if (!sipSession || !(0, sdp_1.getSipCallId)(sipSession)) {
|
|
47
47
|
return handleError('Unable to make call through WebRTC');
|
|
48
48
|
}
|
|
49
49
|
setTimeout(() => {
|
package/lib/domain/CallLog.js
CHANGED
|
@@ -46,8 +46,7 @@ class CallLog {
|
|
|
46
46
|
}
|
|
47
47
|
static parseNew(plain, session) {
|
|
48
48
|
const callLog = CallLog.parse(plain);
|
|
49
|
-
|
|
50
|
-
callLog.newMissedCall = session && session.hasExtension((plain.requested_extension || plain.destination_extension)) && !plain.answered;
|
|
49
|
+
callLog.newMissedCall = session && plain.destination_user_uuid === session.uuid && !plain.answered;
|
|
51
50
|
return callLog;
|
|
52
51
|
}
|
|
53
52
|
static newFrom(profile) {
|
|
@@ -105,7 +104,7 @@ class CallLog {
|
|
|
105
104
|
return this.callDirection === 'inbound';
|
|
106
105
|
}
|
|
107
106
|
isAnOutgoingCall(session) {
|
|
108
|
-
console.warn(`@wazo/sdk
|
|
107
|
+
console.warn(`@wazo/sdk
|
|
109
108
|
CallLog.isAnOutgoingcall(session) method is obsolete.
|
|
110
109
|
Please use CallLog.isOutgoing(session).
|
|
111
110
|
`);
|
|
@@ -119,7 +119,7 @@ class CTIPhone extends Emitter_1.default {
|
|
|
119
119
|
number: callSession.number,
|
|
120
120
|
});
|
|
121
121
|
try {
|
|
122
|
-
yield CallApi_1.default.cancelCall(callSession);
|
|
122
|
+
yield CallApi_1.default.cancelCall({ apiId: callSession.getId() });
|
|
123
123
|
if (this.currentCall && callSession.callId === this.currentCall.id) {
|
|
124
124
|
this.endCurrentCall(callSession);
|
|
125
125
|
}
|
|
@@ -143,7 +143,7 @@ class CTIPhone extends Emitter_1.default {
|
|
|
143
143
|
callId: callSession.getId(),
|
|
144
144
|
number: callSession.number,
|
|
145
145
|
});
|
|
146
|
-
yield CallApi_1.default.cancelCall(callSession);
|
|
146
|
+
yield CallApi_1.default.cancelCall({ id: callSession.getId() });
|
|
147
147
|
this.eventEmitter.emit('onCallEnded', callSession);
|
|
148
148
|
});
|
|
149
149
|
}
|