@wazo/sdk 1.0.0-alpha.0 → 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 (162) 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/__tests__/api-client.test.js +20 -1
  5. package/esm/api/auth.js +16 -2
  6. package/esm/checker/checks/webrtc.js +2 -2
  7. package/esm/domain/CallLog.js +2 -3
  8. package/esm/domain/Phone/CTIPhone.js +2 -2
  9. package/esm/domain/Phone/WebRTCPhone.js +64 -63
  10. package/esm/index.js +5 -1
  11. package/esm/service/CallApi.js +4 -4
  12. package/esm/simple/Auth.js +19 -15
  13. package/esm/simple/Phone.js +6 -5
  14. package/esm/simple/__tests__/Auth.test.js +8 -64
  15. package/esm/simple/index.js +2 -1
  16. package/esm/simple/room/Room.js +2 -2
  17. package/esm/simple/room/SipRoom.js +2 -2
  18. package/esm/state-machine/call-state-machine.js +2 -2
  19. package/esm/state-machine/softphone-state-machine.js +1 -2
  20. package/esm/state-machine/utils.js +8 -3
  21. package/esm/types/api/auth.d.ts +3 -0
  22. package/esm/types/api/auth.d.ts.map +1 -1
  23. package/esm/types/checker/checks/index.d.ts +1 -1
  24. package/esm/types/checker/checks/webrtc-transport.d.ts +2 -2
  25. package/esm/types/checker/checks/webrtc-transport.d.ts.map +1 -1
  26. package/esm/types/domain/CallLog.d.ts.map +1 -1
  27. package/esm/types/domain/CallSession.d.ts +3 -3
  28. package/esm/types/domain/CallSession.d.ts.map +1 -1
  29. package/esm/types/domain/Phone/CTIPhone.d.ts.map +1 -1
  30. package/esm/types/domain/Phone/WebRTCPhone.d.ts +22 -22
  31. package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  32. package/esm/types/domain/types.d.ts +0 -4
  33. package/esm/types/domain/types.d.ts.map +1 -1
  34. package/esm/types/index.d.ts +5 -1
  35. package/esm/types/index.d.ts.map +1 -1
  36. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
  37. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  38. package/esm/types/service/CallApi.d.ts +5 -5
  39. package/esm/types/service/CallApi.d.ts.map +1 -1
  40. package/esm/types/simple/Auth.d.ts +6 -1
  41. package/esm/types/simple/Auth.d.ts.map +1 -1
  42. package/esm/types/simple/Phone.d.ts +8 -8
  43. package/esm/types/simple/Phone.d.ts.map +1 -1
  44. package/esm/types/simple/index.d.ts +3 -1
  45. package/esm/types/simple/index.d.ts.map +1 -1
  46. package/esm/types/state-machine/softphone-state-machine.d.ts +1 -2
  47. package/esm/types/state-machine/softphone-state-machine.d.ts.map +1 -1
  48. package/esm/types/state-machine/utils.d.ts +2 -2
  49. package/esm/types/state-machine/utils.d.ts.map +1 -1
  50. package/esm/types/utils/api-requester.d.ts.map +1 -1
  51. package/esm/types/utils/sdp.d.ts +3 -2
  52. package/esm/types/utils/sdp.d.ts.map +1 -1
  53. package/esm/types/utils/webrtc.d.ts +1 -0
  54. package/esm/types/utils/webrtc.d.ts.map +1 -1
  55. package/esm/types/voice/call.d.ts +30 -12
  56. package/esm/types/voice/call.d.ts.map +1 -1
  57. package/esm/types/voice/softphone.d.ts +25 -13
  58. package/esm/types/voice/softphone.d.ts.map +1 -1
  59. package/esm/types/web-rtc-client.d.ts +39 -38
  60. package/esm/types/web-rtc-client.d.ts.map +1 -1
  61. package/esm/utils/__tests__/api-requester.test.js +17 -0
  62. package/esm/utils/api-requester.js +9 -1
  63. package/esm/utils/sdp.js +22 -9
  64. package/esm/utils/webrtc.js +24 -4
  65. package/esm/voice/call.js +130 -38
  66. package/esm/voice/softphone.js +145 -35
  67. package/esm/web-rtc-client.js +61 -58
  68. package/lib/__tests__/__voice__/call.test.js +56 -1
  69. package/lib/__tests__/api-client.test.js +20 -1
  70. package/lib/api/auth.js +16 -2
  71. package/lib/checker/checks/webrtc.js +1 -1
  72. package/lib/domain/CallLog.js +2 -3
  73. package/lib/domain/Phone/CTIPhone.js +2 -2
  74. package/lib/domain/Phone/WebRTCPhone.js +63 -62
  75. package/lib/index.js +11 -3
  76. package/lib/service/CallApi.js +2 -2
  77. package/lib/simple/Auth.js +21 -15
  78. package/lib/simple/Phone.js +3 -2
  79. package/lib/simple/__tests__/Auth.test.js +11 -64
  80. package/lib/simple/index.js +2 -1
  81. package/lib/simple/room/Room.js +1 -1
  82. package/lib/simple/room/SipRoom.js +1 -1
  83. package/lib/state-machine/call-state-machine.js +2 -2
  84. package/lib/state-machine/softphone-state-machine.js +1 -2
  85. package/lib/state-machine/utils.js +8 -3
  86. package/lib/types/api/auth.d.ts +3 -0
  87. package/lib/types/api/auth.d.ts.map +1 -1
  88. package/lib/types/checker/checks/index.d.ts +1 -1
  89. package/lib/types/checker/checks/webrtc-transport.d.ts +2 -2
  90. package/lib/types/checker/checks/webrtc-transport.d.ts.map +1 -1
  91. package/lib/types/domain/CallLog.d.ts.map +1 -1
  92. package/lib/types/domain/CallSession.d.ts +3 -3
  93. package/lib/types/domain/CallSession.d.ts.map +1 -1
  94. package/lib/types/domain/Phone/CTIPhone.d.ts.map +1 -1
  95. package/lib/types/domain/Phone/WebRTCPhone.d.ts +22 -22
  96. package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  97. package/lib/types/domain/types.d.ts +0 -4
  98. package/lib/types/domain/types.d.ts.map +1 -1
  99. package/lib/types/index.d.ts +5 -1
  100. package/lib/types/index.d.ts.map +1 -1
  101. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
  102. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  103. package/lib/types/service/CallApi.d.ts +5 -5
  104. package/lib/types/service/CallApi.d.ts.map +1 -1
  105. package/lib/types/simple/Auth.d.ts +6 -1
  106. package/lib/types/simple/Auth.d.ts.map +1 -1
  107. package/lib/types/simple/Phone.d.ts +8 -8
  108. package/lib/types/simple/Phone.d.ts.map +1 -1
  109. package/lib/types/simple/index.d.ts +3 -1
  110. package/lib/types/simple/index.d.ts.map +1 -1
  111. package/lib/types/state-machine/softphone-state-machine.d.ts +1 -2
  112. package/lib/types/state-machine/softphone-state-machine.d.ts.map +1 -1
  113. package/lib/types/state-machine/utils.d.ts +2 -2
  114. package/lib/types/state-machine/utils.d.ts.map +1 -1
  115. package/lib/types/utils/api-requester.d.ts.map +1 -1
  116. package/lib/types/utils/sdp.d.ts +3 -2
  117. package/lib/types/utils/sdp.d.ts.map +1 -1
  118. package/lib/types/utils/webrtc.d.ts +1 -0
  119. package/lib/types/utils/webrtc.d.ts.map +1 -1
  120. package/lib/types/voice/call.d.ts +30 -12
  121. package/lib/types/voice/call.d.ts.map +1 -1
  122. package/lib/types/voice/softphone.d.ts +25 -13
  123. package/lib/types/voice/softphone.d.ts.map +1 -1
  124. package/lib/types/web-rtc-client.d.ts +39 -38
  125. package/lib/types/web-rtc-client.d.ts.map +1 -1
  126. package/lib/utils/__tests__/api-requester.test.js +17 -0
  127. package/lib/utils/api-requester.js +9 -1
  128. package/lib/utils/sdp.js +25 -10
  129. package/lib/utils/webrtc.js +25 -4
  130. package/lib/voice/call.js +131 -36
  131. package/lib/voice/softphone.js +150 -35
  132. package/lib/web-rtc-client.js +59 -57
  133. package/package.json +1 -1
  134. package/src/__tests__/__voice__/call.test.ts +63 -2
  135. package/src/__tests__/api-client.test.ts +22 -1
  136. package/src/api/auth.ts +30 -3
  137. package/src/checker/checks/webrtc-transport.ts +2 -2
  138. package/src/checker/checks/webrtc.ts +2 -2
  139. package/src/domain/CallLog.ts +2 -3
  140. package/src/domain/CallSession.ts +3 -3
  141. package/src/domain/Phone/CTIPhone.ts +3 -2
  142. package/src/domain/Phone/WebRTCPhone.ts +95 -93
  143. package/src/domain/types.ts +0 -5
  144. package/src/index.ts +6 -1
  145. package/src/lib/WazoSessionDescriptionHandler.ts +3 -3
  146. package/src/service/CallApi.ts +7 -7
  147. package/src/simple/Auth.ts +21 -16
  148. package/src/simple/Phone.ts +12 -11
  149. package/src/simple/__tests__/Auth.test.ts +9 -87
  150. package/src/simple/index.ts +2 -1
  151. package/src/simple/room/Room.ts +3 -3
  152. package/src/simple/room/SipRoom.ts +3 -3
  153. package/src/state-machine/call-state-machine.ts +2 -2
  154. package/src/state-machine/softphone-state-machine.ts +1 -2
  155. package/src/state-machine/utils.ts +12 -5
  156. package/src/utils/__tests__/api-requester.test.ts +20 -0
  157. package/src/utils/api-requester.ts +9 -1
  158. package/src/utils/sdp.ts +26 -11
  159. package/src/utils/webrtc.ts +27 -5
  160. package/src/voice/call.ts +169 -50
  161. package/src/voice/softphone.ts +180 -41
  162. package/src/web-rtc-client.ts +106 -99
package/esm/voice/call.js CHANGED
@@ -4,13 +4,17 @@ import { createActor } from 'xstate';
4
4
  import { Invitation } from 'sip.js/lib/api/invitation';
5
5
  import { SessionState } from 'sip.js/lib/api/session-state';
6
6
  import callStateMachine, { Actions, EstablishedActions, States, EstablishedStates } from '../state-machine/call-state-machine';
7
+ import newFrom from '../utils/new-from';
8
+ import updateFrom from '../utils/update-from';
7
9
  import IssueReporter from '../service/IssueReporter';
8
- import { getSipSessionId } from '../utils/sdp';
10
+ import softphone from './softphone';
11
+ import { getCallDisplayName, getCallNumber, getSipCallId } from '../utils/sdp';
9
12
  import { assertCan, assertState, getState } from '../state-machine/utils';
10
- import { downgradeToAudio, getLocalStream, getLocalVideoStream, getPeerConnection, getRemoteStream, getRemoteVideoStream, getStreamFromConstraints, getWebRtcStats, hasALocalVideoTrack, hasLocalVideo, hasRemoteVideo, isVideoRemotelyHeld, setLocalMediaStream, toggleVideo, upgradeToVideo } from '../utils/webrtc';
13
+ import { downgradeToAudio, getLocalStream, getLocalVideoStream, getPeerConnection, getRemoteStream, getRemoteVideoStream, getStreamFromConstraints, getWebRtcStats, hasALocalVideoTrack, hasLocalVideo, hasRemoteVideo, isVideoMuted, isVideoRemotelyHeld, setLocalMediaStream, toggleVideo, upgradeToVideo } from '../utils/webrtc';
11
14
  const logger = IssueReporter.loggerFor('call');
12
15
  // Events
13
- export const EVENT_CALL_ACCEPTED = 'accepted';
16
+ export const EVENT_CALL_REMOTLY_ACCEPTED = 'remotelyAccepted';
17
+ export const EVENT_CALL_LOCALLY_ACCEPTED = 'locallyAccepted';
14
18
  export const EVENT_CALL_CANCELED = 'canceled';
15
19
  export const EVENT_PROGRESS = 'progress';
16
20
  export const EVENT_EARLY_MEDIA = 'earlyMedia';
@@ -33,12 +37,10 @@ export const EVENT_SHARE_SCREEN_ENDED = 'onScreenShareEnded';
33
37
  export const EVENT_WEB_RTC_STATS = 'webRtcStats';
34
38
  export const EVENT_CAMERA_RESUMED = 'onCameraResumed';
35
39
  export const EVENT_CAMERA_DISABLED = 'onCameraDisabled';
36
- export const EVENT_TERMINATE_SOUND = 'terminateSound';
37
40
  export const MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
38
41
  export const MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
39
42
  export const MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
40
43
  class Call extends EventEmitter {
41
- eventEmitter;
42
44
  callActor;
43
45
  // Wazo call id, used in Wazo Websocket and API
44
46
  apiId;
@@ -49,7 +51,54 @@ class Call extends EventEmitter {
49
51
  endTime;
50
52
  phone;
51
53
  shouldSendReinvite = false;
54
+ recording = false;
55
+ displayName;
56
+ number;
52
57
  currentScreenShare;
58
+ static newFrom(call) {
59
+ return newFrom(call, Call);
60
+ }
61
+ static parseCall(apiCall) {
62
+ const sipCall = {
63
+ id: apiCall.sipCallId,
64
+ stateChange: {
65
+ addListener: () => { },
66
+ },
67
+ remoteIdentity: {
68
+ uri: {
69
+ _normal: {
70
+ user: apiCall.calleeNumber,
71
+ },
72
+ },
73
+ },
74
+ // Mock sdk so `hasLocalVideo` will return true.
75
+ sessionDescriptionHandler: {
76
+ localMediaStream: {
77
+ getTracks: () => (apiCall.isVideo ? [{ kind: 'video', readyState: 'live' }] : []),
78
+ },
79
+ },
80
+ };
81
+ const call = new Call(sipCall, softphone);
82
+ call.apiId = apiCall.id;
83
+ call.answerTime = new Date(+apiCall.startingTime);
84
+ // Update call state
85
+ const snapshot = call.callActor.getSnapshot();
86
+ if (apiCall.isUp()) {
87
+ snapshot.value = { [States.ESTABLISHED]: EstablishedStates.ONGOING };
88
+ }
89
+ if (apiCall.muted) {
90
+ snapshot.value = { [States.ESTABLISHED]: EstablishedStates.MUTED };
91
+ }
92
+ if (apiCall.isRinging()) {
93
+ snapshot.value = States.RINGING;
94
+ }
95
+ if (apiCall.isRecording()) {
96
+ call.recording = true;
97
+ }
98
+ // @ts-ignore
99
+ call.callActor.update(snapshot);
100
+ return call;
101
+ }
53
102
  constructor(sipCall, phone) {
54
103
  super();
55
104
  this.callActor = createActor(callStateMachine);
@@ -57,7 +106,8 @@ class Call extends EventEmitter {
57
106
  this.creationTime = new Date();
58
107
  this.phone = phone;
59
108
  this.sipCall = sipCall;
60
- this._bindEvents();
109
+ this.number = getCallNumber(sipCall);
110
+ this.displayName = getCallDisplayName(sipCall);
61
111
  }
62
112
  async accept(options = {}) {
63
113
  assertCan(this.callActor, Actions.ACCEPT);
@@ -68,6 +118,7 @@ class Call extends EventEmitter {
68
118
  this.answerTime = new Date();
69
119
  return this.phone.client.answer(this.sipCall, options.withCamera).then(() => {
70
120
  logger.info('call - accepted', { id: this.id, ...options });
121
+ this.emit(EVENT_CALL_LOCALLY_ACCEPTED, this);
71
122
  return this.id;
72
123
  }).catch(e => {
73
124
  logger.error(e);
@@ -78,16 +129,18 @@ class Call extends EventEmitter {
78
129
  async reject() {
79
130
  assertCan(this.callActor, Actions.REJECT);
80
131
  logger.info('call - reject', { id: this.id });
81
- this.eventEmitter.emit(EVENT_TERMINATE_SOUND, 'call rejected locally');
82
- this.shouldSendReinvite = false;
83
- return this.hangup();
132
+ return this._terminate();
84
133
  }
85
134
  async hangup() {
86
135
  assertCan(this.callActor, Actions.HANGUP);
87
136
  logger.info('call - hangup', { id: this.id });
137
+ return this._terminate();
138
+ }
139
+ async _terminate() {
88
140
  await this.phone.client.hangup(this.sipCall);
141
+ this.shouldSendReinvite = false;
89
142
  // Remove this call from softphone's calls
90
- this.phone.removeCall(this);
143
+ this.phone.onCallTerminated(this);
91
144
  return true;
92
145
  }
93
146
  forceCancel() {
@@ -99,7 +152,7 @@ class Call extends EventEmitter {
99
152
  logger.info('call - force cancel, error', e);
100
153
  }
101
154
  }
102
- startConference(withCalls) {
155
+ startConference( /* withCalls: Call[] */) {
103
156
  // @TODO
104
157
  // const participants = [this, ...withCalls].reduce((acc: Record<string, any>, call: Call) => {
105
158
  // acc[call.talkingToIds[0]] = call;
@@ -117,14 +170,14 @@ class Call extends EventEmitter {
117
170
  logger.info('call - mute', { id: this.id });
118
171
  this._sendAction(EstablishedActions.MUTE);
119
172
  this.phone.client.mute(this.sipCall);
120
- this.eventEmitter.emit(EVENT_CALL_MUTED);
173
+ this.emit(EVENT_CALL_MUTED);
121
174
  }
122
175
  unMute() {
123
176
  assertCan(this.callActor, EstablishedActions.UN_MUTE);
124
177
  logger.info('call - un-mute', { id: this.id });
125
178
  this._sendAction(EstablishedActions.UN_MUTE);
126
179
  this.phone.client.unmute(this.sipCall);
127
- this.eventEmitter.emit(EVENT_CALL_UN_MUTED);
180
+ this.emit(EVENT_CALL_UN_MUTED);
128
181
  }
129
182
  async hold() {
130
183
  assertCan(this.callActor, EstablishedActions.HOLD);
@@ -140,7 +193,7 @@ class Call extends EventEmitter {
140
193
  await downgradeToAudio(this.sipCall);
141
194
  }
142
195
  const promise = this.phone.client.hold(this.sipCall, this.isConference(), hasVideo);
143
- this.eventEmitter.emit(EVENT_CALL_HELD);
196
+ this.emit(EVENT_CALL_HELD);
144
197
  return promise;
145
198
  }
146
199
  async resume() {
@@ -167,7 +220,7 @@ class Call extends EventEmitter {
167
220
  this._onScreenSharing(stream, hadVideo, wasDesktop);
168
221
  }
169
222
  };
170
- this.eventEmitter.emit(EVENT_CALL_RESUMED);
223
+ this.emit(EVENT_CALL_RESUMED);
171
224
  return promise.then(() => {
172
225
  const stream = this.getLocalVideoStream();
173
226
  if (wasScreensharing) {
@@ -180,19 +233,37 @@ class Call extends EventEmitter {
180
233
  assertState(this.callActor, States.ESTABLISHED);
181
234
  logger.info('call - turn camera on', { id: this.id });
182
235
  toggleVideo(this.sipCall, true);
183
- this.eventEmitter.emit(EVENT_CAMERA_RESUMED);
236
+ this.emit(EVENT_CAMERA_RESUMED);
184
237
  }
185
238
  turnCameraOff() {
186
239
  assertState(this.callActor, States.ESTABLISHED);
187
240
  logger.info('call - turn camera off', { id: this.id });
188
241
  toggleVideo(this.sipCall, false);
189
- this.eventEmitter.emit(EVENT_CAMERA_DISABLED);
242
+ this.emit(EVENT_CAMERA_DISABLED);
243
+ }
244
+ isMuted() {
245
+ return this._hasEstablishedState(EstablishedStates.MUTED);
246
+ }
247
+ isCameraMuted() {
248
+ return isVideoMuted(this.sipCall);
190
249
  }
191
250
  isHeld() {
192
- return getState(this.callActor) === EstablishedStates.HELD;
251
+ return this._hasEstablishedState(EstablishedStates.HELD);
252
+ }
253
+ isEstablishing() {
254
+ return this.sipCall.state === SessionState.Establishing;
193
255
  }
194
256
  isEstablished() {
195
- return getState(this.callActor) === States.ESTABLISHED;
257
+ return typeof this.state === 'object' && States.ESTABLISHED in this.state;
258
+ }
259
+ isRinging() {
260
+ return this.state === States.RINGING;
261
+ }
262
+ isOutgoing() {
263
+ return this.sipCall instanceof Invitation;
264
+ }
265
+ isIncoming() {
266
+ return !this.isOutgoing();
196
267
  }
197
268
  isConference() {
198
269
  return getPeerConnection(this.sipCall)?.sfu;
@@ -200,7 +271,7 @@ class Call extends EventEmitter {
200
271
  transfer(target) {
201
272
  assertState(this.callActor, States.ESTABLISHED);
202
273
  logger.info('call - transfer', { id: this.id, target });
203
- this.phone.client.transfer(this.sipCall, target);
274
+ return this.phone.client.transfer(this.sipCall, target);
204
275
  }
205
276
  atxfer() {
206
277
  assertState(this.callActor, States.ESTABLISHED);
@@ -320,7 +391,7 @@ class Call extends EventEmitter {
320
391
  catch (e) {
321
392
  console.warn(e);
322
393
  }
323
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_ENDED);
394
+ this.emit(EVENT_SHARE_SCREEN_ENDED);
324
395
  this.currentScreenShare = null;
325
396
  return reinvited;
326
397
  }
@@ -329,9 +400,13 @@ class Call extends EventEmitter {
329
400
  logger.info('call - updrading directly in screensharing mode', { id: this.id, tracks: localStream?.getTracks() });
330
401
  this._onScreenSharing(localStream, false, desktop);
331
402
  }
403
+ onMakeCall() {
404
+ this._bindEvents();
405
+ this._sendAction(Actions.MAKE_CALL);
406
+ }
332
407
  onAccepted() {
333
408
  this._sendAction(Actions.REMOTLY_ACCEPTED);
334
- this.emit(EVENT_CALL_ACCEPTED);
409
+ this.emit(EVENT_CALL_REMOTLY_ACCEPTED);
335
410
  }
336
411
  onProgress() {
337
412
  this.emit(EVENT_PROGRESS);
@@ -345,10 +420,14 @@ class Call extends EventEmitter {
345
420
  onError(error) {
346
421
  this.emit(EVENT_CALL_ERROR, error);
347
422
  }
423
+ onCallIncoming() {
424
+ this._bindEvents();
425
+ this._sendAction(Actions.INCOMING_CALL);
426
+ }
348
427
  onRejected() {
349
428
  this.endTime = new Date();
350
429
  this.emit(EVENT_CALL_REJECTED);
351
- this.phone.removeCall(this);
430
+ this.phone.onCallTerminated(this);
352
431
  }
353
432
  onNetworkStats(stats, previousStats) {
354
433
  this.emit(EVENT_WEB_RTC_STATS, stats, previousStats);
@@ -380,13 +459,24 @@ class Call extends EventEmitter {
380
459
  onReinvite(request, updatedCalleeName, updatedNumber, hadRemoteVideo) {
381
460
  this.emit(EVENT_REINVITE, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
382
461
  }
462
+ updateFrom(call) {
463
+ updateFrom(this, call);
464
+ }
465
+ is(otherCall) {
466
+ return otherCall && this.id && this.id === otherCall.id;
467
+ }
468
+ shouldAutoAnswer() {
469
+ return !!this.sipCall.request?.getHeader('alert-info');
470
+ }
383
471
  get id() {
384
- return getSipSessionId(this.sipCall);
472
+ return getSipCallId(this.sipCall);
473
+ }
474
+ get state() {
475
+ return getState(this.callActor);
385
476
  }
386
- get number() {
387
- const identity = this.sipCall.remoteIdentity || this.sipCall.assertedIdentity;
388
- // @ts-ignore: private
389
- return identity ? identity.uri._normal.user : null;
477
+ _hasEstablishedState(establishedState) {
478
+ const state = this.state;
479
+ return typeof state === 'object' && States.ESTABLISHED in state && state[States.ESTABLISHED] === establishedState;
390
480
  }
391
481
  _bindEvents() {
392
482
  if (this.sipCall instanceof Invitation) {
@@ -396,21 +486,22 @@ class Call extends EventEmitter {
396
486
  logger.trace('call - on sip session canceled', { callId: message.callId, id: this.id });
397
487
  onCancel(message);
398
488
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
399
- this.eventEmitter.emit(EVENT_CALL_CANCELED, elsewhere);
489
+ this.emit(EVENT_CALL_CANCELED, elsewhere);
400
490
  };
401
491
  }
402
- this.sipCall.stateChange.addListener((newState) => {
492
+ this.sipCall?.stateChange?.addListener((newState) => {
403
493
  switch (newState) {
404
494
  case SessionState.Terminating:
405
495
  logger.info('call - terminating', { id: this.id });
406
- this.eventEmitter.emit(EVENT_CALL_TERMINATING);
496
+ this.emit(EVENT_CALL_TERMINATING);
407
497
  break;
408
498
  case SessionState.Terminated:
409
499
  {
410
500
  logger.info('call - terminated', { id: this.id });
411
501
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
412
502
  this.endTime = new Date();
413
- return this.eventEmitter.emit(EVENT_CALL_ENDED);
503
+ this.emit(EVENT_CALL_ENDED);
504
+ return this.phone.onCallTerminated(this);
414
505
  }
415
506
  default:
416
507
  break;
@@ -437,18 +528,17 @@ class Call extends EventEmitter {
437
528
  kind,
438
529
  });
439
530
  if (kind === 'audio') {
440
- return this.eventEmitter.emit(EVENT_AUDIO_STREAM, stream);
531
+ return this.emit(EVENT_AUDIO_STREAM, stream);
441
532
  }
442
- return this.eventEmitter.emit(EVENT_VIDEO_STREAM, stream, event.track.id, event);
533
+ return this.emit(EVENT_VIDEO_STREAM, stream, event.track.id, event);
443
534
  };
444
535
  peerConnection.onremovestream = (event) => {
445
536
  logger.info('call - on remove stream called on the peer connection', {
446
537
  id: event.stream.id,
447
538
  tracks: event.stream.getTracks(),
448
539
  });
449
- this.eventEmitter.emit(EVENT_REMOVE_STREAM, event.stream);
540
+ this.emit(EVENT_REMOVE_STREAM, event.stream);
450
541
  };
451
- // Client events
452
542
  }
453
543
  _downgradeToAudio(withMessage = true) {
454
544
  assertState(this.callActor, States.ESTABLISHED);
@@ -508,7 +598,7 @@ class Call extends EventEmitter {
508
598
  if (screenTrack) {
509
599
  screenTrack.onended = () => {
510
600
  logger.info('call - on screenshare ended', { hadVideo, id: this.id, screenTrack });
511
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_ENDING);
601
+ this.emit(EVENT_SHARE_SCREEN_ENDING);
512
602
  };
513
603
  }
514
604
  this.currentScreenShare = {
@@ -518,10 +608,12 @@ class Call extends EventEmitter {
518
608
  desktop,
519
609
  };
520
610
  setLocalMediaStream(this.sipCall, screenStream);
521
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_STARTED, screenStream);
611
+ this.emit(EVENT_SHARE_SCREEN_STARTED, screenStream);
522
612
  }
523
613
  _sendAction(action) {
614
+ const was = this.state;
524
615
  this.callActor.send({ type: action });
616
+ logger.trace('call - send action', { action, was, state: this.state });
525
617
  }
526
618
  }
527
619
  export default Call;