@wazo/sdk 1.0.0-alpha.17 → 1.0.0-alpha.19
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 +2 -2
- package/esm/__tests__/__voice__/call.test.js +40 -4
- package/esm/state-machine/call-state-machine.js +33 -18
- package/esm/types/state-machine/call-state-machine.d.ts +12 -1
- package/esm/types/state-machine/call-state-machine.d.ts.map +1 -1
- package/esm/types/utils/webrtc.d.ts.map +1 -1
- package/esm/types/voice/call.d.ts.map +1 -1
- package/esm/utils/webrtc.js +3 -0
- package/esm/voice/call.js +24 -6
- package/lib/__tests__/__voice__/call.test.js +39 -3
- package/lib/state-machine/call-state-machine.js +34 -19
- package/lib/types/state-machine/call-state-machine.d.ts +12 -1
- package/lib/types/state-machine/call-state-machine.d.ts.map +1 -1
- package/lib/types/utils/webrtc.d.ts.map +1 -1
- package/lib/types/voice/call.d.ts.map +1 -1
- package/lib/utils/webrtc.js +3 -0
- package/lib/voice/call.js +24 -6
- package/package.json +1 -1
- package/src/__tests__/__voice__/call.test.ts +46 -4
- package/src/state-machine/call-state-machine.ts +37 -18
- package/src/utils/webrtc.ts +3 -0
- package/src/voice/call.ts +28 -8
|
@@ -3,7 +3,7 @@ import { Inviter, UserAgent, type URI } from 'sip.js';
|
|
|
3
3
|
|
|
4
4
|
import softphone from '../../voice/softphone';
|
|
5
5
|
import Call from '../../voice/call';
|
|
6
|
-
import { Actions, EstablishedStates, States } from '../../state-machine/call-state-machine';
|
|
6
|
+
import { Actions, EstablishedStates, EstablishedSubStates, States } from '../../state-machine/call-state-machine';
|
|
7
7
|
import { Actions as SoftphoneActions } from '../../state-machine/softphone-state-machine';
|
|
8
8
|
import ApiCall from '../../domain/Call';
|
|
9
9
|
|
|
@@ -32,6 +32,9 @@ jest.mock('../..', () => ({
|
|
|
32
32
|
|
|
33
33
|
jest.mock('../../web-rtc-client', () => jest.fn().mockImplementation(() => ({
|
|
34
34
|
answer: jest.fn(() => Promise.resolve()),
|
|
35
|
+
mute: jest.fn(() => Promise.resolve()),
|
|
36
|
+
hold: jest.fn(() => Promise.resolve()),
|
|
37
|
+
unhold: jest.fn(() => Promise.resolve()),
|
|
35
38
|
hangup: jest.fn(() => Promise.resolve()),
|
|
36
39
|
register: jest.fn(() => Promise.resolve()),
|
|
37
40
|
onCallEnded: jest.fn(() => Promise.resolve()),
|
|
@@ -76,9 +79,16 @@ describe('Call', () => {
|
|
|
76
79
|
expect(call.id).toBe(apiCall.sipCallId);
|
|
77
80
|
expect(call.apiId).toBe(apiCall.id);
|
|
78
81
|
expect(call.number).toBe(apiCall.calleeNumber);
|
|
79
|
-
expect(call.answerTime).toStrictEqual(
|
|
82
|
+
expect(call.answerTime).toStrictEqual(undefined);
|
|
83
|
+
expect(call.creationTime).toStrictEqual(apiCall.startingTime);
|
|
80
84
|
expect(call.isMuted()).toBeTruthy();
|
|
81
|
-
expect(call.state).toStrictEqual({
|
|
85
|
+
expect(call.state).toStrictEqual({
|
|
86
|
+
[States.ESTABLISHED]: {
|
|
87
|
+
[EstablishedStates.ONGOING]: {},
|
|
88
|
+
[EstablishedSubStates.MUTE]: EstablishedStates.MUTED,
|
|
89
|
+
[EstablishedSubStates.HOLD]: EstablishedStates.UN_HELD,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
82
92
|
expect(call.isEstablished()).toBeTruthy();
|
|
83
93
|
});
|
|
84
94
|
});
|
|
@@ -141,11 +151,43 @@ describe('Call', () => {
|
|
|
141
151
|
call._sendAction(Actions.MAKE_CALL);
|
|
142
152
|
|
|
143
153
|
call.on('remotelyAccepted', () => {
|
|
144
|
-
expect(call.state).toStrictEqual({
|
|
154
|
+
expect(call.state).toStrictEqual({
|
|
155
|
+
[States.ESTABLISHED]: {
|
|
156
|
+
[EstablishedStates.ONGOING]: {},
|
|
157
|
+
[EstablishedSubStates.MUTE]: EstablishedStates.UN_MUTED,
|
|
158
|
+
[EstablishedSubStates.HOLD]: EstablishedStates.UN_HELD,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
145
161
|
done();
|
|
146
162
|
});
|
|
147
163
|
|
|
148
164
|
call.onAccepted();
|
|
149
165
|
});
|
|
150
166
|
});
|
|
167
|
+
|
|
168
|
+
describe('Multiple sub state', () => {
|
|
169
|
+
it('Should mute and hold a call', () => {
|
|
170
|
+
const call = new Call(sipCall, softphone);
|
|
171
|
+
// @ts-ignore: private method
|
|
172
|
+
call._sendAction(Actions.MAKE_CALL);
|
|
173
|
+
|
|
174
|
+
expect(call.isMuted()).toBeFalsy();
|
|
175
|
+
expect(call.isHeld()).toBeFalsy();
|
|
176
|
+
|
|
177
|
+
// @ts-ignore: private method
|
|
178
|
+
call._sendAction(Actions.REMOTLY_ACCEPTED);
|
|
179
|
+
|
|
180
|
+
call.mute();
|
|
181
|
+
expect(call.isMuted()).toBeTruthy();
|
|
182
|
+
expect(call.isHeld()).toBeFalsy();
|
|
183
|
+
|
|
184
|
+
call.hold();
|
|
185
|
+
expect(call.isMuted()).toBeTruthy();
|
|
186
|
+
expect(call.isHeld()).toBeTruthy();
|
|
187
|
+
|
|
188
|
+
call.resume();
|
|
189
|
+
expect(call.isMuted()).toBeTruthy();
|
|
190
|
+
expect(call.isHeld()).toBeFalsy();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
151
193
|
});
|
|
@@ -15,11 +15,19 @@ export const EstablishedStates = {
|
|
|
15
15
|
ONGOING: 'ongoing',
|
|
16
16
|
HELD: 'held',
|
|
17
17
|
MUTED: 'muted',
|
|
18
|
+
UN_MUTED: 'unMuted',
|
|
19
|
+
UN_HELD: 'unHeld',
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
export const EstablishedSubStates = {
|
|
23
|
+
MUTE: 'muteState',
|
|
24
|
+
HOLD: 'holdState',
|
|
18
25
|
} as const;
|
|
19
26
|
|
|
20
27
|
export type StateTypes = typeof States[keyof typeof States];
|
|
21
28
|
|
|
22
29
|
export type EstablishedStateTypes = typeof EstablishedStates[keyof typeof EstablishedStates];
|
|
30
|
+
export type EstablishedSubStateTypes = typeof EstablishedSubStates[keyof typeof EstablishedSubStates];
|
|
23
31
|
|
|
24
32
|
export const Actions = {
|
|
25
33
|
INCOMING_CALL: 'incomingCall',
|
|
@@ -88,35 +96,46 @@ const callMachine = setup({
|
|
|
88
96
|
},
|
|
89
97
|
[States.ESTABLISHED]: {
|
|
90
98
|
initial: EstablishedStates.ONGOING,
|
|
99
|
+
type: 'parallel',
|
|
91
100
|
on: {
|
|
92
101
|
[Actions.HANGUP]: {
|
|
93
102
|
guard: 'isRegistered',
|
|
94
103
|
target: States.TERMINATED,
|
|
95
104
|
},
|
|
96
|
-
[EstablishedActions.HOLD]: {
|
|
97
|
-
guard: 'isRegistered',
|
|
98
|
-
target: `.${EstablishedStates.HELD}`,
|
|
99
|
-
},
|
|
100
|
-
[EstablishedActions.MUTE]: {
|
|
101
|
-
guard: 'isRegistered',
|
|
102
|
-
target: `.${EstablishedStates.MUTED}`,
|
|
103
|
-
},
|
|
104
105
|
},
|
|
105
106
|
states: {
|
|
106
107
|
[EstablishedStates.ONGOING]: { },
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
|
|
109
|
+
// Mute / Unmute
|
|
110
|
+
[EstablishedSubStates.MUTE]: {
|
|
111
|
+
initial: EstablishedStates.UN_MUTED,
|
|
112
|
+
states: {
|
|
113
|
+
[EstablishedStates.MUTED]: {
|
|
114
|
+
on: {
|
|
115
|
+
unMute: EstablishedStates.UN_MUTED,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
[EstablishedStates.UN_MUTED]: {
|
|
119
|
+
on: {
|
|
120
|
+
mute: EstablishedStates.MUTED,
|
|
121
|
+
},
|
|
112
122
|
},
|
|
113
123
|
},
|
|
114
124
|
},
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
|
|
126
|
+
// Hold / Resume
|
|
127
|
+
[EstablishedSubStates.HOLD]: {
|
|
128
|
+
initial: EstablishedStates.UN_HELD,
|
|
129
|
+
states: {
|
|
130
|
+
[EstablishedStates.HELD]: {
|
|
131
|
+
on: {
|
|
132
|
+
[EstablishedActions.RESUME]: EstablishedStates.UN_HELD,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
[EstablishedStates.UN_HELD]: {
|
|
136
|
+
on: {
|
|
137
|
+
[EstablishedActions.HOLD]: EstablishedStates.HELD,
|
|
138
|
+
},
|
|
120
139
|
},
|
|
121
140
|
},
|
|
122
141
|
},
|
package/src/utils/webrtc.ts
CHANGED
|
@@ -253,6 +253,9 @@ export const toggleVideo = (sipCall: SipCall, muteCamera: boolean): void => {
|
|
|
253
253
|
export const isVideoMuted = (sipCall: SipCall): boolean => {
|
|
254
254
|
const sdh = sipCall.sessionDescriptionHandler as SessionDescriptionHandler;
|
|
255
255
|
const pc = sdh?.peerConnection as PeerConnection;
|
|
256
|
+
if (!pc) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
256
259
|
|
|
257
260
|
if (pc?.getSenders) {
|
|
258
261
|
for (const sender of pc.getSenders()) {
|
package/src/voice/call.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { SessionDescriptionHandler } from 'sip.js/lib/platform/web';
|
|
|
9
9
|
import { SessionDescriptionHandlerOptions } from 'sip.js/lib/api';
|
|
10
10
|
import type { IncomingRequestMessage } from 'sip.js/lib/core/messages/incoming-request-message';
|
|
11
11
|
|
|
12
|
-
import callStateMachine, { type ActionTypes, Actions, type EstablishedActionTypes, EstablishedActions, States, type StateTypes, EstablishedStates, type EstablishedStateTypes, 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, EstablishedSubStateTypes } from '../state-machine/call-state-machine';
|
|
13
13
|
import { SipCall, PeerConnection } from '../domain/types';
|
|
14
14
|
import ApiCall from '../domain/Call';
|
|
15
15
|
import newFrom from '../utils/new-from';
|
|
@@ -129,11 +129,23 @@ class Call extends EventEmitter {
|
|
|
129
129
|
const snapshot = call.callActor.getSnapshot();
|
|
130
130
|
|
|
131
131
|
if (apiCall.isUp()) {
|
|
132
|
-
snapshot.value = {
|
|
132
|
+
snapshot.value = {
|
|
133
|
+
[States.ESTABLISHED]: {
|
|
134
|
+
[EstablishedStates.ONGOING]: {},
|
|
135
|
+
muteState: EstablishedStates.UN_MUTED,
|
|
136
|
+
holdState: EstablishedStates.UN_HELD,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
133
139
|
}
|
|
134
140
|
|
|
135
141
|
if (apiCall.muted) {
|
|
136
|
-
snapshot.value = {
|
|
142
|
+
snapshot.value = {
|
|
143
|
+
[States.ESTABLISHED]: {
|
|
144
|
+
[EstablishedStates.ONGOING]: {},
|
|
145
|
+
muteState: EstablishedStates.MUTED,
|
|
146
|
+
holdState: EstablishedStates.UN_HELD,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
if (apiCall.isRinging()) {
|
|
@@ -345,7 +357,7 @@ class Call extends EventEmitter {
|
|
|
345
357
|
}
|
|
346
358
|
|
|
347
359
|
isMuted() {
|
|
348
|
-
return this._hasEstablishedState(EstablishedStates.MUTED);
|
|
360
|
+
return this._hasEstablishedState('muteState', EstablishedStates.MUTED);
|
|
349
361
|
}
|
|
350
362
|
|
|
351
363
|
isCameraMuted() {
|
|
@@ -353,7 +365,7 @@ class Call extends EventEmitter {
|
|
|
353
365
|
}
|
|
354
366
|
|
|
355
367
|
isHeld() {
|
|
356
|
-
return this._hasEstablishedState(EstablishedStates.HELD);
|
|
368
|
+
return this._hasEstablishedState('holdState', EstablishedStates.HELD);
|
|
357
369
|
}
|
|
358
370
|
|
|
359
371
|
isEstablishing() {
|
|
@@ -662,9 +674,17 @@ class Call extends EventEmitter {
|
|
|
662
674
|
return getState(this.callActor) as StateTypes | Record<StateTypes, EstablishedStateTypes>;
|
|
663
675
|
}
|
|
664
676
|
|
|
665
|
-
private _hasEstablishedState(establishedState: EstablishedStateTypes) {
|
|
666
|
-
const state = this.state as Record<StateTypes, EstablishedStateTypes
|
|
667
|
-
|
|
677
|
+
private _hasEstablishedState(subState: EstablishedSubStateTypes, establishedState: EstablishedStateTypes) {
|
|
678
|
+
const state = this.state as Record<StateTypes, EstablishedStateTypes | Record<EstablishedSubStateTypes, EstablishedStateTypes>>;
|
|
679
|
+
if (typeof state !== 'object') {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (!(States.ESTABLISHED in state)) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return (state[States.ESTABLISHED] as Record<EstablishedSubStateTypes, EstablishedStateTypes>)[subState] === establishedState;
|
|
668
688
|
}
|
|
669
689
|
|
|
670
690
|
private _bindEvents() {
|