@wazo/sdk 1.0.0-alpha.1 → 1.0.0-alpha.10

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.
Files changed (148) hide show
  1. package/README.md +16 -7
  2. package/dist/wazo-sdk.js +6 -6
  3. package/esm/__tests__/__voice__/call.test.js +57 -2
  4. package/esm/api/auth.js +3 -0
  5. package/esm/checker/checks/webrtc.js +2 -2
  6. package/esm/domain/CallLog.js +2 -3
  7. package/esm/domain/Phone/CTIPhone.js +2 -2
  8. package/esm/domain/Phone/WebRTCPhone.js +64 -63
  9. package/esm/index.js +3 -1
  10. package/esm/service/CallApi.js +4 -4
  11. package/esm/simple/Auth.js +13 -3
  12. package/esm/simple/Phone.js +6 -5
  13. package/esm/simple/index.js +2 -1
  14. package/esm/simple/room/Room.js +2 -2
  15. package/esm/simple/room/SipRoom.js +2 -2
  16. package/esm/state-machine/call-state-machine.js +2 -2
  17. package/esm/state-machine/softphone-state-machine.js +1 -2
  18. package/esm/state-machine/utils.js +8 -3
  19. package/esm/types/api/auth.d.ts +3 -0
  20. package/esm/types/api/auth.d.ts.map +1 -1
  21. package/esm/types/checker/checks/index.d.ts +1 -1
  22. package/esm/types/checker/checks/webrtc-transport.d.ts +2 -2
  23. package/esm/types/checker/checks/webrtc-transport.d.ts.map +1 -1
  24. package/esm/types/domain/CallLog.d.ts.map +1 -1
  25. package/esm/types/domain/CallSession.d.ts +3 -3
  26. package/esm/types/domain/CallSession.d.ts.map +1 -1
  27. package/esm/types/domain/Phone/CTIPhone.d.ts.map +1 -1
  28. package/esm/types/domain/Phone/WebRTCPhone.d.ts +22 -22
  29. package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  30. package/esm/types/domain/types.d.ts +0 -4
  31. package/esm/types/domain/types.d.ts.map +1 -1
  32. package/esm/types/index.d.ts +3 -1
  33. package/esm/types/index.d.ts.map +1 -1
  34. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
  35. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  36. package/esm/types/service/CallApi.d.ts +5 -5
  37. package/esm/types/service/CallApi.d.ts.map +1 -1
  38. package/esm/types/simple/Auth.d.ts +6 -1
  39. package/esm/types/simple/Auth.d.ts.map +1 -1
  40. package/esm/types/simple/Phone.d.ts +8 -8
  41. package/esm/types/simple/Phone.d.ts.map +1 -1
  42. package/esm/types/simple/index.d.ts +3 -1
  43. package/esm/types/simple/index.d.ts.map +1 -1
  44. package/esm/types/state-machine/softphone-state-machine.d.ts +1 -2
  45. package/esm/types/state-machine/softphone-state-machine.d.ts.map +1 -1
  46. package/esm/types/state-machine/utils.d.ts +2 -2
  47. package/esm/types/state-machine/utils.d.ts.map +1 -1
  48. package/esm/types/utils/sdp.d.ts +3 -2
  49. package/esm/types/utils/sdp.d.ts.map +1 -1
  50. package/esm/types/utils/webrtc.d.ts +1 -0
  51. package/esm/types/utils/webrtc.d.ts.map +1 -1
  52. package/esm/types/voice/call.d.ts +30 -12
  53. package/esm/types/voice/call.d.ts.map +1 -1
  54. package/esm/types/voice/softphone.d.ts +25 -13
  55. package/esm/types/voice/softphone.d.ts.map +1 -1
  56. package/esm/types/web-rtc-client.d.ts +39 -38
  57. package/esm/types/web-rtc-client.d.ts.map +1 -1
  58. package/esm/utils/sdp.js +22 -9
  59. package/esm/utils/webrtc.js +23 -3
  60. package/esm/voice/call.js +130 -38
  61. package/esm/voice/softphone.js +145 -35
  62. package/esm/web-rtc-client.js +61 -58
  63. package/lib/__tests__/__voice__/call.test.js +56 -1
  64. package/lib/api/auth.js +3 -0
  65. package/lib/checker/checks/webrtc.js +1 -1
  66. package/lib/domain/CallLog.js +2 -3
  67. package/lib/domain/Phone/CTIPhone.js +2 -2
  68. package/lib/domain/Phone/WebRTCPhone.js +63 -62
  69. package/lib/index.js +7 -3
  70. package/lib/service/CallApi.js +2 -2
  71. package/lib/simple/Auth.js +15 -3
  72. package/lib/simple/Phone.js +3 -2
  73. package/lib/simple/index.js +2 -1
  74. package/lib/simple/room/Room.js +1 -1
  75. package/lib/simple/room/SipRoom.js +1 -1
  76. package/lib/state-machine/call-state-machine.js +2 -2
  77. package/lib/state-machine/softphone-state-machine.js +1 -2
  78. package/lib/state-machine/utils.js +8 -3
  79. package/lib/types/api/auth.d.ts +3 -0
  80. package/lib/types/api/auth.d.ts.map +1 -1
  81. package/lib/types/checker/checks/index.d.ts +1 -1
  82. package/lib/types/checker/checks/webrtc-transport.d.ts +2 -2
  83. package/lib/types/checker/checks/webrtc-transport.d.ts.map +1 -1
  84. package/lib/types/domain/CallLog.d.ts.map +1 -1
  85. package/lib/types/domain/CallSession.d.ts +3 -3
  86. package/lib/types/domain/CallSession.d.ts.map +1 -1
  87. package/lib/types/domain/Phone/CTIPhone.d.ts.map +1 -1
  88. package/lib/types/domain/Phone/WebRTCPhone.d.ts +22 -22
  89. package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  90. package/lib/types/domain/types.d.ts +0 -4
  91. package/lib/types/domain/types.d.ts.map +1 -1
  92. package/lib/types/index.d.ts +3 -1
  93. package/lib/types/index.d.ts.map +1 -1
  94. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
  95. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  96. package/lib/types/service/CallApi.d.ts +5 -5
  97. package/lib/types/service/CallApi.d.ts.map +1 -1
  98. package/lib/types/simple/Auth.d.ts +6 -1
  99. package/lib/types/simple/Auth.d.ts.map +1 -1
  100. package/lib/types/simple/Phone.d.ts +8 -8
  101. package/lib/types/simple/Phone.d.ts.map +1 -1
  102. package/lib/types/simple/index.d.ts +3 -1
  103. package/lib/types/simple/index.d.ts.map +1 -1
  104. package/lib/types/state-machine/softphone-state-machine.d.ts +1 -2
  105. package/lib/types/state-machine/softphone-state-machine.d.ts.map +1 -1
  106. package/lib/types/state-machine/utils.d.ts +2 -2
  107. package/lib/types/state-machine/utils.d.ts.map +1 -1
  108. package/lib/types/utils/sdp.d.ts +3 -2
  109. package/lib/types/utils/sdp.d.ts.map +1 -1
  110. package/lib/types/utils/webrtc.d.ts +1 -0
  111. package/lib/types/utils/webrtc.d.ts.map +1 -1
  112. package/lib/types/voice/call.d.ts +30 -12
  113. package/lib/types/voice/call.d.ts.map +1 -1
  114. package/lib/types/voice/softphone.d.ts +25 -13
  115. package/lib/types/voice/softphone.d.ts.map +1 -1
  116. package/lib/types/web-rtc-client.d.ts +39 -38
  117. package/lib/types/web-rtc-client.d.ts.map +1 -1
  118. package/lib/utils/sdp.js +25 -10
  119. package/lib/utils/webrtc.js +24 -3
  120. package/lib/voice/call.js +131 -36
  121. package/lib/voice/softphone.js +150 -35
  122. package/lib/web-rtc-client.js +59 -57
  123. package/package.json +1 -1
  124. package/src/__tests__/__voice__/call.test.ts +63 -2
  125. package/src/api/auth.ts +5 -0
  126. package/src/checker/checks/webrtc-transport.ts +2 -2
  127. package/src/checker/checks/webrtc.ts +2 -2
  128. package/src/domain/CallLog.ts +2 -3
  129. package/src/domain/CallSession.ts +3 -3
  130. package/src/domain/Phone/CTIPhone.ts +3 -2
  131. package/src/domain/Phone/WebRTCPhone.ts +95 -93
  132. package/src/domain/types.ts +0 -5
  133. package/src/index.ts +4 -1
  134. package/src/lib/WazoSessionDescriptionHandler.ts +3 -3
  135. package/src/service/CallApi.ts +7 -7
  136. package/src/simple/Auth.ts +15 -3
  137. package/src/simple/Phone.ts +12 -11
  138. package/src/simple/index.ts +2 -1
  139. package/src/simple/room/Room.ts +3 -3
  140. package/src/simple/room/SipRoom.ts +3 -3
  141. package/src/state-machine/call-state-machine.ts +2 -2
  142. package/src/state-machine/softphone-state-machine.ts +1 -2
  143. package/src/state-machine/utils.ts +12 -5
  144. package/src/utils/sdp.ts +26 -11
  145. package/src/utils/webrtc.ts +26 -4
  146. package/src/voice/call.ts +169 -50
  147. package/src/voice/softphone.ts +180 -41
  148. package/src/web-rtc-client.ts +106 -99
@@ -4,19 +4,24 @@ import { createActor } from 'xstate';
4
4
  import InvalidState from '../domain/InvalidState';
5
5
  import Wazo from '..';
6
6
  import softphoneStateMachine, { Actions, States } from '../state-machine/softphone-state-machine';
7
- import { Actions as CallActions } from '../state-machine/call-state-machine';
8
7
  import WazoWebRTCClient from '../web-rtc-client';
9
8
  import IssueReporter from '../service/IssueReporter';
10
9
  import configureLogger from '../utils/sip-logger';
11
10
  import Call from './call';
12
11
  import { assertCan, can, getState, waitUntilState } from '../state-machine/utils';
12
+ import { getSipCallId } from '../utils/sdp';
13
13
  export const EVENT_INCOMING = 'incoming';
14
+ export const EVENT_OUTGOING = 'outgoing';
14
15
  export const EVENT_HEARTBEAT = 'heartbeat';
15
16
  export const EVENT_HEARTBEAT_TIMEOUT = 'heartbeatTimeout';
16
17
  export const EVENT_REGISTERED = 'registered';
17
18
  export const EVENT_UNREGISTERED = 'unregistered';
18
19
  export const EVENT_DISCONNECTED = 'disconnected';
19
20
  export const EVENT_VIDEO_INPUT_CHANGE = 'videoInputChange';
21
+ export const EVENT_TERMINATE_SOUND = 'terminateSound';
22
+ export const EVENT_PLAY_HANGUP_SOUND = 'playHangupSound';
23
+ export const EVENT_PLAY_RING_SOUND = 'playRingSound';
24
+ export const EVENT_PLAY_INBOUND_CALL_SOUND = 'playInboundCallSound';
20
25
  export const EVENT_ON_MESSAGE = 'message';
21
26
  export const EVENT_ON_CHAT = 'phone/ON_CHAT';
22
27
  export const EVENT_ON_SIGNAL = 'phone/ON_SIGNAL';
@@ -28,7 +33,6 @@ export class Softphone extends EventEmitter {
28
33
  audioRingDeviceId;
29
34
  audioOutputVolume;
30
35
  audioRingVolume;
31
- eventEmitter;
32
36
  calls;
33
37
  client;
34
38
  session;
@@ -36,6 +40,7 @@ export class Softphone extends EventEmitter {
36
40
  softphoneActor;
37
41
  options;
38
42
  shouldSendReinvite;
43
+ ringingEnabled = true;
39
44
  constructor() {
40
45
  super();
41
46
  this.calls = [];
@@ -49,6 +54,7 @@ export class Softphone extends EventEmitter {
49
54
  this.audioRingVolume = 1;
50
55
  const server = Wazo.Auth.getHost();
51
56
  const session = Wazo.Auth.getSession();
57
+ logger.info('softphone - connect', { server, session: !!session });
52
58
  if (!server || !session) {
53
59
  throw new Error('Please connect to the server using `Wazo.Auth.logIn` or `Wazo.Auth.authenticate` before using Room.connect().');
54
60
  }
@@ -60,13 +66,17 @@ export class Softphone extends EventEmitter {
60
66
  this.options.userUuid = session.uuid || '';
61
67
  return this.connectWithCredentials(server, this.sipLine, session.displayName(), options);
62
68
  }
69
+ async hangupAllCalls() {
70
+ return Promise.all(this.calls.map(call => call.hangup()));
71
+ }
63
72
  async disconnect() {
64
73
  assertCan(this.softphoneActor, Actions.UNREGISTER);
65
74
  if (!this.client) {
75
+ logger.info('softphone - disconnect, not client to disconnect, bailing');
66
76
  return null;
67
77
  }
68
78
  // Terminate all calls
69
- await Promise.all(this.calls.map(call => call.hangup()));
79
+ await this.hangupAllCalls();
70
80
  return this.client.unregister();
71
81
  }
72
82
  getPrimaryWebRtcLine() {
@@ -74,7 +84,8 @@ export class Softphone extends EventEmitter {
74
84
  }
75
85
  async connectWithCredentials(server, sipLine, displayName, rawOptions = {}) {
76
86
  assertCan(this.softphoneActor, Actions.REGISTER);
77
- this.softphoneActor.send({ type: Actions.REGISTER });
87
+ logger.info('softphone - connect with credentials', { server, username: sipLine.username, displayName, options: rawOptions });
88
+ this._sendAction(Actions.REGISTER);
78
89
  const [host, port = 443] = server.split(':');
79
90
  let options = { ...rawOptions };
80
91
  options.media = options.media || {
@@ -114,19 +125,22 @@ export class Softphone extends EventEmitter {
114
125
  logger.warn('softphone - calling with empty number, bailing.');
115
126
  return Promise.resolve(null);
116
127
  }
117
- if (this.getState() !== States.UNREGISTERED) {
118
- throw new InvalidState(`Invalid state ${States.UNREGISTERED}`, States.UNREGISTERED);
119
- }
120
- if (this.getState() !== States.REGISTERING) {
128
+ if (this.state === States.REGISTERING) {
121
129
  logger.info('softphone - calling when registering, waiting for Softphone to be registered ...');
122
130
  await waitUntilState(this.softphoneActor, States.REGISTERED);
123
131
  }
132
+ if (this.state !== States.REGISTERED) {
133
+ throw new InvalidState(`Invalid state ${States.UNREGISTERED}`, States.UNREGISTERED);
134
+ }
124
135
  // Hold other calls
125
136
  this.holdAllCalls();
126
137
  let sipCall;
127
138
  try {
128
139
  sipCall = this.client.call(options.params.To, options.withCamera, options.audioOnly, options.conference, options);
129
140
  const call = new Call(sipCall, this);
141
+ call.onMakeCall();
142
+ this.calls.push(call);
143
+ this.emit(EVENT_OUTGOING, call);
130
144
  return call;
131
145
  }
132
146
  catch (error) {
@@ -137,11 +151,64 @@ export class Softphone extends EventEmitter {
137
151
  removeCall(callToRemove) {
138
152
  this.calls = this.calls.filter((call) => call.id !== callToRemove.id);
139
153
  }
154
+ onCallTerminated(call) {
155
+ logger.info('softphone - on call terminated', { id: call.id });
156
+ const currentCall = this.getCurrentCall();
157
+ const isCurrentCall = currentCall?.id === call.id;
158
+ const isRinging = call.isRinging();
159
+ const isCurrentIncomingCall = isCurrentCall && isRinging;
160
+ const incomingCalls = this.getIncomingCalls();
161
+ const nbIncomingCalls = incomingCalls.length;
162
+ // Send an event to terminate ringing sound
163
+ if (isCurrentIncomingCall) {
164
+ setTimeout(() => {
165
+ // Avoid race condition when the other is calling and hanging up immediately
166
+ this.emit(EVENT_TERMINATE_SOUND, call, 'call terminated');
167
+ }, 5);
168
+ }
169
+ // If the terminated call was an incoming call, we have to re-trigger if it's was the first incoming call
170
+ // Otherwise, we have to re-trigger an incoming call event if another call is incoming
171
+ const shouldRetrigger = isCurrentCall ? nbIncomingCalls : isCurrentIncomingCall;
172
+ // Re-trigger incoming call event for remaining incoming calls
173
+ logger.info('Softphone - check to re-trigger incoming call', { shouldRetrigger, nbIncomingCalls });
174
+ if (shouldRetrigger && nbIncomingCalls > 1) {
175
+ const nextCall = incomingCalls.find(c => c.id !== call.id);
176
+ // Avoid race condition
177
+ setTimeout(() => {
178
+ if (this.ringingEnabled) {
179
+ if (currentCall) {
180
+ this.emit(EVENT_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, nextCall);
181
+ }
182
+ else {
183
+ this.emit(EVENT_PLAY_INBOUND_CALL_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, nextCall);
184
+ }
185
+ }
186
+ this.emit(EVENT_INCOMING, nextCall);
187
+ }, 100);
188
+ }
189
+ // @ts-ignore: does not exist
190
+ if (!call.sipCall.isCanceled) {
191
+ setTimeout(() => {
192
+ this.emit(EVENT_PLAY_HANGUP_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, call);
193
+ }, 10);
194
+ }
195
+ this.client.onCallEnded(call.sipCall);
196
+ this.removeCall(call);
197
+ }
198
+ enableRinging() {
199
+ logger.info('softphone - enable ringing');
200
+ this.ringingEnabled = true;
201
+ }
202
+ disableRinging() {
203
+ logger.info('softphone - disable ringing');
204
+ this.ringingEnabled = false;
205
+ }
140
206
  holdAllCalls(exceptCall = null) {
141
- this.calls.filter(call => !call.isHeld() && call.id === exceptCall?.id).forEach(call => call.hold());
207
+ logger.info('softphone - hold all calls', { exceptId: exceptCall?.id, ids: this.calls.map(call => call.id) });
208
+ this.calls.filter(call => !call.isHeld() && call.id !== exceptCall?.id).forEach(call => call.hold());
142
209
  }
143
210
  startHeartbeat() {
144
- logger.info('softphone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client.hasHeartbeat() });
211
+ logger.info('softphone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client?.hasHeartbeat() });
145
212
  if (!this.client || this.client.hasHeartbeat()) {
146
213
  return;
147
214
  }
@@ -190,28 +257,52 @@ export class Softphone extends EventEmitter {
190
257
  logger.info('softphone - changing ring volume', { volume });
191
258
  this.audioRingVolume = volume;
192
259
  }
193
- getCalls() {
194
- return this.calls;
195
- }
196
260
  getCurrentCall() {
197
- return this.calls.find(call => call.isEstablished());
261
+ return this.getActiveCalls()[0];
262
+ }
263
+ getActiveCalls() {
264
+ return this.calls.filter(call => call.isEstablished());
198
265
  }
199
- getState() {
200
- return this.softphoneActor.getSnapshot().value;
266
+ getIncomingCalls() {
267
+ return this.calls.filter(call => call.isRinging());
268
+ }
269
+ get state() {
270
+ return getState(this.softphoneActor);
271
+ }
272
+ get user() {
273
+ return this.client?.userAgent?.contact?.uri?.user;
201
274
  }
202
275
  getUserAgent() {
203
276
  return this.client?.config?.userAgentString || 'softphone';
204
277
  }
278
+ isRegistering() {
279
+ return this.state === States.REGISTERING;
280
+ }
281
+ isRegistered() {
282
+ return this.state === States.REGISTERED;
283
+ }
284
+ isUnRegistered() {
285
+ return this.state === States.UNREGISTERED;
286
+ }
205
287
  _bindEvents() {
206
288
  this.client.on(this.client.INVITE, (sipSession) => {
207
289
  const call = new Call(sipSession, this);
208
- call._sendAction(CallActions.INCOMING_CALL);
290
+ logger.info('softphone - on invite', { callId: call.id, number: call.number });
291
+ call.onCallIncoming();
209
292
  this.calls.push(call);
210
- this.eventEmitter.emit(EVENT_INCOMING, call);
293
+ this.emit(EVENT_INCOMING, call);
294
+ if (!this.getCurrentCall()) {
295
+ if (this.ringingEnabled) {
296
+ this.emit(EVENT_PLAY_RING_SOUND, this.audioRingDeviceId, this.audioRingVolume, call);
297
+ }
298
+ }
299
+ else {
300
+ this.emit(EVENT_PLAY_INBOUND_CALL_SOUND, this.audioOutputDeviceId, this.audioOutputVolume, call);
301
+ }
211
302
  });
212
303
  this.client.on(this.client.ON_REINVITE, (sipCall, request, updatedCalleeName, updatedNumber, hadRemoteVideo) => {
213
304
  logger.info('softphone - on reinvite', {
214
- callId: sipCall.id,
305
+ callId: getSipCallId(sipCall),
215
306
  inviteId: request.callId,
216
307
  updatedCalleeName,
217
308
  updatedNumber,
@@ -220,6 +311,8 @@ export class Softphone extends EventEmitter {
220
311
  this._onCallEvent(sipCall, 'onReinvite', request, updatedCalleeName, updatedNumber, hadRemoteVideo);
221
312
  });
222
313
  this.client.on(this.client.ACCEPTED, async (sipCall) => {
314
+ const call = this._getCall(sipCall);
315
+ this.emit(EVENT_TERMINATE_SOUND, call, 'call accepted');
223
316
  this._onCallEvent(sipCall, 'onAccepted');
224
317
  if (this.audioOutputDeviceId) {
225
318
  await this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
@@ -249,23 +342,31 @@ export class Softphone extends EventEmitter {
249
342
  });
250
343
  this.client.on(this.client.UNREGISTERED, () => {
251
344
  logger.info('softphone - unregistered');
252
- this.eventEmitter.emit(EVENT_UNREGISTERED);
253
- this._sendAction(Actions.UNREGISTERED);
345
+ if (!can(this.softphoneActor, Actions.UNREGISTER)) {
346
+ logger.warn('softphone - cannot unregister', { state: this.state });
347
+ return;
348
+ }
349
+ this._sendAction(Actions.UNREGISTER);
350
+ this.emit(EVENT_UNREGISTERED);
254
351
  });
255
352
  this.client.on(this.client.ON_DISCONNECTED, () => {
256
353
  logger.info('softphone - disconnected');
257
- this.eventEmitter.emit(EVENT_DISCONNECTED);
354
+ if (!can(this.softphoneActor, Actions.TRANSPORT_CLOSED)) {
355
+ logger.warn('softphone - cannot disconnected', { state: this.state });
356
+ return;
357
+ }
258
358
  this._sendAction(Actions.TRANSPORT_CLOSED);
359
+ this.emit(EVENT_DISCONNECTED);
259
360
  });
260
361
  this.client.on(this.client.REGISTERED, () => {
261
362
  logger.info('softphone - registered', { state: getState(this.softphoneActor) });
262
363
  if (!can(this.softphoneActor, Actions.REGISTER_DONE)) {
263
- logger.warn('softphone - registered but not in REGISTERING state', { state: getState(this.softphoneActor) });
364
+ logger.warn('softphone - registered but not in REGISTERING state', { state: this.state });
264
365
  return;
265
366
  }
266
367
  this.stopHeartbeat();
267
368
  this._sendAction(Actions.REGISTER_DONE);
268
- this.eventEmitter.emit(EVENT_REGISTERED);
369
+ this.emit(EVENT_REGISTERED);
269
370
  // If the phone registered with a current callSession (eg: when switching network):
270
371
  // send a reinvite to renegociate ICE with new IP
271
372
  if (this.shouldSendReinvite) {
@@ -276,12 +377,16 @@ export class Softphone extends EventEmitter {
276
377
  }
277
378
  });
278
379
  this.client.on(this.client.CONNECTED, () => {
279
- logger.info('softphone - connected');
380
+ logger.info('softphone - connected', { state: this.state });
280
381
  this.stopHeartbeat();
281
382
  });
383
+ this.client.on(this.client.REGISTERING, () => {
384
+ logger.info('softphone - registering', { state: this.state });
385
+ this._sendAction(Actions.REGISTER);
386
+ });
282
387
  this.client.on(this.client.DISCONNECTED, () => {
283
388
  logger.info('softphone - disconnected');
284
- this.eventEmitter.emit(EVENT_DISCONNECTED);
389
+ this.emit(EVENT_DISCONNECTED);
285
390
  // Do not trigger heartbeat if already running
286
391
  if (!this.client.hasHeartbeat()) {
287
392
  this.startHeartbeat();
@@ -290,30 +395,35 @@ export class Softphone extends EventEmitter {
290
395
  this.shouldSendReinvite = this.calls.length > 0;
291
396
  });
292
397
  this.client.on('onVideoInputChange', stream => {
293
- this.eventEmitter.emit(EVENT_VIDEO_INPUT_CHANGE, stream);
398
+ this.emit(EVENT_VIDEO_INPUT_CHANGE, stream);
294
399
  });
295
400
  this.client.on(this.client.MESSAGE, (message) => {
296
401
  this._onMessage(message);
297
- this.eventEmitter.emit(EVENT_ON_MESSAGE, message);
402
+ this.emit(EVENT_ON_MESSAGE, message);
298
403
  });
299
404
  this.client.setOnHeartbeatTimeout(() => {
300
- this.eventEmitter.emit(EVENT_HEARTBEAT_TIMEOUT);
405
+ this.emit(EVENT_HEARTBEAT_TIMEOUT);
301
406
  });
302
407
  this.client.setOnHeartbeatCallback(() => {
303
- this.eventEmitter.emit(EVENT_HEARTBEAT);
408
+ this.emit(EVENT_HEARTBEAT);
304
409
  });
305
410
  }
306
411
  _sendAction(action) {
412
+ const was = this.state;
307
413
  this.softphoneActor.send({ type: action });
414
+ logger.trace('softphone - send action', { action, was, state: this.state });
308
415
  }
309
416
  _getCall(sipCall) {
310
- return this.calls.find(call => call.id === sipCall.id);
417
+ return this.calls.find(call => call.id === getSipCallId(sipCall));
418
+ }
419
+ _getCallIds() {
420
+ return this.calls.map(call => call.id);
311
421
  }
312
422
  _onCallEvent(sipCall, eventName, ...args) {
313
- logger.warn('softphone - received call event', { eventName, sipId: sipCall.id });
423
+ logger.info('softphone - received call event', { eventName, sipId: getSipCallId(sipCall) });
314
424
  const call = this._getCall(sipCall);
315
425
  if (!call) {
316
- logger.warn('softphone - no call found to send the event', { eventName, sipId: sipCall.id });
426
+ logger.warn('softphone - no call found to send the event', { eventName, sipId: getSipCallId(sipCall), ids: this._getCallIds() });
317
427
  return;
318
428
  }
319
429
  // @ts-ignore
@@ -333,11 +443,11 @@ export class Softphone extends EventEmitter {
333
443
  const { type, content, } = body;
334
444
  switch (type) {
335
445
  case MESSAGE_TYPE_CHAT:
336
- this.eventEmitter.emit(EVENT_ON_CHAT, content);
446
+ this.emit(EVENT_ON_CHAT, content);
337
447
  break;
338
448
  case MESSAGE_TYPE_SIGNAL:
339
449
  {
340
- this.eventEmitter.emit(EVENT_ON_SIGNAL, content);
450
+ this.emit(EVENT_ON_SIGNAL, content);
341
451
  break;
342
452
  }
343
453
  default: