@wazo/sdk 0.37.23 → 0.37.27
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/README.md +95 -57
- package/dist/wazo-sdk.js +3 -3
- package/esm/__tests__/api-client.test.js +12 -7
- package/esm/__tests__/web-rtc-client.test.js +47 -20
- package/esm/api/agentd.js +1 -1
- package/esm/api/amid.js +1 -1
- package/esm/api/application.js +1 -1
- package/esm/api/auth.js +1 -1
- package/esm/api/call-logd.js +1 -1
- package/esm/api/calld.js +1 -1
- package/esm/api/chatd.js +1 -1
- package/esm/api/confd.js +11 -6
- package/esm/api/ctid-ng.js +1 -1
- package/esm/api/dird.js +2 -2
- package/esm/api/webhookd.js +1 -1
- package/esm/api-client.js +12 -7
- package/esm/checker/Checker.js +47 -20
- package/esm/checker/checks/aor.js +12 -7
- package/esm/checker/checks/api.js +12 -7
- package/esm/checker/checks/index.js +47 -20
- package/esm/checker/checks/wazo-websocket.js +1 -1
- package/esm/checker/checks/webrtc-transport.js +47 -20
- package/esm/checker/checks/webrtc.js +47 -20
- package/esm/domain/AdHocAPIConference.js +12 -7
- package/esm/domain/Contact.js +1 -1
- package/esm/domain/Features.js +12 -7
- package/esm/domain/Meeting.js +12 -5
- package/esm/domain/Phone/CTIPhone.js +12 -7
- package/esm/domain/Phone/WebRTCPhone.js +34 -6
- package/esm/domain/__tests__/Contact.test.js +1 -1
- package/esm/domain/__tests__/Meeting.test.js +144 -0
- package/esm/index.js +80 -25
- package/esm/lib/WazoSessionDescriptionHandler.js +9 -4
- package/esm/service/CallApi.js +12 -7
- package/esm/service/IssueReporter.js +1 -1
- package/esm/service/__tests__/IssueReporter.test.js +1 -1
- package/esm/service/getApiClient.js +12 -7
- package/esm/simple/Auth.js +80 -25
- package/esm/simple/Configuration.js +80 -25
- package/esm/simple/Directory.js +12 -7
- package/esm/simple/Phone.js +80 -25
- package/esm/simple/Websocket.js +1 -1
- package/esm/simple/index.js +80 -25
- package/esm/simple/room/LocalParticipant.js +80 -25
- package/esm/simple/room/Participant.js +80 -25
- package/esm/simple/room/RemoteParticipant.js +80 -25
- package/esm/simple/room/Room.js +80 -25
- package/esm/simple/room/SipRoom.js +80 -25
- package/esm/simple/room/Stream.js +80 -25
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +80 -25
- package/esm/simple/utils.js +80 -25
- package/esm/types/WebSocketMessage.js +1 -1
- package/esm/utils/__tests__/api-requester.test.js +1 -1
- package/esm/utils/api-requester.js +1 -1
- package/esm/web-rtc-client.js +47 -20
- package/esm/websocket-client.js +1 -1
- package/lib/__tests__/api-client.test.js +12 -7
- package/lib/__tests__/web-rtc-client.test.js +47 -20
- package/lib/api/agentd.js +1 -1
- package/lib/api/amid.js +1 -1
- package/lib/api/application.js +1 -1
- package/lib/api/auth.js +1 -1
- package/lib/api/call-logd.js +1 -1
- package/lib/api/calld.js +1 -1
- package/lib/api/chatd.js +1 -1
- package/lib/api/confd.js +11 -6
- package/lib/api/ctid-ng.js +1 -1
- package/lib/api/dird.js +2 -2
- package/lib/api/webhookd.js +1 -1
- package/lib/api-client.js +12 -7
- package/lib/checker/Checker.js +47 -20
- package/lib/checker/checks/aor.js +12 -7
- package/lib/checker/checks/api.js +12 -7
- package/lib/checker/checks/index.js +47 -20
- package/lib/checker/checks/wazo-websocket.js +1 -1
- package/lib/checker/checks/webrtc-transport.js +47 -20
- package/lib/checker/checks/webrtc.js +47 -20
- package/lib/domain/AdHocAPIConference.js +12 -7
- package/lib/domain/Contact.js +1 -1
- package/lib/domain/Features.js +12 -7
- package/lib/domain/Meeting.js +16 -5
- package/lib/domain/Phone/CTIPhone.js +12 -7
- package/lib/domain/Phone/WebRTCPhone.js +34 -6
- package/lib/domain/__tests__/Contact.test.js +1 -1
- package/lib/domain/__tests__/Meeting.test.js +150 -0
- package/lib/index.js +80 -25
- package/lib/lib/WazoSessionDescriptionHandler.js +9 -4
- package/lib/service/CallApi.js +12 -7
- package/lib/service/IssueReporter.js +1 -1
- package/lib/service/__tests__/IssueReporter.test.js +1 -1
- package/lib/service/getApiClient.js +12 -7
- package/lib/simple/Auth.js +80 -25
- package/lib/simple/Configuration.js +80 -25
- package/lib/simple/Directory.js +12 -7
- package/lib/simple/Phone.js +80 -25
- package/lib/simple/Websocket.js +1 -1
- package/lib/simple/index.js +80 -25
- package/lib/simple/room/LocalParticipant.js +80 -25
- package/lib/simple/room/Participant.js +80 -25
- package/lib/simple/room/RemoteParticipant.js +80 -25
- package/lib/simple/room/Room.js +80 -25
- package/lib/simple/room/SipRoom.js +80 -25
- package/lib/simple/room/Stream.js +80 -25
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +80 -25
- package/lib/simple/utils.js +80 -25
- package/lib/types/WebSocketMessage.js +2 -0
- package/lib/utils/__tests__/api-requester.test.js +1 -1
- package/lib/utils/api-requester.js +1 -1
- package/lib/web-rtc-client.js +47 -20
- package/lib/websocket-client.js +1 -1
- package/package.json +1 -1
- package/src/domain/Contact.js +1 -1
- package/src/domain/Meeting.js +12 -5
- package/src/domain/Phone/WebRTCPhone.js +33 -5
- package/src/domain/__tests__/Meeting.test.js +50 -0
- package/src/lib/WazoSessionDescriptionHandler.js +8 -3
- package/src/utils/api-requester.js +1 -1
- package/src/web-rtc-client.js +27 -10
package/lib/web-rtc-client.js
CHANGED
|
@@ -115,7 +115,7 @@ const logger$2 = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
|
|
|
115
115
|
|
|
116
116
|
// Use a function here to be able to mock it in tests
|
|
117
117
|
const realFetch = () => {
|
|
118
|
-
if (typeof document !== 'undefined') {
|
|
118
|
+
if (typeof document !== 'undefined' && window.fetch) {
|
|
119
119
|
// Browser
|
|
120
120
|
return window.fetch;
|
|
121
121
|
}
|
|
@@ -834,11 +834,16 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
834
834
|
|
|
835
835
|
// $FlowFixMe
|
|
836
836
|
setRemoteSessionDescription(sessionDescription ) {
|
|
837
|
-
|
|
837
|
+
try {
|
|
838
|
+
const result = super.setRemoteSessionDescription(sessionDescription);
|
|
838
839
|
|
|
839
|
-
|
|
840
|
+
this.eventEmitter.emit('setDescription', sessionDescription);
|
|
840
841
|
|
|
841
|
-
|
|
842
|
+
return result;
|
|
843
|
+
} catch (error) {
|
|
844
|
+
this.logger.error('SessionDescriptionHandler.setRemoteSessionDescription error', error);
|
|
845
|
+
throw error;
|
|
846
|
+
}
|
|
842
847
|
}
|
|
843
848
|
|
|
844
849
|
// Overridden to avoid to fix ice-candidates missing in the SDP in react-native and chrome canary.
|
|
@@ -2458,7 +2463,7 @@ class Contact {
|
|
|
2458
2463
|
this[key] = old[key] || this[key];
|
|
2459
2464
|
});
|
|
2460
2465
|
|
|
2461
|
-
if (old.lineState
|
|
2466
|
+
if (old.lineState) {
|
|
2462
2467
|
this.lineState = old.lineState;
|
|
2463
2468
|
}
|
|
2464
2469
|
|
|
@@ -3165,8 +3170,9 @@ class ExternalApp {
|
|
|
3165
3170
|
|
|
3166
3171
|
|
|
3167
3172
|
|
|
3168
|
-
|
|
3173
|
+
|
|
3169
3174
|
|
|
3175
|
+
|
|
3170
3176
|
|
|
3171
3177
|
|
|
3172
3178
|
class Meeting {
|
|
@@ -3177,9 +3183,10 @@ class Meeting {
|
|
|
3177
3183
|
|
|
3178
3184
|
|
|
3179
3185
|
|
|
3180
|
-
|
|
3186
|
+
|
|
3181
3187
|
|
|
3182
3188
|
|
|
3189
|
+
|
|
3183
3190
|
|
|
3184
3191
|
static parse(plain ) {
|
|
3185
3192
|
return new Meeting({
|
|
@@ -3189,8 +3196,9 @@ class Meeting {
|
|
|
3189
3196
|
ownerUuids: plain.owner_uuids,
|
|
3190
3197
|
port: plain.port,
|
|
3191
3198
|
uuid: plain.uuid,
|
|
3192
|
-
|
|
3199
|
+
extension: plain.exten,
|
|
3193
3200
|
persistent: plain.persistent,
|
|
3201
|
+
creationTime: moment__default['default'](plain.creation_time).toDate(),
|
|
3194
3202
|
});
|
|
3195
3203
|
}
|
|
3196
3204
|
|
|
@@ -3212,8 +3220,9 @@ class Meeting {
|
|
|
3212
3220
|
ownerUuids,
|
|
3213
3221
|
port,
|
|
3214
3222
|
uri,
|
|
3215
|
-
|
|
3223
|
+
extension,
|
|
3216
3224
|
persistent,
|
|
3225
|
+
creationTime,
|
|
3217
3226
|
} = {}) {
|
|
3218
3227
|
this.guestSipAuthorization = guestSipAuthorization;
|
|
3219
3228
|
this.uri = uri;
|
|
@@ -3221,8 +3230,9 @@ class Meeting {
|
|
|
3221
3230
|
this.ownerUuids = ownerUuids;
|
|
3222
3231
|
this.port = port;
|
|
3223
3232
|
this.uuid = uuid;
|
|
3224
|
-
this.
|
|
3233
|
+
this.extension = extension;
|
|
3225
3234
|
this.persistent = persistent;
|
|
3235
|
+
this.creationTime = creationTime;
|
|
3226
3236
|
|
|
3227
3237
|
// Useful to compare instead of instanceof with minified code
|
|
3228
3238
|
this.type = 'Meeting';
|
|
@@ -5714,7 +5724,7 @@ class WebRTCClient extends Emitter {
|
|
|
5714
5724
|
}
|
|
5715
5725
|
|
|
5716
5726
|
call(number , enableVideo , audioOnly = false, conference = false) {
|
|
5717
|
-
logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
|
|
5727
|
+
logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly, conference });
|
|
5718
5728
|
const inviterOptions = {
|
|
5719
5729
|
sessionDescriptionHandlerOptionsReInvite: {
|
|
5720
5730
|
conference,
|
|
@@ -6790,6 +6800,7 @@ class WebRTCClient extends Emitter {
|
|
|
6790
6800
|
const screenSharing = constraints && 'screen' in constraints ? constraints.screen : false;
|
|
6791
6801
|
const isDesktop = constraints && 'desktop' in constraints ? constraints.desktop : false;
|
|
6792
6802
|
const withAudio = constraints && 'audio' in constraints ? constraints.audio : true;
|
|
6803
|
+
const mandatoryVideo = constraints && typeof constraints.video === 'object' ? constraints.video.mandatory : {};
|
|
6793
6804
|
|
|
6794
6805
|
logger.info('Retrieving media a configuration', { enableVideo, screenSharing, isDesktop, withAudio, constraints });
|
|
6795
6806
|
|
|
@@ -6797,7 +6808,8 @@ class WebRTCClient extends Emitter {
|
|
|
6797
6808
|
constraints: {
|
|
6798
6809
|
// Exact constraint are not supported with `getDisplayMedia` and we must have a video=false in desktop screenshare
|
|
6799
6810
|
audio: screenSharing ? !isDesktop : (withAudio ? this._getAudioConstraints() : false),
|
|
6800
|
-
video: screenSharing ? (isDesktop
|
|
6811
|
+
video: screenSharing ? (isDesktop
|
|
6812
|
+
? ({ mandatory: { chromeMediaSource: 'desktop', ...(mandatoryVideo || {}) } }) : { cursor: 'always' })
|
|
6801
6813
|
: this._getVideoConstraints(enableVideo),
|
|
6802
6814
|
screen: screenSharing,
|
|
6803
6815
|
desktop: isDesktop,
|
|
@@ -7132,12 +7144,14 @@ class WebRTCClient extends Emitter {
|
|
|
7132
7144
|
|
|
7133
7145
|
session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
|
|
7134
7146
|
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7147
|
+
if (pc) {
|
|
7148
|
+
pc.oniceconnectionstatechange = () => {
|
|
7149
|
+
logger.info('on ice connection state changed', { state: pc.iceConnectionState });
|
|
7150
|
+
if (pc.iceConnectionState === 'disconnected') {
|
|
7151
|
+
this.eventEmitter.emit(ON_DISCONNECTED);
|
|
7152
|
+
}
|
|
7153
|
+
};
|
|
7154
|
+
}
|
|
7141
7155
|
|
|
7142
7156
|
if (withEvent) {
|
|
7143
7157
|
this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
|
|
@@ -7347,13 +7361,17 @@ class WebRTCClient extends Emitter {
|
|
|
7347
7361
|
const nbStats = this.sessionNetworkStats[sessionId].length;
|
|
7348
7362
|
const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
|
|
7349
7363
|
const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
|
|
7364
|
+
const lastAudioContentSent = lastNetworkStats ? lastNetworkStats.audioContentSent : 0;
|
|
7350
7365
|
const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
|
|
7351
7366
|
const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
|
|
7367
|
+
const lastAudioContentReceived = lastNetworkStats ? lastNetworkStats.audioContentReceived : 0;
|
|
7352
7368
|
const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
|
|
7353
7369
|
const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
|
|
7354
7370
|
const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
|
|
7355
|
-
let audioBytesSent = 0;
|
|
7356
|
-
let audioBytesReceived = 0;
|
|
7371
|
+
let audioBytesSent = 0; // content + header
|
|
7372
|
+
let audioBytesReceived = 0; // content + header
|
|
7373
|
+
let audioContentSent = 0; // useful to detect blank call
|
|
7374
|
+
let audioContentReceived = 0;
|
|
7357
7375
|
let videoBytesSent = 0;
|
|
7358
7376
|
let videoBytesReceived = 0;
|
|
7359
7377
|
let transportSent = 0;
|
|
@@ -7363,6 +7381,7 @@ class WebRTCClient extends Emitter {
|
|
|
7363
7381
|
stats.forEach(report => {
|
|
7364
7382
|
if (report.type === 'outbound-rtp' && report.kind === 'audio') {
|
|
7365
7383
|
audioBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
|
|
7384
|
+
audioContentSent += Number(report.bytesSent);
|
|
7366
7385
|
}
|
|
7367
7386
|
if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
|
|
7368
7387
|
audioBytesSent += Number(report.bytesSent);
|
|
@@ -7374,6 +7393,7 @@ class WebRTCClient extends Emitter {
|
|
|
7374
7393
|
packetsLost += Number(report.packetsLost);
|
|
7375
7394
|
networkStats.packetsReceived = Number(report.packetsReceived);
|
|
7376
7395
|
audioBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
7396
|
+
audioContentReceived += Number(report.bytesReceived);
|
|
7377
7397
|
}
|
|
7378
7398
|
if (report.type === 'inbound-rtp' && report.kind === 'video') {
|
|
7379
7399
|
videoBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
@@ -7402,10 +7422,17 @@ class WebRTCClient extends Emitter {
|
|
|
7402
7422
|
});
|
|
7403
7423
|
|
|
7404
7424
|
networkStats.packetsLost = packetsLost;
|
|
7425
|
+
|
|
7405
7426
|
networkStats.totalAudioBytesSent = audioBytesSent;
|
|
7406
7427
|
networkStats.audioBytesSent = audioBytesSent - lastAudioSent;
|
|
7407
7428
|
networkStats.totalAudioBytesReceived = audioBytesReceived - lastAudioReceived;
|
|
7408
7429
|
networkStats.audioBytesReceived = audioBytesReceived;
|
|
7430
|
+
|
|
7431
|
+
networkStats.totalAudioContentSent = audioContentSent;
|
|
7432
|
+
networkStats.audioContentSent = audioContentSent - lastAudioContentSent;
|
|
7433
|
+
networkStats.totalAudioBytesReceived = audioContentReceived - lastAudioContentReceived;
|
|
7434
|
+
networkStats.audioContentReceived = audioContentReceived;
|
|
7435
|
+
|
|
7409
7436
|
networkStats.totalVideoBytesSent = videoBytesSent;
|
|
7410
7437
|
networkStats.videoBytesSent = videoBytesSent - lastVideoSent;
|
|
7411
7438
|
networkStats.totalVideoBytesReceived = videoBytesReceived;
|
package/lib/websocket-client.js
CHANGED
|
@@ -49,7 +49,7 @@ IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
|
|
|
49
49
|
|
|
50
50
|
// Use a function here to be able to mock it in tests
|
|
51
51
|
const realFetch = () => {
|
|
52
|
-
if (typeof document !== 'undefined') {
|
|
52
|
+
if (typeof document !== 'undefined' && window.fetch) {
|
|
53
53
|
// Browser
|
|
54
54
|
return window.fetch;
|
|
55
55
|
}
|
package/package.json
CHANGED
package/src/domain/Contact.js
CHANGED
package/src/domain/Meeting.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
|
+
import moment from 'moment';
|
|
3
|
+
|
|
2
4
|
import newFrom from '../utils/new-from';
|
|
3
5
|
|
|
4
6
|
export type MeetingCreationResponse = {
|
|
@@ -8,8 +10,9 @@ export type MeetingCreationResponse = {
|
|
|
8
10
|
owner_uuids: Array<string>,
|
|
9
11
|
port: string,
|
|
10
12
|
uuid: string,
|
|
11
|
-
|
|
13
|
+
exten: string,
|
|
12
14
|
persistent: boolean,
|
|
15
|
+
creation_time: string,
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
export default class Meeting {
|
|
@@ -20,9 +23,10 @@ export default class Meeting {
|
|
|
20
23
|
uuid: string;
|
|
21
24
|
name: string;
|
|
22
25
|
port: string;
|
|
23
|
-
|
|
26
|
+
extension: string;
|
|
24
27
|
persistent: boolean;
|
|
25
28
|
ownerUuids: Array<string>;
|
|
29
|
+
creationTime: Date;
|
|
26
30
|
|
|
27
31
|
static parse(plain: MeetingCreationResponse): Meeting {
|
|
28
32
|
return new Meeting({
|
|
@@ -32,8 +36,9 @@ export default class Meeting {
|
|
|
32
36
|
ownerUuids: plain.owner_uuids,
|
|
33
37
|
port: plain.port,
|
|
34
38
|
uuid: plain.uuid,
|
|
35
|
-
|
|
39
|
+
extension: plain.exten,
|
|
36
40
|
persistent: plain.persistent,
|
|
41
|
+
creationTime: moment(plain.creation_time).toDate(),
|
|
37
42
|
});
|
|
38
43
|
}
|
|
39
44
|
|
|
@@ -55,8 +60,9 @@ export default class Meeting {
|
|
|
55
60
|
ownerUuids,
|
|
56
61
|
port,
|
|
57
62
|
uri,
|
|
58
|
-
|
|
63
|
+
extension,
|
|
59
64
|
persistent,
|
|
65
|
+
creationTime,
|
|
60
66
|
}: Object = {}) {
|
|
61
67
|
this.guestSipAuthorization = guestSipAuthorization;
|
|
62
68
|
this.uri = uri;
|
|
@@ -64,8 +70,9 @@ export default class Meeting {
|
|
|
64
70
|
this.ownerUuids = ownerUuids;
|
|
65
71
|
this.port = port;
|
|
66
72
|
this.uuid = uuid;
|
|
67
|
-
this.
|
|
73
|
+
this.extension = extension;
|
|
68
74
|
this.persistent = persistent;
|
|
75
|
+
this.creationTime = creationTime;
|
|
69
76
|
|
|
70
77
|
// Useful to compare instead of instanceof with minified code
|
|
71
78
|
this.type = 'Meeting';
|
|
@@ -203,6 +203,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
203
203
|
constraints,
|
|
204
204
|
audioOnly,
|
|
205
205
|
conference,
|
|
206
|
+
iceRestart,
|
|
206
207
|
});
|
|
207
208
|
|
|
208
209
|
if (!sipSession) {
|
|
@@ -306,6 +307,11 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
306
307
|
|
|
307
308
|
this.client.downgradeToAudio(sipSession);
|
|
308
309
|
|
|
310
|
+
if (callSession) {
|
|
311
|
+
callSession.cameraEnabled = false;
|
|
312
|
+
this._updateCallSession(callSession);
|
|
313
|
+
}
|
|
314
|
+
|
|
309
315
|
if (withMessage) {
|
|
310
316
|
this._sendReinviteMessage(callSession, false);
|
|
311
317
|
}
|
|
@@ -333,6 +339,11 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
333
339
|
|
|
334
340
|
const newStream = await this.client.upgradeToVideo(sipSession, constraints, isConference);
|
|
335
341
|
|
|
342
|
+
if (callSession) {
|
|
343
|
+
callSession.cameraEnabled = true;
|
|
344
|
+
this._updateCallSession(callSession);
|
|
345
|
+
}
|
|
346
|
+
|
|
336
347
|
// If no stream is returned, it means we have to reinvite
|
|
337
348
|
if (!newStream) {
|
|
338
349
|
return true;
|
|
@@ -604,7 +615,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
604
615
|
}
|
|
605
616
|
|
|
606
617
|
_onCallAccepted(sipSession: Session, cameraEnabled: boolean): CallSession {
|
|
607
|
-
logger.info('WebRTC phone -
|
|
618
|
+
logger.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
|
|
608
619
|
|
|
609
620
|
const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
|
|
610
621
|
this.currentSipSession = sipSession;
|
|
@@ -673,6 +684,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
673
684
|
_onCallTerminated(sipSession: Session) {
|
|
674
685
|
logger.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
|
|
675
686
|
|
|
687
|
+
const sipSessionId = this.getSipSessionId(sipSession);
|
|
676
688
|
const callSession = this._createCallSession(sipSession);
|
|
677
689
|
const isCurrentSession = this.isCurrentCallSipSession(callSession);
|
|
678
690
|
const isCurrentIncomingCall = callSession.is(this.getIncomingCallSession());
|
|
@@ -690,7 +702,6 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
690
702
|
}, 5);
|
|
691
703
|
}
|
|
692
704
|
|
|
693
|
-
const sipSessionId = this.getSipSessionId(sipSession);
|
|
694
705
|
if (sipSessionId) {
|
|
695
706
|
this.removeIncomingSessions(sipSessionId);
|
|
696
707
|
}
|
|
@@ -1116,7 +1127,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1116
1127
|
// @TODO: line is not used here
|
|
1117
1128
|
async makeCall(number: string, line: any, cameraEnabled?: boolean,
|
|
1118
1129
|
audioOnly: boolean = false, conference: boolean = false): Promise<?CallSession> {
|
|
1119
|
-
logger.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
|
|
1130
|
+
logger.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled, audioOnly, conference });
|
|
1120
1131
|
if (!number) {
|
|
1121
1132
|
return Promise.resolve(null);
|
|
1122
1133
|
}
|
|
@@ -1335,8 +1346,12 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1335
1346
|
}
|
|
1336
1347
|
|
|
1337
1348
|
const sessionId = this.incomingSessions[0];
|
|
1349
|
+
const sipSession = this.client.getSipSession(sessionId);
|
|
1350
|
+
if (!sipSession) {
|
|
1351
|
+
return null;
|
|
1352
|
+
}
|
|
1338
1353
|
|
|
1339
|
-
return this._createCallSession(
|
|
1354
|
+
return this._createCallSession(sipSession);
|
|
1340
1355
|
}
|
|
1341
1356
|
|
|
1342
1357
|
sendMessage(sipSession: Session = null, body: string, contentType: string = 'text/plain') {
|
|
@@ -1477,9 +1492,13 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1477
1492
|
if (this.shouldSendReinvite && this.currentSipSession
|
|
1478
1493
|
&& this.currentSipSession.state === SessionState.Established) {
|
|
1479
1494
|
this.shouldSendReinvite = false;
|
|
1495
|
+
const pc = this.currentSipSession.sessionDescriptionHandler.peerConnection;
|
|
1496
|
+
const isConference = pc ? pc.sfu : false;
|
|
1497
|
+
const hasVideo = this.currentCallSession && this.currentCallSession.cameraEnabled;
|
|
1498
|
+
|
|
1480
1499
|
try {
|
|
1481
1500
|
// Send reinvite with iceRestart
|
|
1482
|
-
this.sendReinvite(this.currentCallSession, null,
|
|
1501
|
+
this.sendReinvite(this.currentCallSession, null, isConference, !hasVideo, true);
|
|
1483
1502
|
} catch (e) {
|
|
1484
1503
|
logger.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
|
|
1485
1504
|
}
|
|
@@ -1563,6 +1582,15 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1563
1582
|
return this.client.getSipSessionId(sipSession);
|
|
1564
1583
|
}
|
|
1565
1584
|
|
|
1585
|
+
_updateCallSession(callSession: CallSession) {
|
|
1586
|
+
const sipSession = this.findSipSession(callSession);
|
|
1587
|
+
const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
|
|
1588
|
+
|
|
1589
|
+
if (sipSessionId) {
|
|
1590
|
+
this.callSessions[sipSessionId] = callSession;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1566
1594
|
_onMessage(message: Message) {
|
|
1567
1595
|
if (!message || message.method !== 'MESSAGE') {
|
|
1568
1596
|
return;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
/* global btoa */
|
|
3
|
+
|
|
4
|
+
import Meeting from '../Meeting';
|
|
5
|
+
|
|
6
|
+
describe('Meeting domain', () => {
|
|
7
|
+
it('can return username and secret from an base64 encrypted string', () => {
|
|
8
|
+
const USERNAME = 'username';
|
|
9
|
+
const SECRET = 'secret';
|
|
10
|
+
|
|
11
|
+
const args = {
|
|
12
|
+
guest_sip_authorization: btoa(`${USERNAME}:${SECRET}`),
|
|
13
|
+
creation_time: '',
|
|
14
|
+
ingress_http_uri: '',
|
|
15
|
+
name: '',
|
|
16
|
+
owner_uuids: [],
|
|
17
|
+
port: '',
|
|
18
|
+
uuid: '',
|
|
19
|
+
exten: '',
|
|
20
|
+
persistent: false,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const meeting = Meeting.parse(args);
|
|
24
|
+
|
|
25
|
+
const { username, secret } = meeting.getGuestSipCredentials();
|
|
26
|
+
|
|
27
|
+
expect(username).toEqual(USERNAME);
|
|
28
|
+
expect(secret).toEqual(SECRET);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should return a date from a string', () => {
|
|
32
|
+
const args = {
|
|
33
|
+
creation_time: '2021-12-21T15:56:42.880Z',
|
|
34
|
+
guest_sip_authorization: '',
|
|
35
|
+
ingress_http_uri: '',
|
|
36
|
+
name: '',
|
|
37
|
+
owner_uuids: [],
|
|
38
|
+
port: '',
|
|
39
|
+
uuid: '',
|
|
40
|
+
exten: '',
|
|
41
|
+
persistent: false,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const { creationTime } = Meeting.parse(args);
|
|
45
|
+
|
|
46
|
+
expect(creationTime.getDate()).toEqual(21);
|
|
47
|
+
expect(creationTime.getFullYear()).toEqual(2021);
|
|
48
|
+
expect(creationTime.getMonth()).toEqual(11);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -62,11 +62,16 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
|
|
|
62
62
|
|
|
63
63
|
// $FlowFixMe
|
|
64
64
|
setRemoteSessionDescription(sessionDescription: RTCSessionDescriptionInit): Promise<void> {
|
|
65
|
-
|
|
65
|
+
try {
|
|
66
|
+
const result = super.setRemoteSessionDescription(sessionDescription);
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
this.eventEmitter.emit('setDescription', sessionDescription);
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
return result;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
this.logger.error('SessionDescriptionHandler.setRemoteSessionDescription error', error);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
// Overridden to avoid to fix ice-candidates missing in the SDP in react-native and chrome canary.
|
|
@@ -25,7 +25,7 @@ const logger = IssueReporter ? IssueReporter.loggerFor('api') : console;
|
|
|
25
25
|
|
|
26
26
|
// Use a function here to be able to mock it in tests
|
|
27
27
|
export const realFetch = () => {
|
|
28
|
-
if (typeof document !== 'undefined') {
|
|
28
|
+
if (typeof document !== 'undefined' && window.fetch) {
|
|
29
29
|
// Browser
|
|
30
30
|
return window.fetch;
|
|
31
31
|
}
|
package/src/web-rtc-client.js
CHANGED
|
@@ -453,7 +453,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
call(number: string, enableVideo?: boolean, audioOnly: boolean = false, conference: boolean = false): Session {
|
|
456
|
-
logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
|
|
456
|
+
logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly, conference });
|
|
457
457
|
const inviterOptions: Object = {
|
|
458
458
|
sessionDescriptionHandlerOptionsReInvite: {
|
|
459
459
|
conference,
|
|
@@ -1529,6 +1529,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
1529
1529
|
const screenSharing = constraints && 'screen' in constraints ? constraints.screen : false;
|
|
1530
1530
|
const isDesktop = constraints && 'desktop' in constraints ? constraints.desktop : false;
|
|
1531
1531
|
const withAudio = constraints && 'audio' in constraints ? constraints.audio : true;
|
|
1532
|
+
const mandatoryVideo = constraints && typeof constraints.video === 'object' ? constraints.video.mandatory : {};
|
|
1532
1533
|
|
|
1533
1534
|
logger.info('Retrieving media a configuration', { enableVideo, screenSharing, isDesktop, withAudio, constraints });
|
|
1534
1535
|
|
|
@@ -1536,7 +1537,8 @@ export default class WebRTCClient extends Emitter {
|
|
|
1536
1537
|
constraints: {
|
|
1537
1538
|
// Exact constraint are not supported with `getDisplayMedia` and we must have a video=false in desktop screenshare
|
|
1538
1539
|
audio: screenSharing ? !isDesktop : (withAudio ? this._getAudioConstraints() : false),
|
|
1539
|
-
video: screenSharing ? (isDesktop
|
|
1540
|
+
video: screenSharing ? (isDesktop
|
|
1541
|
+
? ({ mandatory: { chromeMediaSource: 'desktop', ...(mandatoryVideo || {}) } }) : { cursor: 'always' })
|
|
1540
1542
|
: this._getVideoConstraints(enableVideo),
|
|
1541
1543
|
screen: screenSharing,
|
|
1542
1544
|
desktop: isDesktop,
|
|
@@ -1871,12 +1873,14 @@ export default class WebRTCClient extends Emitter {
|
|
|
1871
1873
|
|
|
1872
1874
|
session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
|
|
1873
1875
|
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1876
|
+
if (pc) {
|
|
1877
|
+
pc.oniceconnectionstatechange = () => {
|
|
1878
|
+
logger.info('on ice connection state changed', { state: pc.iceConnectionState });
|
|
1879
|
+
if (pc.iceConnectionState === 'disconnected') {
|
|
1880
|
+
this.eventEmitter.emit(ON_DISCONNECTED);
|
|
1881
|
+
}
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1880
1884
|
|
|
1881
1885
|
if (withEvent) {
|
|
1882
1886
|
this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
|
|
@@ -2086,13 +2090,17 @@ export default class WebRTCClient extends Emitter {
|
|
|
2086
2090
|
const nbStats = this.sessionNetworkStats[sessionId].length;
|
|
2087
2091
|
const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
|
|
2088
2092
|
const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
|
|
2093
|
+
const lastAudioContentSent = lastNetworkStats ? lastNetworkStats.audioContentSent : 0;
|
|
2089
2094
|
const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
|
|
2090
2095
|
const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
|
|
2096
|
+
const lastAudioContentReceived = lastNetworkStats ? lastNetworkStats.audioContentReceived : 0;
|
|
2091
2097
|
const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
|
|
2092
2098
|
const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
|
|
2093
2099
|
const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
|
|
2094
|
-
let audioBytesSent = 0;
|
|
2095
|
-
let audioBytesReceived = 0;
|
|
2100
|
+
let audioBytesSent = 0; // content + header
|
|
2101
|
+
let audioBytesReceived = 0; // content + header
|
|
2102
|
+
let audioContentSent = 0; // useful to detect blank call
|
|
2103
|
+
let audioContentReceived = 0;
|
|
2096
2104
|
let videoBytesSent = 0;
|
|
2097
2105
|
let videoBytesReceived = 0;
|
|
2098
2106
|
let transportSent = 0;
|
|
@@ -2102,6 +2110,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
2102
2110
|
stats.forEach(report => {
|
|
2103
2111
|
if (report.type === 'outbound-rtp' && report.kind === 'audio') {
|
|
2104
2112
|
audioBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
|
|
2113
|
+
audioContentSent += Number(report.bytesSent);
|
|
2105
2114
|
}
|
|
2106
2115
|
if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
|
|
2107
2116
|
audioBytesSent += Number(report.bytesSent);
|
|
@@ -2113,6 +2122,7 @@ export default class WebRTCClient extends Emitter {
|
|
|
2113
2122
|
packetsLost += Number(report.packetsLost);
|
|
2114
2123
|
networkStats.packetsReceived = Number(report.packetsReceived);
|
|
2115
2124
|
audioBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
2125
|
+
audioContentReceived += Number(report.bytesReceived);
|
|
2116
2126
|
}
|
|
2117
2127
|
if (report.type === 'inbound-rtp' && report.kind === 'video') {
|
|
2118
2128
|
videoBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
@@ -2141,10 +2151,17 @@ export default class WebRTCClient extends Emitter {
|
|
|
2141
2151
|
});
|
|
2142
2152
|
|
|
2143
2153
|
networkStats.packetsLost = packetsLost;
|
|
2154
|
+
|
|
2144
2155
|
networkStats.totalAudioBytesSent = audioBytesSent;
|
|
2145
2156
|
networkStats.audioBytesSent = audioBytesSent - lastAudioSent;
|
|
2146
2157
|
networkStats.totalAudioBytesReceived = audioBytesReceived - lastAudioReceived;
|
|
2147
2158
|
networkStats.audioBytesReceived = audioBytesReceived;
|
|
2159
|
+
|
|
2160
|
+
networkStats.totalAudioContentSent = audioContentSent;
|
|
2161
|
+
networkStats.audioContentSent = audioContentSent - lastAudioContentSent;
|
|
2162
|
+
networkStats.totalAudioBytesReceived = audioContentReceived - lastAudioContentReceived;
|
|
2163
|
+
networkStats.audioContentReceived = audioContentReceived;
|
|
2164
|
+
|
|
2148
2165
|
networkStats.totalVideoBytesSent = videoBytesSent;
|
|
2149
2166
|
networkStats.videoBytesSent = videoBytesSent - lastVideoSent;
|
|
2150
2167
|
networkStats.totalVideoBytesReceived = videoBytesReceived;
|