@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.
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 +10 -4
  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 +131 -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 +10 -4
  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 +132 -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 +14 -6
  144. package/src/utils/sdp.ts +26 -11
  145. package/src/utils/webrtc.ts +26 -4
  146. package/src/voice/call.ts +170 -50
  147. package/src/voice/softphone.ts +180 -41
  148. package/src/web-rtc-client.ts +106 -99
package/src/voice/call.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
2
  import { EventEmitter } from 'events';
3
3
  import { createActor } from 'xstate';
4
+ import { Inviter } from 'sip.js/lib/api/inviter';
4
5
  import { Invitation } from 'sip.js/lib/api/invitation';
5
6
  import { SessionState } from 'sip.js/lib/api/session-state';
6
7
  import { OutgoingInviteRequest } from 'sip.js/lib/core';
@@ -8,13 +9,16 @@ import { SessionDescriptionHandler } from 'sip.js/lib/platform/web';
8
9
  import { SessionDescriptionHandlerOptions } from 'sip.js/lib/api';
9
10
  import type { IncomingRequestMessage } from 'sip.js/lib/core/messages/incoming-request-message';
10
11
 
11
- import callStateMachine, { type ActionTypes, Actions, type EstablishedActionTypes, EstablishedActions, States, EstablishedStates, type CallActorRef } from '../state-machine/call-state-machine';
12
+ import callStateMachine, { type ActionTypes, Actions, type EstablishedActionTypes, EstablishedActions, States, type StateTypes, EstablishedStates, type EstablishedStateTypes, type CallActorRef } from '../state-machine/call-state-machine';
12
13
  import { SipCall, PeerConnection } from '../domain/types';
14
+ import ApiCall from '../domain/Call';
15
+ import newFrom from '../utils/new-from';
16
+ import updateFrom from '../utils/update-from';
13
17
  import IssueReporter from '../service/IssueReporter';
14
- import { Softphone } from './softphone';
15
- import { getSipSessionId } from '../utils/sdp';
18
+ import softphone, { Softphone } from './softphone';
19
+ import { getCallDisplayName, getCallNumber, getSipCallId } from '../utils/sdp';
16
20
  import { assertCan, assertState, getState } from '../state-machine/utils';
17
- import { downgradeToAudio, getLocalStream, getLocalVideoStream, getPeerConnection, getRemoteStream, getRemoteVideoStream, getStreamFromConstraints, getWebRtcStats, hasALocalVideoTrack, hasLocalVideo, hasRemoteVideo, isVideoRemotelyHeld, setLocalMediaStream, toggleVideo, upgradeToVideo } from '../utils/webrtc';
21
+ import { downgradeToAudio, getLocalStream, getLocalVideoStream, getPeerConnection, getRemoteStream, getRemoteVideoStream, getStreamFromConstraints, getWebRtcStats, hasALocalVideoTrack, hasLocalVideo, hasRemoteVideo, isVideoMuted, isVideoRemotelyHeld, setLocalMediaStream, toggleVideo, upgradeToVideo } from '../utils/webrtc';
18
22
 
19
23
  const logger = IssueReporter.loggerFor('call');
20
24
 
@@ -30,7 +34,8 @@ export type ReinviteOptions = {
30
34
  };
31
35
 
32
36
  // Events
33
- export const EVENT_CALL_ACCEPTED = 'accepted';
37
+ export const EVENT_CALL_REMOTLY_ACCEPTED = 'remotelyAccepted';
38
+ export const EVENT_CALL_LOCALLY_ACCEPTED = 'locallyAccepted';
34
39
  export const EVENT_CALL_CANCELED = 'canceled';
35
40
  export const EVENT_PROGRESS = 'progress';
36
41
  export const EVENT_EARLY_MEDIA = 'earlyMedia';
@@ -53,15 +58,12 @@ export const EVENT_SHARE_SCREEN_ENDED = 'onScreenShareEnded';
53
58
  export const EVENT_WEB_RTC_STATS = 'webRtcStats';
54
59
  export const EVENT_CAMERA_RESUMED = 'onCameraResumed';
55
60
  export const EVENT_CAMERA_DISABLED = 'onCameraDisabled';
56
- export const EVENT_TERMINATE_SOUND = 'terminateSound';
57
61
 
58
62
  export const MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
59
63
  export const MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
60
64
  export const MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
61
65
 
62
66
  class Call extends EventEmitter {
63
- eventEmitter: EventEmitter;
64
-
65
67
  callActor: CallActorRef;
66
68
 
67
69
  // Wazo call id, used in Wazo Websocket and API
@@ -81,8 +83,68 @@ class Call extends EventEmitter {
81
83
 
82
84
  shouldSendReinvite = false;
83
85
 
86
+ recording = false;
87
+
88
+ displayName: string | null;
89
+
90
+ number: string | null;
91
+
84
92
  currentScreenShare: Record<string, any> | null;
85
93
 
94
+ static newFrom(call: Call) {
95
+ return newFrom(call, Call);
96
+ }
97
+
98
+ static parseCall(apiCall: ApiCall): Call {
99
+ const sipCall = {
100
+ id: apiCall.sipCallId,
101
+ stateChange: {
102
+ addListener: () => {},
103
+ },
104
+ remoteIdentity: {
105
+ uri: {
106
+ _normal: {
107
+ user: apiCall.calleeNumber,
108
+ },
109
+ },
110
+ },
111
+ // Mock sdk so `hasLocalVideo` will return true.
112
+ sessionDescriptionHandler: {
113
+ localMediaStream: {
114
+ getTracks: () => (apiCall.isVideo ? [{ kind: 'video', readyState: 'live' }] : []),
115
+ },
116
+ },
117
+ } as any;
118
+
119
+ const call = new Call(sipCall, softphone);
120
+ call.apiId = apiCall.id;
121
+ call.answerTime = new Date(+apiCall.startingTime);
122
+
123
+ // Update call state
124
+ const snapshot = call.callActor.getSnapshot();
125
+
126
+ if (apiCall.isUp()) {
127
+ snapshot.value = { [States.ESTABLISHED]: EstablishedStates.ONGOING };
128
+ }
129
+
130
+ if (apiCall.muted) {
131
+ snapshot.value = { [States.ESTABLISHED]: EstablishedStates.MUTED };
132
+ }
133
+
134
+ if (apiCall.isRinging()) {
135
+ snapshot.value = States.RINGING;
136
+ }
137
+
138
+ if (apiCall.isRecording()) {
139
+ call.recording = true;
140
+ }
141
+
142
+ // @ts-ignore
143
+ call.callActor.update(snapshot);
144
+
145
+ return call;
146
+ }
147
+
86
148
  constructor(sipCall: SipCall, phone: Softphone) {
87
149
  super();
88
150
 
@@ -94,7 +156,8 @@ class Call extends EventEmitter {
94
156
  this.phone = phone;
95
157
  this.sipCall = sipCall;
96
158
 
97
- this._bindEvents();
159
+ this.number = getCallNumber(sipCall);
160
+ this.displayName = getCallDisplayName(sipCall);
98
161
  }
99
162
 
100
163
  async accept(options: AcceptOptions = {}): Promise<string | null> {
@@ -111,6 +174,8 @@ class Call extends EventEmitter {
111
174
  return this.phone.client.answer(this.sipCall as Invitation, options.withCamera).then(() => {
112
175
  logger.info('call - accepted', { id: this.id, ...options });
113
176
 
177
+ this.emit(EVENT_CALL_LOCALLY_ACCEPTED, this);
178
+
114
179
  return this.id;
115
180
  }).catch(e => {
116
181
  logger.error(e);
@@ -123,21 +188,23 @@ class Call extends EventEmitter {
123
188
  assertCan(this.callActor, Actions.REJECT);
124
189
  logger.info('call - reject', { id: this.id });
125
190
 
126
- this.eventEmitter.emit(EVENT_TERMINATE_SOUND, 'call rejected locally');
127
-
128
- this.shouldSendReinvite = false;
129
-
130
- return this.hangup();
191
+ return this._terminate();
131
192
  }
132
193
 
133
194
  async hangup(): Promise<boolean> {
134
195
  assertCan(this.callActor, Actions.HANGUP);
135
196
  logger.info('call - hangup', { id: this.id });
136
197
 
198
+ return this._terminate();
199
+ }
200
+
201
+ async _terminate(): Promise<boolean> {
137
202
  await this.phone.client.hangup(this.sipCall);
138
203
 
204
+ this.shouldSendReinvite = false;
205
+
139
206
  // Remove this call from softphone's calls
140
- this.phone.removeCall(this);
207
+ this.phone.onCallTerminated(this);
141
208
 
142
209
  return true;
143
210
  }
@@ -151,7 +218,7 @@ class Call extends EventEmitter {
151
218
  }
152
219
  }
153
220
 
154
- startConference(withCalls: Call[]) {
221
+ startConference(/* withCalls: Call[] */) {
155
222
  // @TODO
156
223
  // const participants = [this, ...withCalls].reduce((acc: Record<string, any>, call: Call) => {
157
224
  // acc[call.talkingToIds[0]] = call;
@@ -174,7 +241,7 @@ class Call extends EventEmitter {
174
241
 
175
242
  this.phone.client.mute(this.sipCall);
176
243
 
177
- this.eventEmitter.emit(EVENT_CALL_MUTED);
244
+ this.emit(EVENT_CALL_MUTED);
178
245
  }
179
246
 
180
247
  unMute() {
@@ -185,7 +252,7 @@ class Call extends EventEmitter {
185
252
 
186
253
  this.phone.client.unmute(this.sipCall);
187
254
 
188
- this.eventEmitter.emit(EVENT_CALL_UN_MUTED);
255
+ this.emit(EVENT_CALL_UN_MUTED);
189
256
  }
190
257
 
191
258
  async hold() {
@@ -208,7 +275,7 @@ class Call extends EventEmitter {
208
275
 
209
276
  const promise = this.phone.client.hold(this.sipCall, this.isConference(), hasVideo);
210
277
 
211
- this.eventEmitter.emit(EVENT_CALL_HELD);
278
+ this.emit(EVENT_CALL_HELD);
212
279
 
213
280
  return promise;
214
281
  }
@@ -244,7 +311,7 @@ class Call extends EventEmitter {
244
311
  }
245
312
  };
246
313
 
247
- this.eventEmitter.emit(EVENT_CALL_RESUMED);
314
+ this.emit(EVENT_CALL_RESUMED);
248
315
 
249
316
  return promise.then(() => {
250
317
  const stream = this.getLocalVideoStream();
@@ -261,7 +328,7 @@ class Call extends EventEmitter {
261
328
  logger.info('call - turn camera on', { id: this.id });
262
329
  toggleVideo(this.sipCall, true);
263
330
 
264
- this.eventEmitter.emit(EVENT_CAMERA_RESUMED);
331
+ this.emit(EVENT_CAMERA_RESUMED);
265
332
  }
266
333
 
267
334
  turnCameraOff(): void {
@@ -269,15 +336,39 @@ class Call extends EventEmitter {
269
336
  logger.info('call - turn camera off', { id: this.id });
270
337
  toggleVideo(this.sipCall, false);
271
338
 
272
- this.eventEmitter.emit(EVENT_CAMERA_DISABLED);
339
+ this.emit(EVENT_CAMERA_DISABLED);
340
+ }
341
+
342
+ isMuted() {
343
+ return this._hasEstablishedState(EstablishedStates.MUTED);
344
+ }
345
+
346
+ isCameraMuted() {
347
+ return isVideoMuted(this.sipCall);
273
348
  }
274
349
 
275
350
  isHeld() {
276
- return getState(this.callActor) === EstablishedStates.HELD;
351
+ return this._hasEstablishedState(EstablishedStates.HELD);
352
+ }
353
+
354
+ isEstablishing() {
355
+ return this.sipCall.state === SessionState.Establishing;
277
356
  }
278
357
 
279
358
  isEstablished() {
280
- return getState(this.callActor) === States.ESTABLISHED;
359
+ return typeof this.state === 'object' && States.ESTABLISHED in (this.state as Record<StateTypes, EstablishedStateTypes>);
360
+ }
361
+
362
+ isRinging() {
363
+ return this.state === States.RINGING;
364
+ }
365
+
366
+ isOutgoing() {
367
+ return this.sipCall instanceof Inviter;
368
+ }
369
+
370
+ isIncoming() {
371
+ return !this.isOutgoing();
281
372
  }
282
373
 
283
374
  isConference(): boolean {
@@ -288,7 +379,7 @@ class Call extends EventEmitter {
288
379
  assertState(this.callActor, States.ESTABLISHED);
289
380
  logger.info('call - transfer', { id: this.id, target });
290
381
 
291
- this.phone.client.transfer(this.sipCall, target);
382
+ return this.phone.client.transfer(this.sipCall, target);
292
383
  }
293
384
 
294
385
  atxfer(): Record<string, any> | null | undefined {
@@ -446,7 +537,7 @@ class Call extends EventEmitter {
446
537
  console.warn(e);
447
538
  }
448
539
 
449
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_ENDED);
540
+ this.emit(EVENT_SHARE_SCREEN_ENDED);
450
541
  this.currentScreenShare = null;
451
542
 
452
543
  return reinvited;
@@ -459,9 +550,15 @@ class Call extends EventEmitter {
459
550
  this._onScreenSharing(localStream as MediaStream, false, desktop);
460
551
  }
461
552
 
553
+ onMakeCall() {
554
+ this._bindEvents();
555
+
556
+ this._sendAction(Actions.MAKE_CALL);
557
+ }
558
+
462
559
  onAccepted() {
463
560
  this._sendAction(Actions.REMOTLY_ACCEPTED);
464
- this.emit(EVENT_CALL_ACCEPTED);
561
+ this.emit(EVENT_CALL_REMOTLY_ACCEPTED);
465
562
  }
466
563
 
467
564
  onProgress() {
@@ -480,12 +577,18 @@ class Call extends EventEmitter {
480
577
  this.emit(EVENT_CALL_ERROR, error);
481
578
  }
482
579
 
580
+ onCallIncoming() {
581
+ this._bindEvents();
582
+
583
+ this._sendAction(Actions.INCOMING_CALL);
584
+ }
585
+
483
586
  onRejected() {
484
587
  this.endTime = new Date();
485
588
 
486
589
  this.emit(EVENT_CALL_REJECTED);
487
590
 
488
- this.phone.removeCall(this);
591
+ this.phone.onCallTerminated(this);
489
592
  }
490
593
 
491
594
  onNetworkStats(stats: Record<string, any>, previousStats: Record<string, any>) {
@@ -528,17 +631,32 @@ class Call extends EventEmitter {
528
631
  this.emit(EVENT_REINVITE, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
529
632
  }
530
633
 
634
+ updateFrom(call: Call) {
635
+ updateFrom(this, call);
636
+ }
637
+
638
+ is(otherCall: Call) {
639
+ return otherCall && this.id && this.id === otherCall.id;
640
+ }
641
+
642
+ shouldAutoAnswer() {
643
+ return !!this.sipCall.request?.getHeader('alert-info');
644
+ }
645
+
531
646
  get id() {
532
- return getSipSessionId(this.sipCall);
647
+ return getSipCallId(this.sipCall);
533
648
  }
534
649
 
535
- get number() {
536
- const identity = this.sipCall.remoteIdentity || this.sipCall.assertedIdentity;
537
- // @ts-ignore: private
538
- return identity ? identity.uri._normal.user : null;
650
+ get state(): StateTypes | Record<StateTypes, EstablishedStateTypes> {
651
+ return getState(this.callActor) as StateTypes | Record<StateTypes, EstablishedStateTypes>;
539
652
  }
540
653
 
541
- _bindEvents() {
654
+ private _hasEstablishedState(establishedState: EstablishedStateTypes) {
655
+ const state = this.state as Record<StateTypes, EstablishedStateTypes>;
656
+ return typeof state === 'object' && States.ESTABLISHED in state && state[States.ESTABLISHED] === establishedState;
657
+ }
658
+
659
+ private _bindEvents() {
542
660
  if (this.sipCall instanceof Invitation) {
543
661
  // Monkey patch to know when canceled with the CANCEL message
544
662
  const onCancel = (this.sipCall as Invitation)._onCancel.bind(this.sipCall);
@@ -548,15 +666,15 @@ class Call extends EventEmitter {
548
666
  onCancel(message);
549
667
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
550
668
 
551
- this.eventEmitter.emit(EVENT_CALL_CANCELED, elsewhere);
669
+ this.emit(EVENT_CALL_CANCELED, elsewhere);
552
670
  };
553
671
  }
554
672
 
555
- this.sipCall.stateChange.addListener((newState: SessionState) => {
673
+ this.sipCall?.stateChange?.addListener((newState: SessionState) => {
556
674
  switch (newState) {
557
675
  case SessionState.Terminating:
558
676
  logger.info('call - terminating', { id: this.id });
559
- this.eventEmitter.emit(EVENT_CALL_TERMINATING);
677
+ this.emit(EVENT_CALL_TERMINATING);
560
678
  break;
561
679
 
562
680
  case SessionState.Terminated:
@@ -566,7 +684,9 @@ class Call extends EventEmitter {
566
684
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
567
685
  this.endTime = new Date();
568
686
 
569
- return this.eventEmitter.emit(EVENT_CALL_ENDED);
687
+ this.emit(EVENT_CALL_ENDED);
688
+
689
+ return this.phone.onCallTerminated(this);
570
690
  }
571
691
 
572
692
  default:
@@ -599,10 +719,10 @@ class Call extends EventEmitter {
599
719
  });
600
720
 
601
721
  if (kind === 'audio') {
602
- return this.eventEmitter.emit(EVENT_AUDIO_STREAM, stream);
722
+ return this.emit(EVENT_AUDIO_STREAM, stream);
603
723
  }
604
724
 
605
- return this.eventEmitter.emit(EVENT_VIDEO_STREAM, stream, event.track.id, event);
725
+ return this.emit(EVENT_VIDEO_STREAM, stream, event.track.id, event);
606
726
  };
607
727
 
608
728
  peerConnection.onremovestream = (event: any) => {
@@ -610,13 +730,11 @@ class Call extends EventEmitter {
610
730
  id: event.stream.id,
611
731
  tracks: event.stream.getTracks(),
612
732
  });
613
- this.eventEmitter.emit(EVENT_REMOVE_STREAM, event.stream);
733
+ this.emit(EVENT_REMOVE_STREAM, event.stream);
614
734
  };
615
-
616
- // Client events
617
735
  }
618
736
 
619
- _downgradeToAudio(withMessage = true) {
737
+ private _downgradeToAudio(withMessage = true) {
620
738
  assertState(this.callActor, States.ESTABLISHED);
621
739
  logger.info('call - downgrade to audio', { id: this.id, withMessage });
622
740
 
@@ -630,7 +748,7 @@ class Call extends EventEmitter {
630
748
  }
631
749
 
632
750
  // Returns true if we need to send a re-INVITE request
633
- async _upgradeToVideo(options: ReinviteOptions = {}): Promise<boolean> {
751
+ private async _upgradeToVideo(options: ReinviteOptions = {}): Promise<boolean> {
634
752
  assertState(this.callActor, States.ESTABLISHED);
635
753
  logger.info('call - upgrade to video', { id: this.id, ...options });
636
754
 
@@ -660,7 +778,7 @@ class Call extends EventEmitter {
660
778
  return false;
661
779
  }
662
780
 
663
- _sendReinviteMessage(isUpgrade: boolean) {
781
+ private _sendReinviteMessage(isUpgrade: boolean) {
664
782
  assertState(this.callActor, States.ESTABLISHED);
665
783
  logger.info('call - sending reinvite message', { id: this.id, isUpgrade });
666
784
 
@@ -679,7 +797,7 @@ class Call extends EventEmitter {
679
797
  }, 2500);
680
798
  }
681
799
 
682
- _onScreenSharing(screenStream: MediaStream, hadVideo: boolean, desktop?: boolean | null | undefined) {
800
+ private _onScreenSharing(screenStream: MediaStream, hadVideo: boolean, desktop?: boolean | null | undefined) {
683
801
  const screenTrack = screenStream.getVideoTracks()[0];
684
802
  const pc = this.phone.client.getPeerConnection(this.id);
685
803
  const sender = pc && pc.getSenders && pc.getSenders().find((s) => s && s.track && s.track.kind === 'video');
@@ -690,7 +808,7 @@ class Call extends EventEmitter {
690
808
  screenTrack.onended = () => {
691
809
  logger.info('call - on screenshare ended', { hadVideo, id: this.id, screenTrack });
692
810
 
693
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_ENDING);
811
+ this.emit(EVENT_SHARE_SCREEN_ENDING);
694
812
  };
695
813
  }
696
814
 
@@ -702,11 +820,13 @@ class Call extends EventEmitter {
702
820
  };
703
821
 
704
822
  setLocalMediaStream(this.sipCall, screenStream);
705
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_STARTED, screenStream);
823
+ this.emit(EVENT_SHARE_SCREEN_STARTED, screenStream);
706
824
  }
707
825
 
708
- _sendAction(action: ActionTypes | EstablishedActionTypes) {
826
+ private _sendAction(action: ActionTypes | EstablishedActionTypes) {
827
+ const was = this.state;
709
828
  this.callActor.send({ type: action });
829
+ logger.trace('call - send action', { action, was, state: this.state });
710
830
  }
711
831
  }
712
832