@wazo/sdk 1.0.0-alpha.1 → 1.0.0-alpha.11
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 +6 -6
- package/esm/__tests__/__voice__/call.test.js +57 -2
- 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 +64 -63
- 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 +6 -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 +2 -2
- 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/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 +2 -2
- package/esm/types/state-machine/utils.d.ts.map +1 -1
- package/esm/types/utils/sdp.d.ts +3 -2
- package/esm/types/utils/sdp.d.ts.map +1 -1
- package/esm/types/utils/webrtc.d.ts +1 -0
- package/esm/types/utils/webrtc.d.ts.map +1 -1
- package/esm/types/voice/call.d.ts +30 -12
- package/esm/types/voice/call.d.ts.map +1 -1
- package/esm/types/voice/softphone.d.ts +25 -13
- 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 +22 -9
- package/esm/utils/webrtc.js +23 -3
- package/esm/voice/call.js +131 -38
- package/esm/voice/softphone.js +145 -35
- package/esm/web-rtc-client.js +61 -58
- package/lib/__tests__/__voice__/call.test.js +56 -1
- 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 +63 -62
- 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 +3 -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 +2 -2
- 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/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 +2 -2
- package/lib/types/state-machine/utils.d.ts.map +1 -1
- package/lib/types/utils/sdp.d.ts +3 -2
- package/lib/types/utils/sdp.d.ts.map +1 -1
- package/lib/types/utils/webrtc.d.ts +1 -0
- package/lib/types/utils/webrtc.d.ts.map +1 -1
- package/lib/types/voice/call.d.ts +30 -12
- package/lib/types/voice/call.d.ts.map +1 -1
- package/lib/types/voice/softphone.d.ts +25 -13
- 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 +25 -10
- package/lib/utils/webrtc.js +24 -3
- package/lib/voice/call.js +132 -36
- package/lib/voice/softphone.js +150 -35
- package/lib/web-rtc-client.js +59 -57
- package/package.json +1 -1
- package/src/__tests__/__voice__/call.test.ts +63 -2
- 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 +95 -93
- 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 +12 -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 +2 -2
- package/src/state-machine/softphone-state-machine.ts +1 -2
- package/src/state-machine/utils.ts +14 -6
- package/src/utils/sdp.ts +26 -11
- package/src/utils/webrtc.ts +26 -4
- package/src/voice/call.ts +170 -50
- package/src/voice/softphone.ts +180 -41
- package/src/web-rtc-client.ts +106 -99
package/src/voice/softphone.ts
CHANGED
|
@@ -10,21 +10,26 @@ import InvalidState from '../domain/InvalidState';
|
|
|
10
10
|
|
|
11
11
|
import Wazo from '..';
|
|
12
12
|
import softphoneStateMachine, { type SoftphoneActorRef, Actions, type StateTypes, States, ActionTypes } from '../state-machine/softphone-state-machine';
|
|
13
|
-
import { Actions as CallActions } from '../state-machine/call-state-machine';
|
|
14
13
|
import { WebRtcConfig, SipCall } from '../domain/types';
|
|
15
14
|
import WazoWebRTCClient from '../web-rtc-client';
|
|
16
15
|
import IssueReporter from '../service/IssueReporter';
|
|
17
16
|
import configureLogger from '../utils/sip-logger';
|
|
18
17
|
import Call from './call';
|
|
19
18
|
import { assertCan, can, getState, waitUntilState } from '../state-machine/utils';
|
|
19
|
+
import { getSipCallId } from '../utils/sdp';
|
|
20
20
|
|
|
21
21
|
export const EVENT_INCOMING = 'incoming';
|
|
22
|
+
export const EVENT_OUTGOING = 'outgoing';
|
|
22
23
|
export const EVENT_HEARTBEAT = 'heartbeat';
|
|
23
24
|
export const EVENT_HEARTBEAT_TIMEOUT = 'heartbeatTimeout';
|
|
24
25
|
export const EVENT_REGISTERED = 'registered';
|
|
25
26
|
export const EVENT_UNREGISTERED = 'unregistered';
|
|
26
27
|
export const EVENT_DISCONNECTED = 'disconnected';
|
|
27
28
|
export const EVENT_VIDEO_INPUT_CHANGE = 'videoInputChange';
|
|
29
|
+
export const EVENT_TERMINATE_SOUND = 'terminateSound';
|
|
30
|
+
export const EVENT_PLAY_HANGUP_SOUND = 'playHangupSound';
|
|
31
|
+
export const EVENT_PLAY_RING_SOUND = 'playRingSound';
|
|
32
|
+
export const EVENT_PLAY_INBOUND_CALL_SOUND = 'playInboundCallSound';
|
|
28
33
|
export const EVENT_ON_MESSAGE = 'message';
|
|
29
34
|
export const EVENT_ON_CHAT = 'phone/ON_CHAT';
|
|
30
35
|
export const EVENT_ON_SIGNAL = 'phone/ON_SIGNAL';
|
|
@@ -40,6 +45,7 @@ export type CallOptions = {
|
|
|
40
45
|
// If audioOnly is set to true, all video stream will be deactivated, even remotes ones.
|
|
41
46
|
audioOnly?: boolean,
|
|
42
47
|
conference?: boolean,
|
|
48
|
+
extraHeaders?: Record<string, any>,
|
|
43
49
|
};
|
|
44
50
|
|
|
45
51
|
const logger = IssueReporter.loggerFor('softphone');
|
|
@@ -53,8 +59,6 @@ export class Softphone extends EventEmitter {
|
|
|
53
59
|
|
|
54
60
|
audioRingVolume: number;
|
|
55
61
|
|
|
56
|
-
eventEmitter: EventEmitter;
|
|
57
|
-
|
|
58
62
|
calls: Call[];
|
|
59
63
|
|
|
60
64
|
client: WazoWebRTCClient;
|
|
@@ -69,6 +73,8 @@ export class Softphone extends EventEmitter {
|
|
|
69
73
|
|
|
70
74
|
shouldSendReinvite: boolean;
|
|
71
75
|
|
|
76
|
+
ringingEnabled = true;
|
|
77
|
+
|
|
72
78
|
constructor() {
|
|
73
79
|
super();
|
|
74
80
|
|
|
@@ -87,6 +93,8 @@ export class Softphone extends EventEmitter {
|
|
|
87
93
|
const server = Wazo.Auth.getHost();
|
|
88
94
|
const session = Wazo.Auth.getSession();
|
|
89
95
|
|
|
96
|
+
logger.info('softphone - connect', { server, session: !!session });
|
|
97
|
+
|
|
90
98
|
if (!server || !session) {
|
|
91
99
|
throw new Error('Please connect to the server using `Wazo.Auth.logIn` or `Wazo.Auth.authenticate` before using Room.connect().');
|
|
92
100
|
}
|
|
@@ -103,14 +111,19 @@ export class Softphone extends EventEmitter {
|
|
|
103
111
|
return this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
|
|
104
112
|
}
|
|
105
113
|
|
|
114
|
+
async hangupAllCalls() {
|
|
115
|
+
return Promise.all(this.calls.map(call => call.hangup()));
|
|
116
|
+
}
|
|
117
|
+
|
|
106
118
|
async disconnect() {
|
|
107
119
|
assertCan(this.softphoneActor, Actions.UNREGISTER);
|
|
108
120
|
if (!this.client) {
|
|
121
|
+
logger.info('softphone - disconnect, not client to disconnect, bailing');
|
|
109
122
|
return null;
|
|
110
123
|
}
|
|
111
124
|
|
|
112
125
|
// Terminate all calls
|
|
113
|
-
await
|
|
126
|
+
await this.hangupAllCalls();
|
|
114
127
|
|
|
115
128
|
return this.client.unregister();
|
|
116
129
|
}
|
|
@@ -127,7 +140,9 @@ export class Softphone extends EventEmitter {
|
|
|
127
140
|
): Promise<void> {
|
|
128
141
|
assertCan(this.softphoneActor, Actions.REGISTER);
|
|
129
142
|
|
|
130
|
-
|
|
143
|
+
logger.info('softphone - connect with credentials', { server, username: sipLine.username, displayName, options: rawOptions });
|
|
144
|
+
|
|
145
|
+
this._sendAction(Actions.REGISTER);
|
|
131
146
|
|
|
132
147
|
const [host, port = 443] = server.split(':');
|
|
133
148
|
let options = { ...rawOptions };
|
|
@@ -179,16 +194,16 @@ export class Softphone extends EventEmitter {
|
|
|
179
194
|
return Promise.resolve(null);
|
|
180
195
|
}
|
|
181
196
|
|
|
182
|
-
if (this.
|
|
183
|
-
throw new InvalidState(`Invalid state ${States.UNREGISTERED}`, States.UNREGISTERED);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (this.getState() !== States.REGISTERING) {
|
|
197
|
+
if (this.state === States.REGISTERING) {
|
|
187
198
|
logger.info('softphone - calling when registering, waiting for Softphone to be registered ...');
|
|
188
199
|
|
|
189
200
|
await waitUntilState(this.softphoneActor, States.REGISTERED);
|
|
190
201
|
}
|
|
191
202
|
|
|
203
|
+
if (this.state !== States.REGISTERED) {
|
|
204
|
+
throw new InvalidState(`Invalid state ${States.UNREGISTERED}`, States.UNREGISTERED);
|
|
205
|
+
}
|
|
206
|
+
|
|
192
207
|
// Hold other calls
|
|
193
208
|
this.holdAllCalls();
|
|
194
209
|
|
|
@@ -197,6 +212,10 @@ export class Softphone extends EventEmitter {
|
|
|
197
212
|
try {
|
|
198
213
|
sipCall = this.client.call(options.params.To, options.withCamera, options.audioOnly, options.conference, options) as SipCall;
|
|
199
214
|
const call = new Call(sipCall, this);
|
|
215
|
+
call.onMakeCall();
|
|
216
|
+
|
|
217
|
+
this.calls.push(call);
|
|
218
|
+
this.emit(EVENT_OUTGOING, call);
|
|
200
219
|
|
|
201
220
|
return call;
|
|
202
221
|
} catch (error: any) {
|
|
@@ -209,12 +228,77 @@ export class Softphone extends EventEmitter {
|
|
|
209
228
|
this.calls = this.calls.filter((call: Call) => call.id !== callToRemove.id);
|
|
210
229
|
}
|
|
211
230
|
|
|
231
|
+
onCallTerminated(call: Call) {
|
|
232
|
+
logger.info('softphone - on call terminated', { id: call.id });
|
|
233
|
+
|
|
234
|
+
const currentCall = this.getCurrentCall();
|
|
235
|
+
const isCurrentCall = currentCall?.id === call.id;
|
|
236
|
+
const isRinging = call.isRinging();
|
|
237
|
+
const isCurrentIncomingCall = isCurrentCall && isRinging;
|
|
238
|
+
const incomingCalls = this.getIncomingCalls();
|
|
239
|
+
const nbIncomingCalls = incomingCalls.length;
|
|
240
|
+
|
|
241
|
+
// Send an event to terminate ringing sound
|
|
242
|
+
if (isCurrentIncomingCall) {
|
|
243
|
+
setTimeout(() => {
|
|
244
|
+
// Avoid race condition when the other is calling and hanging up immediately
|
|
245
|
+
this.emit(EVENT_TERMINATE_SOUND, call, 'call terminated');
|
|
246
|
+
}, 5);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// If the terminated call was an incoming call, we have to re-trigger if it's was the first incoming call
|
|
250
|
+
// Otherwise, we have to re-trigger an incoming call event if another call is incoming
|
|
251
|
+
const shouldRetrigger = isCurrentCall ? nbIncomingCalls : isCurrentIncomingCall;
|
|
252
|
+
|
|
253
|
+
// Re-trigger incoming call event for remaining incoming calls
|
|
254
|
+
logger.info('Softphone - check to re-trigger incoming call', { shouldRetrigger, nbIncomingCalls });
|
|
255
|
+
|
|
256
|
+
if (shouldRetrigger && nbIncomingCalls > 1) {
|
|
257
|
+
const nextCall = incomingCalls.find(c => c.id !== call.id);
|
|
258
|
+
// Avoid race condition
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
if (this.ringingEnabled) {
|
|
261
|
+
if (currentCall) {
|
|
262
|
+
this.emit(EVENT_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, nextCall);
|
|
263
|
+
} else {
|
|
264
|
+
this.emit(EVENT_PLAY_INBOUND_CALL_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, nextCall);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.emit(EVENT_INCOMING, nextCall);
|
|
269
|
+
}, 100);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// @ts-ignore: does not exist
|
|
273
|
+
if (!call.sipCall.isCanceled) {
|
|
274
|
+
setTimeout(() => {
|
|
275
|
+
this.emit(EVENT_PLAY_HANGUP_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, call);
|
|
276
|
+
}, 10);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
this.client.onCallEnded(call.sipCall);
|
|
280
|
+
|
|
281
|
+
this.removeCall(call);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
enableRinging(): Promise<void> | void {
|
|
285
|
+
logger.info('softphone - enable ringing');
|
|
286
|
+
this.ringingEnabled = true;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
disableRinging(): Promise<void> | void {
|
|
290
|
+
logger.info('softphone - disable ringing');
|
|
291
|
+
this.ringingEnabled = false;
|
|
292
|
+
}
|
|
293
|
+
|
|
212
294
|
holdAllCalls(exceptCall: Call | null = null) {
|
|
213
|
-
|
|
295
|
+
logger.info('softphone - hold all calls', { exceptId: exceptCall?.id, ids: this.calls.map(call => call.id) });
|
|
296
|
+
|
|
297
|
+
this.calls.filter(call => !call.isHeld() && call.id !== exceptCall?.id).forEach(call => call.hold());
|
|
214
298
|
}
|
|
215
299
|
|
|
216
300
|
startHeartbeat() {
|
|
217
|
-
logger.info('softphone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client
|
|
301
|
+
logger.info('softphone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client?.hasHeartbeat() });
|
|
218
302
|
if (!this.client || this.client.hasHeartbeat()) {
|
|
219
303
|
return;
|
|
220
304
|
}
|
|
@@ -278,34 +362,64 @@ export class Softphone extends EventEmitter {
|
|
|
278
362
|
this.audioRingVolume = volume;
|
|
279
363
|
}
|
|
280
364
|
|
|
281
|
-
|
|
282
|
-
return this.
|
|
365
|
+
getCurrentCall(): Call | undefined {
|
|
366
|
+
return this.getActiveCalls()[0];
|
|
283
367
|
}
|
|
284
368
|
|
|
285
|
-
|
|
286
|
-
return this.calls.
|
|
369
|
+
getActiveCalls(): Call[] {
|
|
370
|
+
return this.calls.filter(call => call.isEstablished());
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
getIncomingCalls(): Call[] {
|
|
374
|
+
return this.calls.filter(call => call.isRinging());
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
get state(): StateTypes {
|
|
378
|
+
return getState(this.softphoneActor) as StateTypes;
|
|
287
379
|
}
|
|
288
380
|
|
|
289
|
-
|
|
290
|
-
return this.
|
|
381
|
+
get user() {
|
|
382
|
+
return this.client?.userAgent?.contact?.uri?.user;
|
|
291
383
|
}
|
|
292
384
|
|
|
293
385
|
getUserAgent() {
|
|
294
386
|
return this.client?.config?.userAgentString || 'softphone';
|
|
295
387
|
}
|
|
296
388
|
|
|
389
|
+
isRegistering() {
|
|
390
|
+
return this.state === States.REGISTERING;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
isRegistered() {
|
|
394
|
+
return this.state === States.REGISTERED;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
isUnRegistered() {
|
|
398
|
+
return this.state === States.UNREGISTERED;
|
|
399
|
+
}
|
|
400
|
+
|
|
297
401
|
_bindEvents(): void {
|
|
298
402
|
this.client.on(this.client.INVITE, (sipSession: SipCall) => {
|
|
299
403
|
const call = new Call(sipSession, this);
|
|
300
|
-
|
|
404
|
+
logger.info('softphone - on invite', { callId: call.id, number: call.number });
|
|
405
|
+
|
|
406
|
+
call.onCallIncoming();
|
|
301
407
|
this.calls.push(call);
|
|
302
408
|
|
|
303
|
-
this.
|
|
409
|
+
this.emit(EVENT_INCOMING, call);
|
|
410
|
+
|
|
411
|
+
if (!this.getCurrentCall()) {
|
|
412
|
+
if (this.ringingEnabled) {
|
|
413
|
+
this.emit(EVENT_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, call);
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
this.emit(EVENT_PLAY_INBOUND_CALL_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, call);
|
|
417
|
+
}
|
|
304
418
|
});
|
|
305
419
|
|
|
306
420
|
this.client.on(this.client.ON_REINVITE, (sipCall: SipCall, request: IncomingRequestMessage, updatedCalleeName: string, updatedNumber: string, hadRemoteVideo: boolean) => {
|
|
307
421
|
logger.info('softphone - on reinvite', {
|
|
308
|
-
callId: sipCall
|
|
422
|
+
callId: getSipCallId(sipCall),
|
|
309
423
|
inviteId: request.callId,
|
|
310
424
|
updatedCalleeName,
|
|
311
425
|
updatedNumber,
|
|
@@ -316,6 +430,9 @@ export class Softphone extends EventEmitter {
|
|
|
316
430
|
});
|
|
317
431
|
|
|
318
432
|
this.client.on(this.client.ACCEPTED, async (sipCall: SipCall) => {
|
|
433
|
+
const call = this._getCall(sipCall);
|
|
434
|
+
this.emit(EVENT_TERMINATE_SOUND, call, 'call accepted');
|
|
435
|
+
|
|
319
436
|
this._onCallEvent(sipCall, 'onAccepted');
|
|
320
437
|
|
|
321
438
|
if (this.audioOutputDeviceId) {
|
|
@@ -354,29 +471,39 @@ export class Softphone extends EventEmitter {
|
|
|
354
471
|
|
|
355
472
|
this.client.on(this.client.UNREGISTERED, () => {
|
|
356
473
|
logger.info('softphone - unregistered');
|
|
357
|
-
this.
|
|
474
|
+
if (!can(this.softphoneActor, Actions.UNREGISTER)) {
|
|
475
|
+
logger.warn('softphone - cannot unregister', { state: this.state });
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
358
478
|
|
|
359
|
-
this._sendAction(Actions.
|
|
479
|
+
this._sendAction(Actions.UNREGISTER);
|
|
480
|
+
|
|
481
|
+
this.emit(EVENT_UNREGISTERED);
|
|
360
482
|
});
|
|
361
483
|
|
|
362
484
|
this.client.on(this.client.ON_DISCONNECTED, () => {
|
|
363
485
|
logger.info('softphone - disconnected');
|
|
364
|
-
this.
|
|
486
|
+
if (!can(this.softphoneActor, Actions.TRANSPORT_CLOSED)) {
|
|
487
|
+
logger.warn('softphone - cannot disconnected', { state: this.state });
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
365
490
|
|
|
366
491
|
this._sendAction(Actions.TRANSPORT_CLOSED);
|
|
492
|
+
|
|
493
|
+
this.emit(EVENT_DISCONNECTED);
|
|
367
494
|
});
|
|
368
495
|
|
|
369
496
|
this.client.on(this.client.REGISTERED, () => {
|
|
370
497
|
logger.info('softphone - registered', { state: getState(this.softphoneActor) });
|
|
371
498
|
if (!can(this.softphoneActor, Actions.REGISTER_DONE)) {
|
|
372
|
-
logger.warn('softphone - registered but not in REGISTERING state', { state:
|
|
499
|
+
logger.warn('softphone - registered but not in REGISTERING state', { state: this.state });
|
|
373
500
|
return;
|
|
374
501
|
}
|
|
375
502
|
|
|
376
503
|
this.stopHeartbeat();
|
|
377
504
|
this._sendAction(Actions.REGISTER_DONE);
|
|
378
505
|
|
|
379
|
-
this.
|
|
506
|
+
this.emit(EVENT_REGISTERED);
|
|
380
507
|
|
|
381
508
|
// If the phone registered with a current callSession (eg: when switching network):
|
|
382
509
|
// send a reinvite to renegociate ICE with new IP
|
|
@@ -390,13 +517,19 @@ export class Softphone extends EventEmitter {
|
|
|
390
517
|
});
|
|
391
518
|
|
|
392
519
|
this.client.on(this.client.CONNECTED, () => {
|
|
393
|
-
logger.info('softphone - connected');
|
|
520
|
+
logger.info('softphone - connected', { state: this.state });
|
|
394
521
|
this.stopHeartbeat();
|
|
395
522
|
});
|
|
396
523
|
|
|
524
|
+
this.client.on(this.client.REGISTERING, () => {
|
|
525
|
+
logger.info('softphone - registering', { state: this.state });
|
|
526
|
+
|
|
527
|
+
this._sendAction(Actions.REGISTER);
|
|
528
|
+
});
|
|
529
|
+
|
|
397
530
|
this.client.on(this.client.DISCONNECTED, () => {
|
|
398
531
|
logger.info('softphone - disconnected');
|
|
399
|
-
this.
|
|
532
|
+
this.emit(EVENT_DISCONNECTED);
|
|
400
533
|
|
|
401
534
|
// Do not trigger heartbeat if already running
|
|
402
535
|
if (!this.client.hasHeartbeat()) {
|
|
@@ -408,38 +541,44 @@ export class Softphone extends EventEmitter {
|
|
|
408
541
|
});
|
|
409
542
|
|
|
410
543
|
this.client.on('onVideoInputChange', stream => {
|
|
411
|
-
this.
|
|
544
|
+
this.emit(EVENT_VIDEO_INPUT_CHANGE, stream);
|
|
412
545
|
});
|
|
413
546
|
|
|
414
547
|
this.client.on(this.client.MESSAGE, (message: Message) => {
|
|
415
548
|
this._onMessage(message);
|
|
416
549
|
|
|
417
|
-
this.
|
|
550
|
+
this.emit(EVENT_ON_MESSAGE, message);
|
|
418
551
|
});
|
|
419
552
|
|
|
420
553
|
this.client.setOnHeartbeatTimeout(() => {
|
|
421
|
-
this.
|
|
554
|
+
this.emit(EVENT_HEARTBEAT_TIMEOUT);
|
|
422
555
|
});
|
|
423
556
|
|
|
424
557
|
this.client.setOnHeartbeatCallback(() => {
|
|
425
|
-
this.
|
|
558
|
+
this.emit(EVENT_HEARTBEAT);
|
|
426
559
|
});
|
|
427
560
|
}
|
|
428
561
|
|
|
429
|
-
_sendAction(action: ActionTypes) {
|
|
562
|
+
private _sendAction(action: ActionTypes) {
|
|
563
|
+
const was = this.state;
|
|
430
564
|
this.softphoneActor.send({ type: action });
|
|
565
|
+
logger.trace('softphone - send action', { action, was, state: this.state });
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
private _getCall(sipCall: SipCall): Call | undefined {
|
|
569
|
+
return this.calls.find(call => call.id === getSipCallId(sipCall));
|
|
431
570
|
}
|
|
432
571
|
|
|
433
|
-
|
|
434
|
-
return this.calls.
|
|
572
|
+
private _getCallIds(): string[] {
|
|
573
|
+
return this.calls.map(call => call.id);
|
|
435
574
|
}
|
|
436
575
|
|
|
437
|
-
_onCallEvent(sipCall: SipCall, eventName: string, ...args: any[]) {
|
|
438
|
-
logger.
|
|
576
|
+
private _onCallEvent(sipCall: SipCall, eventName: string, ...args: any[]) {
|
|
577
|
+
logger.info('softphone - received call event', { eventName, sipId: getSipCallId(sipCall) });
|
|
439
578
|
|
|
440
579
|
const call = this._getCall(sipCall);
|
|
441
580
|
if (!call) {
|
|
442
|
-
logger.warn('softphone - no call found to send the event', { eventName, sipId: sipCall.
|
|
581
|
+
logger.warn('softphone - no call found to send the event', { eventName, sipId: getSipCallId(sipCall), ids: this._getCallIds() });
|
|
443
582
|
return;
|
|
444
583
|
}
|
|
445
584
|
|
|
@@ -447,7 +586,7 @@ export class Softphone extends EventEmitter {
|
|
|
447
586
|
call[eventName](...args);
|
|
448
587
|
}
|
|
449
588
|
|
|
450
|
-
_onMessage(message: Message & { method?: string, body?: string }): void {
|
|
589
|
+
private _onMessage(message: Message & { method?: string, body?: string }): void {
|
|
451
590
|
if (!message || message.method !== 'MESSAGE') {
|
|
452
591
|
return;
|
|
453
592
|
}
|
|
@@ -467,12 +606,12 @@ export class Softphone extends EventEmitter {
|
|
|
467
606
|
|
|
468
607
|
switch (type) {
|
|
469
608
|
case MESSAGE_TYPE_CHAT:
|
|
470
|
-
this.
|
|
609
|
+
this.emit(EVENT_ON_CHAT, content);
|
|
471
610
|
break;
|
|
472
611
|
|
|
473
612
|
case MESSAGE_TYPE_SIGNAL:
|
|
474
613
|
{
|
|
475
|
-
this.
|
|
614
|
+
this.emit(EVENT_ON_SIGNAL, content);
|
|
476
615
|
break;
|
|
477
616
|
}
|
|
478
617
|
|