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

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 (52) hide show
  1. package/dist/wazo-sdk.js +6 -6
  2. package/esm/__tests__/__voice__/call.test.js +44 -2
  3. package/esm/domain/Phone/WebRTCPhone.js +6 -7
  4. package/esm/simple/Phone.js +1 -0
  5. package/esm/state-machine/call-state-machine.js +1 -1
  6. package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  7. package/esm/types/simple/Phone.d.ts.map +1 -1
  8. package/esm/types/state-machine/utils.d.ts +1 -1
  9. package/esm/types/state-machine/utils.d.ts.map +1 -1
  10. package/esm/types/utils/sdp.d.ts +2 -0
  11. package/esm/types/utils/sdp.d.ts.map +1 -1
  12. package/esm/types/utils/webrtc.d.ts +1 -0
  13. package/esm/types/utils/webrtc.d.ts.map +1 -1
  14. package/esm/types/voice/call.d.ts +19 -11
  15. package/esm/types/voice/call.d.ts.map +1 -1
  16. package/esm/types/voice/softphone.d.ts +18 -13
  17. package/esm/types/voice/softphone.d.ts.map +1 -1
  18. package/esm/utils/sdp.js +13 -0
  19. package/esm/utils/webrtc.js +20 -0
  20. package/esm/voice/call.js +90 -30
  21. package/esm/voice/softphone.js +94 -23
  22. package/lib/__tests__/__voice__/call.test.js +43 -1
  23. package/lib/domain/Phone/WebRTCPhone.js +5 -6
  24. package/lib/simple/Phone.js +1 -0
  25. package/lib/state-machine/call-state-machine.js +1 -1
  26. package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  27. package/lib/types/simple/Phone.d.ts.map +1 -1
  28. package/lib/types/state-machine/utils.d.ts +1 -1
  29. package/lib/types/state-machine/utils.d.ts.map +1 -1
  30. package/lib/types/utils/sdp.d.ts +2 -0
  31. package/lib/types/utils/sdp.d.ts.map +1 -1
  32. package/lib/types/utils/webrtc.d.ts +1 -0
  33. package/lib/types/utils/webrtc.d.ts.map +1 -1
  34. package/lib/types/voice/call.d.ts +19 -11
  35. package/lib/types/voice/call.d.ts.map +1 -1
  36. package/lib/types/voice/softphone.d.ts +18 -13
  37. package/lib/types/voice/softphone.d.ts.map +1 -1
  38. package/lib/utils/sdp.js +16 -1
  39. package/lib/utils/webrtc.js +22 -1
  40. package/lib/voice/call.js +87 -28
  41. package/lib/voice/softphone.js +95 -23
  42. package/package.json +1 -1
  43. package/src/__tests__/__voice__/call.test.ts +47 -2
  44. package/src/domain/Phone/WebRTCPhone.ts +9 -9
  45. package/src/simple/Phone.ts +1 -0
  46. package/src/state-machine/call-state-machine.ts +1 -1
  47. package/src/state-machine/utils.ts +2 -2
  48. package/src/utils/sdp.ts +16 -0
  49. package/src/utils/webrtc.ts +23 -1
  50. package/src/voice/call.ts +118 -40
  51. package/src/voice/softphone.ts +116 -30
  52. package/src/web-rtc-client.ts +1 -1
@@ -12,7 +12,7 @@ import WazoWebRTCClient from '../../web-rtc-client';
12
12
  import Emitter from '../../utils/Emitter';
13
13
  import IssueReporter from '../../service/IssueReporter';
14
14
  import { PeerConnection, WazoSession } from '../types';
15
- import { getSipSessionId } from '../../utils/sdp';
15
+ import { getCallDisplayName, getCallNumber, getSipSessionId } from '../../utils/sdp';
16
16
  import { downgradeToAudio, getStreamFromConstraints, getWebRtcStats, setLocalMediaStream, upgradeToVideo } from '../../utils/webrtc';
17
17
 
18
18
  export const ON_USER_AGENT = 'onUserAgent';
@@ -61,6 +61,8 @@ export const MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
61
61
  export const MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
62
62
  export const events = [ON_USER_AGENT, ON_REGISTERED, ON_UNREGISTERED, ON_PROGRESS, ON_CALL_ACCEPTED, ON_CALL_ANSWERED, ON_CALL_INCOMING, ON_CALL_OUTGOING, ON_CALL_MUTED, ON_CALL_UNMUTED, ON_CALL_RESUMED, ON_CALL_HELD, ON_CALL_UNHELD, ON_CAMERA_DISABLED, ON_CALL_FAILED, ON_CALL_ENDED, ON_CALL_REJECTED, ON_MESSAGE, ON_REINVITE, ON_TRACK, ON_AUDIO_STREAM, ON_VIDEO_STREAM, ON_REMOVE_STREAM, ON_SHARE_SCREEN_ENDED, ON_TERMINATE_SOUND, ON_PLAY_RING_SOUND, ON_PLAY_INBOUND_CALL_SIGNAL_SOUND, ON_PLAY_HANGUP_SOUND, ON_PLAY_PROGRESS_SOUND, ON_VIDEO_INPUT_CHANGE, ON_SHARE_SCREEN_STARTED, ON_CALL_ERROR, ON_CHAT, ON_SIGNAL, ON_NETWORK_STATS, ON_DISCONNECTED, ON_EARLY_MEDIA];
63
63
  const logger = IssueReporter.loggerFor('webrtc-phone');
64
+
65
+ // @deprecated: Use Wazo.Voice.Softphone instead
64
66
  export default class WebRTCPhone extends Emitter implements Phone {
65
67
  client: WazoWebRTCClient;
66
68
 
@@ -1783,20 +1785,17 @@ export default class WebRTCPhone extends Emitter implements Phone {
1783
1785
  }
1784
1786
 
1785
1787
  _createCallSession(sipSession: WazoSession, fromSession?: CallSession | null | undefined, extra: Record<string, any> = {}): CallSession {
1786
- // eslint-disable-next-line
1787
- const identity = sipSession ? sipSession.remoteIdentity || sipSession.assertedIdentity : null;
1788
- // @ts-ignore: private
1789
- const number = identity ? identity.uri._normal.user : null;
1790
- const {
1791
- state,
1792
- } = sipSession || {};
1788
+ const number = getCallNumber(sipSession);
1789
+ const displayName = getCallDisplayName(sipSession);
1790
+ const { state } = sipSession || {};
1793
1791
  const sessionId = getSipSessionId(sipSession);
1792
+
1794
1793
  fromSession = fromSession || this.callSessions[sessionId];
1795
1794
  const callSession = new CallSession({
1796
1795
  callId: fromSession && fromSession.callId,
1797
1796
  sipCallId: sessionId,
1798
1797
  sipStatus: state,
1799
- displayName: identity ? identity.displayName || number : number,
1798
+ displayName,
1800
1799
  // @ts-ignore: date / number
1801
1800
  startTime: fromSession ? fromSession.startTime : new Date(),
1802
1801
  creationTime: fromSession ? fromSession.creationTime : null,
@@ -1817,6 +1816,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1817
1816
  ...extra,
1818
1817
  });
1819
1818
  this.callSessions[sessionId] = callSession;
1819
+
1820
1820
  return callSession;
1821
1821
  }
1822
1822
 
@@ -19,6 +19,7 @@ const sipLogger = IssueReporter.loggerFor('sip.js');
19
19
  const protocolLogger = IssueReporter.loggerFor('sip');
20
20
  const protocolDebugMessages = ['Received WebSocket text message:', 'Sending WebSocket message:'];
21
21
 
22
+ // @deprecated: Use Wazo.Voice.Softphone instead
22
23
  export class Phone extends Emitter {
23
24
  client: WazoWebRTCClient;
24
25
 
@@ -43,7 +43,7 @@ export type EstablishedActionTypes = typeof EstablishedActions[keyof typeof Esta
43
43
 
44
44
  const callMachine = setup({
45
45
  guards: {
46
- isRegistered: () => softphone.getState() === SoftphoneStates.REGISTERED,
46
+ isRegistered: () => softphone.state === SoftphoneStates.REGISTERED,
47
47
  },
48
48
  }).createMachine({
49
49
  id: 'call',
@@ -8,8 +8,8 @@ import IssueReporter from '../service/IssueReporter';
8
8
 
9
9
  const logger = IssueReporter.loggerFor('state-machine');
10
10
 
11
- export const getState = (actor: SoftphoneActorRef | CallActorRef): SoftphoneStates | CallStates | EstablishedStateTypes => {
12
- return actor.getSnapshot().value as SoftphoneStates | CallStates | EstablishedStateTypes;
11
+ export const getState = (actor: SoftphoneActorRef | CallActorRef): SoftphoneStates | CallStates | EstablishedStateTypes | Record<CallStates, EstablishedStateTypes> => {
12
+ return actor.getSnapshot().value as SoftphoneStates | CallStates | EstablishedStateTypes | Record<CallStates, EstablishedStateTypes>;
13
13
  };
14
14
 
15
15
  export const can = (actor: SoftphoneActorRef | CallActorRef, action: SoftphoneActions | CallActions | EstablishedCallActions): boolean => {
package/src/utils/sdp.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-underscore-dangle */
1
2
  import sdpParser from 'sdp-transform';
2
3
  import { UserAgent } from 'sip.js/lib/api/user-agent';
3
4
  import { Inviter } from 'sip.js/lib/api';
@@ -174,3 +175,18 @@ export const replaceLocalIpModifier = (description: Record<string, any>) => Prom
174
175
  });
175
176
 
176
177
  export const makeURI = (target: string, host: string): URI | undefined => UserAgent.makeURI(`sip:${target}@${host}`);
178
+
179
+ export const getCallNumber = (sipCall: SipCall): string => {
180
+ // eslint-disable-next-line
181
+ const identity = sipCall ? sipCall.remoteIdentity || sipCall.assertedIdentity : null;
182
+ // @ts-ignore: private
183
+ return identity ? identity.uri._normal.user : null;
184
+ };
185
+
186
+ export const getCallDisplayName = (sipCall: SipCall): string => {
187
+ // eslint-disable-next-line
188
+ const identity = sipCall ? sipCall.remoteIdentity || sipCall.assertedIdentity : null;
189
+ const number = getCallNumber(sipCall);
190
+
191
+ return identity ? identity.displayName || number : number;
192
+ };
@@ -1,4 +1,4 @@
1
- /* eslint-disable no-underscore-dangle, no-param-reassign */
1
+ /* eslint-disable no-underscore-dangle, no-param-reassign, no-restricted-syntax */
2
2
  import type { SessionDescriptionHandler } from 'sip.js/lib/platform/web/session-description-handler/session-description-handler';
3
3
  import type { SessionDescriptionHandlerFactoryOptions } from 'sip.js/lib/platform/web/session-description-handler/session-description-handler-factory-options';
4
4
  import type { SessionDescriptionHandlerConfiguration } from 'sip.js/lib/platform/web/session-description-handler/session-description-handler-configuration';
@@ -246,6 +246,28 @@ export const toggleVideo = (sipCall: SipCall, muteCamera: boolean): void => {
246
246
  }
247
247
  };
248
248
 
249
+ export const isVideoMuted = (sipCall: SipCall): boolean => {
250
+ const sdh = sipCall.sessionDescriptionHandler as SessionDescriptionHandler;
251
+ const pc = sdh?.peerConnection as PeerConnection;
252
+
253
+ if (pc?.getSenders) {
254
+ for (const sender of pc.getSenders()) {
255
+ if (sender && sender.track && sender.track.kind === 'video') {
256
+ return !sender.track.enabled;
257
+ }
258
+ }
259
+ } else {
260
+ for (const stream of pc.getLocalStreams()) {
261
+ // eslint-disable-next-line no-unreachable-loop
262
+ for (const track of stream.getVideoTracks()) {
263
+ return !track.enabled;
264
+ }
265
+ }
266
+ }
267
+
268
+ return true;
269
+ };
270
+
249
271
  export const cleanupStream = (stream: MediaStream): void => {
250
272
  stream.getTracks().filter(track => track.enabled).forEach(track => track.stop());
251
273
  };
package/src/voice/call.ts CHANGED
@@ -8,13 +8,15 @@ import { SessionDescriptionHandler } from 'sip.js/lib/platform/web';
8
8
  import { SessionDescriptionHandlerOptions } from 'sip.js/lib/api';
9
9
  import type { IncomingRequestMessage } from 'sip.js/lib/core/messages/incoming-request-message';
10
10
 
11
- import callStateMachine, { type ActionTypes, Actions, type EstablishedActionTypes, EstablishedActions, States, EstablishedStates, type CallActorRef } from '../state-machine/call-state-machine';
11
+ import callStateMachine, { type ActionTypes, Actions, type EstablishedActionTypes, EstablishedActions, States, type StateTypes, EstablishedStates, type EstablishedStateTypes, type CallActorRef } from '../state-machine/call-state-machine';
12
12
  import { SipCall, PeerConnection } from '../domain/types';
13
+ import ApiCall from '../domain/Call';
14
+
13
15
  import IssueReporter from '../service/IssueReporter';
14
- import { Softphone } from './softphone';
15
- import { getSipSessionId } from '../utils/sdp';
16
+ import softphone, { EVENT_TERMINATE_SOUND, Softphone } from './softphone';
17
+ import { getCallDisplayName, getCallNumber, getSipSessionId } from '../utils/sdp';
16
18
  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';
19
+ import { downgradeToAudio, getLocalStream, getLocalVideoStream, getPeerConnection, getRemoteStream, getRemoteVideoStream, getStreamFromConstraints, getWebRtcStats, hasALocalVideoTrack, hasLocalVideo, hasRemoteVideo, isVideoMuted, isVideoRemotelyHeld, setLocalMediaStream, toggleVideo, upgradeToVideo } from '../utils/webrtc';
18
20
 
19
21
  const logger = IssueReporter.loggerFor('call');
20
22
 
@@ -53,15 +55,12 @@ export const EVENT_SHARE_SCREEN_ENDED = 'onScreenShareEnded';
53
55
  export const EVENT_WEB_RTC_STATS = 'webRtcStats';
54
56
  export const EVENT_CAMERA_RESUMED = 'onCameraResumed';
55
57
  export const EVENT_CAMERA_DISABLED = 'onCameraDisabled';
56
- export const EVENT_TERMINATE_SOUND = 'terminateSound';
57
58
 
58
59
  export const MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
59
60
  export const MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
60
61
  export const MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
61
62
 
62
63
  class Call extends EventEmitter {
63
- eventEmitter: EventEmitter;
64
-
65
64
  callActor: CallActorRef;
66
65
 
67
66
  // Wazo call id, used in Wazo Websocket and API
@@ -81,8 +80,65 @@ class Call extends EventEmitter {
81
80
 
82
81
  shouldSendReinvite = false;
83
82
 
83
+ recording = false;
84
+
85
+ displayName: string | null;
86
+
87
+ number: string | null;
88
+
84
89
  currentScreenShare: Record<string, any> | null;
85
90
 
91
+ static parseCall(apiCall: ApiCall): Call {
92
+ const sipCall = {
93
+ id: apiCall.sipCallId,
94
+ stateChange: {
95
+ addListener: () => {},
96
+ },
97
+ remoteIdentity: {
98
+ uri: {
99
+ _normal: {
100
+ user: apiCall.calleeNumber,
101
+ },
102
+ },
103
+ },
104
+ // Mock sdk so `hasLocalVideo` will return true.
105
+ sessionDescriptionHandler: {
106
+ localMediaStream: {
107
+ getTracks: () => (apiCall.isVideo ? [{ kind: 'video', readyState: 'live' }] : []),
108
+ },
109
+ },
110
+ } as any;
111
+
112
+ const call = new Call(sipCall, softphone);
113
+ // call._sendAction(Actions.ES);
114
+ call.apiId = apiCall.id;
115
+ call.answerTime = new Date(+apiCall.startingTime);
116
+
117
+ // Update call state
118
+ const snapshot = call.callActor.getSnapshot();
119
+
120
+ if (apiCall.isUp()) {
121
+ snapshot.value = { [States.ESTABLISHED]: EstablishedStates.ONGOING };
122
+ }
123
+
124
+ if (apiCall.muted) {
125
+ snapshot.value = { [States.ESTABLISHED]: EstablishedStates.MUTED };
126
+ }
127
+
128
+ if (apiCall.isRinging()) {
129
+ snapshot.value = States.RINGING;
130
+ }
131
+
132
+ if (apiCall.isRecording()) {
133
+ call.recording = true;
134
+ }
135
+
136
+ // @ts-ignore
137
+ call.callActor.update(snapshot);
138
+
139
+ return call;
140
+ }
141
+
86
142
  constructor(sipCall: SipCall, phone: Softphone) {
87
143
  super();
88
144
 
@@ -94,6 +150,9 @@ class Call extends EventEmitter {
94
150
  this.phone = phone;
95
151
  this.sipCall = sipCall;
96
152
 
153
+ this.number = getCallNumber(sipCall);
154
+ this.displayName = getCallDisplayName(sipCall);
155
+
97
156
  this._bindEvents();
98
157
  }
99
158
 
@@ -123,7 +182,7 @@ class Call extends EventEmitter {
123
182
  assertCan(this.callActor, Actions.REJECT);
124
183
  logger.info('call - reject', { id: this.id });
125
184
 
126
- this.eventEmitter.emit(EVENT_TERMINATE_SOUND, 'call rejected locally');
185
+ this.phone.emit(EVENT_TERMINATE_SOUND, 'call rejected locally');
127
186
 
128
187
  this.shouldSendReinvite = false;
129
188
 
@@ -137,7 +196,7 @@ class Call extends EventEmitter {
137
196
  await this.phone.client.hangup(this.sipCall);
138
197
 
139
198
  // Remove this call from softphone's calls
140
- this.phone.removeCall(this);
199
+ this.phone.onCallTerminated(this);
141
200
 
142
201
  return true;
143
202
  }
@@ -151,7 +210,7 @@ class Call extends EventEmitter {
151
210
  }
152
211
  }
153
212
 
154
- startConference(withCalls: Call[]) {
213
+ startConference(/* withCalls: Call[] */) {
155
214
  // @TODO
156
215
  // const participants = [this, ...withCalls].reduce((acc: Record<string, any>, call: Call) => {
157
216
  // acc[call.talkingToIds[0]] = call;
@@ -174,7 +233,7 @@ class Call extends EventEmitter {
174
233
 
175
234
  this.phone.client.mute(this.sipCall);
176
235
 
177
- this.eventEmitter.emit(EVENT_CALL_MUTED);
236
+ this.emit(EVENT_CALL_MUTED);
178
237
  }
179
238
 
180
239
  unMute() {
@@ -185,7 +244,7 @@ class Call extends EventEmitter {
185
244
 
186
245
  this.phone.client.unmute(this.sipCall);
187
246
 
188
- this.eventEmitter.emit(EVENT_CALL_UN_MUTED);
247
+ this.emit(EVENT_CALL_UN_MUTED);
189
248
  }
190
249
 
191
250
  async hold() {
@@ -208,7 +267,7 @@ class Call extends EventEmitter {
208
267
 
209
268
  const promise = this.phone.client.hold(this.sipCall, this.isConference(), hasVideo);
210
269
 
211
- this.eventEmitter.emit(EVENT_CALL_HELD);
270
+ this.emit(EVENT_CALL_HELD);
212
271
 
213
272
  return promise;
214
273
  }
@@ -244,7 +303,7 @@ class Call extends EventEmitter {
244
303
  }
245
304
  };
246
305
 
247
- this.eventEmitter.emit(EVENT_CALL_RESUMED);
306
+ this.emit(EVENT_CALL_RESUMED);
248
307
 
249
308
  return promise.then(() => {
250
309
  const stream = this.getLocalVideoStream();
@@ -261,7 +320,7 @@ class Call extends EventEmitter {
261
320
  logger.info('call - turn camera on', { id: this.id });
262
321
  toggleVideo(this.sipCall, true);
263
322
 
264
- this.eventEmitter.emit(EVENT_CAMERA_RESUMED);
323
+ this.emit(EVENT_CAMERA_RESUMED);
265
324
  }
266
325
 
267
326
  turnCameraOff(): void {
@@ -269,15 +328,23 @@ class Call extends EventEmitter {
269
328
  logger.info('call - turn camera off', { id: this.id });
270
329
  toggleVideo(this.sipCall, false);
271
330
 
272
- this.eventEmitter.emit(EVENT_CAMERA_DISABLED);
331
+ this.emit(EVENT_CAMERA_DISABLED);
332
+ }
333
+
334
+ isMuted() {
335
+ return this._hasEstablishedState(EstablishedStates.MUTED);
336
+ }
337
+
338
+ isCameraMuted() {
339
+ return isVideoMuted(this.sipCall);
273
340
  }
274
341
 
275
342
  isHeld() {
276
- return getState(this.callActor) === EstablishedStates.HELD;
343
+ return this._hasEstablishedState(EstablishedStates.HELD);
277
344
  }
278
345
 
279
346
  isEstablished() {
280
- return getState(this.callActor) === States.ESTABLISHED;
347
+ return States.ESTABLISHED in (this.state as Record<StateTypes, EstablishedStateTypes>);
281
348
  }
282
349
 
283
350
  isConference(): boolean {
@@ -446,7 +513,7 @@ class Call extends EventEmitter {
446
513
  console.warn(e);
447
514
  }
448
515
 
449
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_ENDED);
516
+ this.emit(EVENT_SHARE_SCREEN_ENDED);
450
517
  this.currentScreenShare = null;
451
518
 
452
519
  return reinvited;
@@ -480,12 +547,16 @@ class Call extends EventEmitter {
480
547
  this.emit(EVENT_CALL_ERROR, error);
481
548
  }
482
549
 
550
+ onCallIncoming() {
551
+ this._sendAction(Actions.INCOMING_CALL);
552
+ }
553
+
483
554
  onRejected() {
484
555
  this.endTime = new Date();
485
556
 
486
557
  this.emit(EVENT_CALL_REJECTED);
487
558
 
488
- this.phone.removeCall(this);
559
+ this.phone.onCallTerminated(this);
489
560
  }
490
561
 
491
562
  onNetworkStats(stats: Record<string, any>, previousStats: Record<string, any>) {
@@ -524,6 +595,10 @@ class Call extends EventEmitter {
524
595
  return isVideoRemotelyHeld(this.sipCall);
525
596
  }
526
597
 
598
+ isRinging() {
599
+ return this.state === States.RINGING;
600
+ }
601
+
527
602
  onReinvite(request: IncomingRequestMessage, updatedCalleeName: string, updatedNumber: string, hadRemoteVideo: boolean) {
528
603
  this.emit(EVENT_REINVITE, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
529
604
  }
@@ -532,13 +607,16 @@ class Call extends EventEmitter {
532
607
  return getSipSessionId(this.sipCall);
533
608
  }
534
609
 
535
- get number() {
536
- const identity = this.sipCall.remoteIdentity || this.sipCall.assertedIdentity;
537
- // @ts-ignore: private
538
- return identity ? identity.uri._normal.user : null;
610
+ get state(): StateTypes | Record<StateTypes, EstablishedStateTypes> {
611
+ return getState(this.callActor) as StateTypes | Record<StateTypes, EstablishedStateTypes>;
539
612
  }
540
613
 
541
- _bindEvents() {
614
+ private _hasEstablishedState(establishedState: EstablishedStateTypes) {
615
+ const state = this.state as Record<StateTypes, EstablishedStateTypes>;
616
+ return States.ESTABLISHED in state && state[States.ESTABLISHED] === establishedState;
617
+ }
618
+
619
+ private _bindEvents() {
542
620
  if (this.sipCall instanceof Invitation) {
543
621
  // Monkey patch to know when canceled with the CANCEL message
544
622
  const onCancel = (this.sipCall as Invitation)._onCancel.bind(this.sipCall);
@@ -548,7 +626,7 @@ class Call extends EventEmitter {
548
626
  onCancel(message);
549
627
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
550
628
 
551
- this.eventEmitter.emit(EVENT_CALL_CANCELED, elsewhere);
629
+ this.emit(EVENT_CALL_CANCELED, elsewhere);
552
630
  };
553
631
  }
554
632
 
@@ -556,7 +634,7 @@ class Call extends EventEmitter {
556
634
  switch (newState) {
557
635
  case SessionState.Terminating:
558
636
  logger.info('call - terminating', { id: this.id });
559
- this.eventEmitter.emit(EVENT_CALL_TERMINATING);
637
+ this.emit(EVENT_CALL_TERMINATING);
560
638
  break;
561
639
 
562
640
  case SessionState.Terminated:
@@ -566,7 +644,9 @@ class Call extends EventEmitter {
566
644
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
567
645
  this.endTime = new Date();
568
646
 
569
- return this.eventEmitter.emit(EVENT_CALL_ENDED);
647
+ this.emit(EVENT_CALL_ENDED);
648
+
649
+ return this.phone.onCallTerminated(this);
570
650
  }
571
651
 
572
652
  default:
@@ -599,10 +679,10 @@ class Call extends EventEmitter {
599
679
  });
600
680
 
601
681
  if (kind === 'audio') {
602
- return this.eventEmitter.emit(EVENT_AUDIO_STREAM, stream);
682
+ return this.emit(EVENT_AUDIO_STREAM, stream);
603
683
  }
604
684
 
605
- return this.eventEmitter.emit(EVENT_VIDEO_STREAM, stream, event.track.id, event);
685
+ return this.emit(EVENT_VIDEO_STREAM, stream, event.track.id, event);
606
686
  };
607
687
 
608
688
  peerConnection.onremovestream = (event: any) => {
@@ -610,13 +690,11 @@ class Call extends EventEmitter {
610
690
  id: event.stream.id,
611
691
  tracks: event.stream.getTracks(),
612
692
  });
613
- this.eventEmitter.emit(EVENT_REMOVE_STREAM, event.stream);
693
+ this.emit(EVENT_REMOVE_STREAM, event.stream);
614
694
  };
615
-
616
- // Client events
617
695
  }
618
696
 
619
- _downgradeToAudio(withMessage = true) {
697
+ private _downgradeToAudio(withMessage = true) {
620
698
  assertState(this.callActor, States.ESTABLISHED);
621
699
  logger.info('call - downgrade to audio', { id: this.id, withMessage });
622
700
 
@@ -630,7 +708,7 @@ class Call extends EventEmitter {
630
708
  }
631
709
 
632
710
  // Returns true if we need to send a re-INVITE request
633
- async _upgradeToVideo(options: ReinviteOptions = {}): Promise<boolean> {
711
+ private async _upgradeToVideo(options: ReinviteOptions = {}): Promise<boolean> {
634
712
  assertState(this.callActor, States.ESTABLISHED);
635
713
  logger.info('call - upgrade to video', { id: this.id, ...options });
636
714
 
@@ -660,7 +738,7 @@ class Call extends EventEmitter {
660
738
  return false;
661
739
  }
662
740
 
663
- _sendReinviteMessage(isUpgrade: boolean) {
741
+ private _sendReinviteMessage(isUpgrade: boolean) {
664
742
  assertState(this.callActor, States.ESTABLISHED);
665
743
  logger.info('call - sending reinvite message', { id: this.id, isUpgrade });
666
744
 
@@ -679,7 +757,7 @@ class Call extends EventEmitter {
679
757
  }, 2500);
680
758
  }
681
759
 
682
- _onScreenSharing(screenStream: MediaStream, hadVideo: boolean, desktop?: boolean | null | undefined) {
760
+ private _onScreenSharing(screenStream: MediaStream, hadVideo: boolean, desktop?: boolean | null | undefined) {
683
761
  const screenTrack = screenStream.getVideoTracks()[0];
684
762
  const pc = this.phone.client.getPeerConnection(this.id);
685
763
  const sender = pc && pc.getSenders && pc.getSenders().find((s) => s && s.track && s.track.kind === 'video');
@@ -690,7 +768,7 @@ class Call extends EventEmitter {
690
768
  screenTrack.onended = () => {
691
769
  logger.info('call - on screenshare ended', { hadVideo, id: this.id, screenTrack });
692
770
 
693
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_ENDING);
771
+ this.emit(EVENT_SHARE_SCREEN_ENDING);
694
772
  };
695
773
  }
696
774
 
@@ -702,10 +780,10 @@ class Call extends EventEmitter {
702
780
  };
703
781
 
704
782
  setLocalMediaStream(this.sipCall, screenStream);
705
- this.eventEmitter.emit(EVENT_SHARE_SCREEN_STARTED, screenStream);
783
+ this.emit(EVENT_SHARE_SCREEN_STARTED, screenStream);
706
784
  }
707
785
 
708
- _sendAction(action: ActionTypes | EstablishedActionTypes) {
786
+ private _sendAction(action: ActionTypes | EstablishedActionTypes) {
709
787
  this.callActor.send({ type: action });
710
788
  }
711
789
  }