@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.
- package/dist/wazo-sdk.js +6 -6
- package/esm/__tests__/__voice__/call.test.js +44 -2
- package/esm/domain/Phone/WebRTCPhone.js +6 -7
- package/esm/simple/Phone.js +1 -0
- package/esm/state-machine/call-state-machine.js +1 -1
- package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
- package/esm/types/simple/Phone.d.ts.map +1 -1
- package/esm/types/state-machine/utils.d.ts +1 -1
- package/esm/types/state-machine/utils.d.ts.map +1 -1
- package/esm/types/utils/sdp.d.ts +2 -0
- package/esm/types/utils/sdp.d.ts.map +1 -1
- package/esm/types/utils/webrtc.d.ts +1 -0
- package/esm/types/utils/webrtc.d.ts.map +1 -1
- package/esm/types/voice/call.d.ts +19 -11
- package/esm/types/voice/call.d.ts.map +1 -1
- package/esm/types/voice/softphone.d.ts +18 -13
- package/esm/types/voice/softphone.d.ts.map +1 -1
- package/esm/utils/sdp.js +13 -0
- package/esm/utils/webrtc.js +20 -0
- package/esm/voice/call.js +90 -30
- package/esm/voice/softphone.js +94 -23
- package/lib/__tests__/__voice__/call.test.js +43 -1
- package/lib/domain/Phone/WebRTCPhone.js +5 -6
- package/lib/simple/Phone.js +1 -0
- package/lib/state-machine/call-state-machine.js +1 -1
- package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
- package/lib/types/simple/Phone.d.ts.map +1 -1
- package/lib/types/state-machine/utils.d.ts +1 -1
- package/lib/types/state-machine/utils.d.ts.map +1 -1
- package/lib/types/utils/sdp.d.ts +2 -0
- package/lib/types/utils/sdp.d.ts.map +1 -1
- package/lib/types/utils/webrtc.d.ts +1 -0
- package/lib/types/utils/webrtc.d.ts.map +1 -1
- package/lib/types/voice/call.d.ts +19 -11
- package/lib/types/voice/call.d.ts.map +1 -1
- package/lib/types/voice/softphone.d.ts +18 -13
- package/lib/types/voice/softphone.d.ts.map +1 -1
- package/lib/utils/sdp.js +16 -1
- package/lib/utils/webrtc.js +22 -1
- package/lib/voice/call.js +87 -28
- package/lib/voice/softphone.js +95 -23
- package/package.json +1 -1
- package/src/__tests__/__voice__/call.test.ts +47 -2
- package/src/domain/Phone/WebRTCPhone.ts +9 -9
- package/src/simple/Phone.ts +1 -0
- package/src/state-machine/call-state-machine.ts +1 -1
- package/src/state-machine/utils.ts +2 -2
- package/src/utils/sdp.ts +16 -0
- package/src/utils/webrtc.ts +23 -1
- package/src/voice/call.ts +118 -40
- package/src/voice/softphone.ts +116 -30
- 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
|
-
|
|
1787
|
-
const
|
|
1788
|
-
|
|
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
|
|
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
|
|
package/src/simple/Phone.ts
CHANGED
|
@@ -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.
|
|
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
|
+
};
|
package/src/utils/webrtc.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
343
|
+
return this._hasEstablishedState(EstablishedStates.HELD);
|
|
277
344
|
}
|
|
278
345
|
|
|
279
346
|
isEstablished() {
|
|
280
|
-
return
|
|
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.
|
|
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.
|
|
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
|
|
536
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
682
|
+
return this.emit(EVENT_AUDIO_STREAM, stream);
|
|
603
683
|
}
|
|
604
684
|
|
|
605
|
-
return this.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
}
|