@wazo/sdk 0.37.21 → 0.37.25
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 +5 -5
- package/esm/__tests__/api-client.test.js +36 -5
- package/esm/__tests__/web-rtc-client.test.js +77 -66
- package/esm/api/call-logd.js +7 -0
- package/esm/api/calld.js +10 -0
- package/esm/api/chatd.js +7 -0
- package/esm/api/confd.js +13 -5
- package/esm/api/ctid-ng.js +10 -0
- package/esm/api/dird.js +3 -0
- package/esm/api-client.js +36 -5
- package/esm/checker/Checker.js +77 -66
- package/esm/checker/checks/aor.js +36 -5
- package/esm/checker/checks/api.js +36 -5
- package/esm/checker/checks/index.js +77 -66
- package/esm/checker/checks/webrtc-transport.js +77 -66
- package/esm/checker/checks/webrtc.js +77 -66
- package/esm/domain/AdHocAPIConference.js +36 -5
- package/esm/domain/Call.js +3 -0
- package/esm/domain/CallLog.js +7 -0
- package/esm/domain/ChatMessage.js +4 -0
- package/esm/domain/ChatRoom.js +3 -0
- package/esm/domain/Contact.js +3 -0
- package/esm/domain/Features.js +36 -5
- package/esm/domain/Meeting.js +15 -5
- package/esm/domain/Phone/CTIPhone.js +40 -5
- package/esm/domain/Phone/WebRTCPhone.js +45 -16
- package/esm/domain/Recording.js +3 -0
- package/esm/domain/Voicemail.js +3 -0
- package/esm/domain/__tests__/Call.test.js +3 -0
- package/esm/domain/__tests__/CallLog.test.js +7 -0
- package/esm/domain/__tests__/Contact.test.js +3 -0
- package/esm/domain/__tests__/Meeting.test.js +144 -0
- package/esm/domain/__tests__/Voicemail.test.js +3 -0
- package/esm/index.js +125 -81
- package/esm/lib/WazoSessionDescriptionHandler.js +0 -38
- package/esm/service/CallApi.js +36 -5
- package/esm/service/getApiClient.js +36 -5
- package/esm/simple/Auth.js +125 -81
- package/esm/simple/Configuration.js +125 -81
- package/esm/simple/Directory.js +36 -5
- package/esm/simple/Phone.js +125 -81
- package/esm/simple/index.js +125 -81
- package/esm/simple/room/LocalParticipant.js +125 -81
- package/esm/simple/room/Participant.js +125 -81
- package/esm/simple/room/RemoteParticipant.js +125 -81
- package/esm/simple/room/Room.js +125 -81
- package/esm/simple/room/SipRoom.js +125 -81
- package/esm/simple/room/Stream.js +125 -81
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +125 -81
- package/esm/simple/utils.js +125 -81
- package/esm/types/WebSocketMessage.js +1 -1
- package/esm/web-rtc-client.js +77 -66
- package/lib/__tests__/api-client.test.js +36 -5
- package/lib/__tests__/web-rtc-client.test.js +77 -66
- package/lib/api/call-logd.js +7 -0
- package/lib/api/calld.js +10 -0
- package/lib/api/chatd.js +7 -0
- package/lib/api/confd.js +13 -5
- package/lib/api/ctid-ng.js +10 -0
- package/lib/api/dird.js +3 -0
- package/lib/api-client.js +36 -5
- package/lib/checker/Checker.js +77 -66
- package/lib/checker/checks/aor.js +36 -5
- package/lib/checker/checks/api.js +36 -5
- package/lib/checker/checks/index.js +77 -66
- package/lib/checker/checks/webrtc-transport.js +77 -66
- package/lib/checker/checks/webrtc.js +77 -66
- package/lib/domain/AdHocAPIConference.js +36 -5
- package/lib/domain/Call.js +3 -0
- package/lib/domain/CallLog.js +7 -0
- package/lib/domain/ChatMessage.js +4 -0
- package/lib/domain/ChatRoom.js +3 -0
- package/lib/domain/Contact.js +3 -0
- package/lib/domain/Features.js +36 -5
- package/lib/domain/Meeting.js +19 -5
- package/lib/domain/Phone/CTIPhone.js +40 -5
- package/lib/domain/Phone/WebRTCPhone.js +45 -16
- package/lib/domain/Recording.js +3 -0
- package/lib/domain/Voicemail.js +3 -0
- package/lib/domain/__tests__/Call.test.js +3 -0
- package/lib/domain/__tests__/CallLog.test.js +7 -0
- package/lib/domain/__tests__/Contact.test.js +3 -0
- package/lib/domain/__tests__/Meeting.test.js +150 -0
- package/lib/domain/__tests__/Voicemail.test.js +3 -0
- package/lib/index.js +125 -81
- package/lib/lib/WazoSessionDescriptionHandler.js +0 -38
- package/lib/service/CallApi.js +36 -5
- package/lib/service/getApiClient.js +36 -5
- package/lib/simple/Auth.js +125 -81
- package/lib/simple/Configuration.js +125 -81
- package/lib/simple/Directory.js +36 -5
- package/lib/simple/Phone.js +125 -81
- package/lib/simple/index.js +125 -81
- package/lib/simple/room/LocalParticipant.js +125 -81
- package/lib/simple/room/Participant.js +125 -81
- package/lib/simple/room/RemoteParticipant.js +125 -81
- package/lib/simple/room/Room.js +125 -81
- package/lib/simple/room/SipRoom.js +125 -81
- package/lib/simple/room/Stream.js +125 -81
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +125 -81
- package/lib/simple/utils.js +125 -81
- package/lib/types/WebSocketMessage.js +2 -0
- package/lib/web-rtc-client.js +77 -66
- package/package.json +1 -1
- package/src/domain/Call.js +3 -0
- package/src/domain/CallLog.js +4 -0
- package/src/domain/ChatMessage.js +4 -0
- package/src/domain/ChatRoom.js +3 -0
- package/src/domain/Contact.js +3 -0
- package/src/domain/Meeting.js +15 -5
- package/src/domain/Phone/CTIPhone.js +4 -0
- package/src/domain/Phone/Phone.js +2 -0
- package/src/domain/Phone/WebRTCPhone.js +45 -16
- package/src/domain/Recording.js +3 -0
- package/src/domain/Voicemail.js +3 -0
- package/src/domain/__tests__/Meeting.test.js +50 -0
- package/src/lib/WazoSessionDescriptionHandler.js +1 -35
- package/src/web-rtc-client.js +41 -23
package/lib/web-rtc-client.js
CHANGED
|
@@ -735,10 +735,6 @@ const getSrflxOrRelay = (candidates ) =>
|
|
|
735
735
|
candidates
|
|
736
736
|
.filter(candidate => candidate && (candidate.type === 'srflx' || candidate.type === 'relay'));
|
|
737
737
|
|
|
738
|
-
const areCandidateValid = (candidates ) =>
|
|
739
|
-
getSrflxOrRelay(candidates)
|
|
740
|
-
.length > 0;
|
|
741
|
-
|
|
742
738
|
const getVideoDirection = (sdp ) => {
|
|
743
739
|
const parsedSdp = sdpParser__default['default'].parse(sdp);
|
|
744
740
|
const videoMedia = parsedSdp.media.find(media => media.type === 'video');
|
|
@@ -791,8 +787,6 @@ const fixSdp = (sdp , candidates , forcePort = true)
|
|
|
791
787
|
/* global RTCSessionDescriptionInit, navigator */
|
|
792
788
|
|
|
793
789
|
const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
|
|
794
|
-
const MAX_WAIT_FOR_ICE_TRIES = 20;
|
|
795
|
-
const WAIT_FOR_ICE_TIMEOUT = 500;
|
|
796
790
|
|
|
797
791
|
// Customized mediaStreamFactory allowing to send screensharing stream directory when upgrading
|
|
798
792
|
const wazoMediaStreamFactory = (constraints ) => {
|
|
@@ -982,38 +976,6 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
982
976
|
this._peerConnection = undefined;
|
|
983
977
|
}
|
|
984
978
|
|
|
985
|
-
async _waitForValidGatheredIce() {
|
|
986
|
-
let tries = 0;
|
|
987
|
-
|
|
988
|
-
while (!areCandidateValid(this.gatheredCandidates) && tries < MAX_WAIT_FOR_ICE_TRIES) {
|
|
989
|
-
wazoLogger.trace('SessionDescriptionHandler._waitForValidGatheredIce, waiting for ice', {
|
|
990
|
-
tries,
|
|
991
|
-
max: MAX_WAIT_FOR_ICE_TRIES,
|
|
992
|
-
});
|
|
993
|
-
|
|
994
|
-
tries++;
|
|
995
|
-
|
|
996
|
-
// eslint-disable-next-line no-await-in-loop
|
|
997
|
-
await new Promise(resolve => setTimeout(resolve, WAIT_FOR_ICE_TIMEOUT));
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
if (tries >= MAX_WAIT_FOR_ICE_TRIES) {
|
|
1001
|
-
const errorMsg = 'No valid candidates found, can\'t answer the call';
|
|
1002
|
-
const error = new Error(errorMsg);
|
|
1003
|
-
wazoLogger.error(errorMsg, { tries, max: MAX_WAIT_FOR_ICE_TRIES });
|
|
1004
|
-
|
|
1005
|
-
// Emit an error, because sip.js catches the exception and switch to status Terminated.
|
|
1006
|
-
this.eventEmitter.emit('error', error);
|
|
1007
|
-
|
|
1008
|
-
wazoLogger.error('No valid candidates found', { tries, candidates: JSON.stringify(this.gatheredCandidates) });
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
// eslint-disable-next-line
|
|
1012
|
-
wazoLogger.trace('Found valid candidates', { tries, candidates: JSON.stringify(this.gatheredCandidates) });
|
|
1013
|
-
|
|
1014
|
-
return this.getLocalSessionDescription();
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
979
|
// Overridden to send `inactive` in conference
|
|
1018
980
|
updateDirection(options , isConference = false,
|
|
1019
981
|
audioOnly = false) {
|
|
@@ -2123,6 +2085,9 @@ class Contact {
|
|
|
2123
2085
|
}
|
|
2124
2086
|
|
|
2125
2087
|
static parseMany(response ) {
|
|
2088
|
+
if (!response || !response.results) {
|
|
2089
|
+
return [];
|
|
2090
|
+
}
|
|
2126
2091
|
return response.results.map(r => Contact.parse(r, response.column_types));
|
|
2127
2092
|
}
|
|
2128
2093
|
|
|
@@ -3200,8 +3165,9 @@ class ExternalApp {
|
|
|
3200
3165
|
|
|
3201
3166
|
|
|
3202
3167
|
|
|
3203
|
-
|
|
3168
|
+
|
|
3204
3169
|
|
|
3170
|
+
|
|
3205
3171
|
|
|
3206
3172
|
|
|
3207
3173
|
class Meeting {
|
|
@@ -3212,9 +3178,10 @@ class Meeting {
|
|
|
3212
3178
|
|
|
3213
3179
|
|
|
3214
3180
|
|
|
3215
|
-
|
|
3181
|
+
|
|
3216
3182
|
|
|
3217
3183
|
|
|
3184
|
+
|
|
3218
3185
|
|
|
3219
3186
|
static parse(plain ) {
|
|
3220
3187
|
return new Meeting({
|
|
@@ -3224,12 +3191,16 @@ class Meeting {
|
|
|
3224
3191
|
ownerUuids: plain.owner_uuids,
|
|
3225
3192
|
port: plain.port,
|
|
3226
3193
|
uuid: plain.uuid,
|
|
3227
|
-
|
|
3194
|
+
extension: plain.exten,
|
|
3228
3195
|
persistent: plain.persistent,
|
|
3196
|
+
creationTime: moment__default['default'](plain.creation_time).toDate(),
|
|
3229
3197
|
});
|
|
3230
3198
|
}
|
|
3231
3199
|
|
|
3232
3200
|
static parseMany(items ) {
|
|
3201
|
+
if (!items) {
|
|
3202
|
+
return [];
|
|
3203
|
+
}
|
|
3233
3204
|
return items.map(plain => Meeting.parse(plain));
|
|
3234
3205
|
}
|
|
3235
3206
|
|
|
@@ -3244,8 +3215,9 @@ class Meeting {
|
|
|
3244
3215
|
ownerUuids,
|
|
3245
3216
|
port,
|
|
3246
3217
|
uri,
|
|
3247
|
-
|
|
3218
|
+
extension,
|
|
3248
3219
|
persistent,
|
|
3220
|
+
creationTime,
|
|
3249
3221
|
} = {}) {
|
|
3250
3222
|
this.guestSipAuthorization = guestSipAuthorization;
|
|
3251
3223
|
this.uri = uri;
|
|
@@ -3253,8 +3225,9 @@ class Meeting {
|
|
|
3253
3225
|
this.ownerUuids = ownerUuids;
|
|
3254
3226
|
this.port = port;
|
|
3255
3227
|
this.uuid = uuid;
|
|
3256
|
-
this.
|
|
3228
|
+
this.extension = extension;
|
|
3257
3229
|
this.persistent = persistent;
|
|
3230
|
+
this.creationTime = creationTime;
|
|
3258
3231
|
|
|
3259
3232
|
// Useful to compare instead of instanceof with minified code
|
|
3260
3233
|
this.type = 'Meeting';
|
|
@@ -3432,6 +3405,10 @@ class ChatMessage {
|
|
|
3432
3405
|
|
|
3433
3406
|
|
|
3434
3407
|
static parseMany(plain ) {
|
|
3408
|
+
if (!plain || !plain.items) {
|
|
3409
|
+
return [];
|
|
3410
|
+
}
|
|
3411
|
+
|
|
3435
3412
|
return plain.items.map(item => ChatMessage.parse(item));
|
|
3436
3413
|
}
|
|
3437
3414
|
|
|
@@ -3541,6 +3518,9 @@ class Voicemail {
|
|
|
3541
3518
|
}
|
|
3542
3519
|
|
|
3543
3520
|
static parseMany(plain ) {
|
|
3521
|
+
if (!plain) {
|
|
3522
|
+
return [];
|
|
3523
|
+
}
|
|
3544
3524
|
const plainUnread = plain.folders.filter(folder => folder.type === 'new')[0].messages;
|
|
3545
3525
|
const plainRead = plain.folders.filter(folder => folder.type === 'old')[0].messages;
|
|
3546
3526
|
|
|
@@ -3650,6 +3630,9 @@ class Call {
|
|
|
3650
3630
|
|
|
3651
3631
|
|
|
3652
3632
|
static parseMany(plain ) {
|
|
3633
|
+
if (!plain) {
|
|
3634
|
+
return [];
|
|
3635
|
+
}
|
|
3653
3636
|
return plain.map((plainCall ) => Call.parse(plainCall));
|
|
3654
3637
|
}
|
|
3655
3638
|
|
|
@@ -3822,6 +3805,9 @@ class Recording {
|
|
|
3822
3805
|
|
|
3823
3806
|
|
|
3824
3807
|
static parseMany(recordings = []) {
|
|
3808
|
+
if (!recordings) {
|
|
3809
|
+
return [];
|
|
3810
|
+
}
|
|
3825
3811
|
return recordings.map(item => Recording.parse(item));
|
|
3826
3812
|
}
|
|
3827
3813
|
|
|
@@ -3923,6 +3909,10 @@ class CallLog {
|
|
|
3923
3909
|
}
|
|
3924
3910
|
|
|
3925
3911
|
static parseMany(plain ) {
|
|
3912
|
+
if (!plain || !plain.items) {
|
|
3913
|
+
return [];
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3926
3916
|
return plain.items.map(item => CallLog.parse(item));
|
|
3927
3917
|
}
|
|
3928
3918
|
|
|
@@ -4495,6 +4485,9 @@ class ChatRoom {
|
|
|
4495
4485
|
|
|
4496
4486
|
|
|
4497
4487
|
static parseMany(plain ) {
|
|
4488
|
+
if (!plain || !plain.items) {
|
|
4489
|
+
return [];
|
|
4490
|
+
}
|
|
4498
4491
|
return plain.items.map(item => ChatRoom.parse(item));
|
|
4499
4492
|
}
|
|
4500
4493
|
|
|
@@ -5726,7 +5719,7 @@ class WebRTCClient extends Emitter {
|
|
|
5726
5719
|
}
|
|
5727
5720
|
|
|
5728
5721
|
call(number , enableVideo , audioOnly = false, conference = false) {
|
|
5729
|
-
logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
|
|
5722
|
+
logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly, conference });
|
|
5730
5723
|
const inviterOptions = {
|
|
5731
5724
|
sessionDescriptionHandlerOptionsReInvite: {
|
|
5732
5725
|
conference,
|
|
@@ -6802,6 +6795,7 @@ class WebRTCClient extends Emitter {
|
|
|
6802
6795
|
const screenSharing = constraints && 'screen' in constraints ? constraints.screen : false;
|
|
6803
6796
|
const isDesktop = constraints && 'desktop' in constraints ? constraints.desktop : false;
|
|
6804
6797
|
const withAudio = constraints && 'audio' in constraints ? constraints.audio : true;
|
|
6798
|
+
const mandatoryVideo = constraints && typeof constraints.video === 'object' ? constraints.video.mandatory : {};
|
|
6805
6799
|
|
|
6806
6800
|
logger.info('Retrieving media a configuration', { enableVideo, screenSharing, isDesktop, withAudio, constraints });
|
|
6807
6801
|
|
|
@@ -6809,7 +6803,8 @@ class WebRTCClient extends Emitter {
|
|
|
6809
6803
|
constraints: {
|
|
6810
6804
|
// Exact constraint are not supported with `getDisplayMedia` and we must have a video=false in desktop screenshare
|
|
6811
6805
|
audio: screenSharing ? !isDesktop : (withAudio ? this._getAudioConstraints() : false),
|
|
6812
|
-
video: screenSharing ? (isDesktop
|
|
6806
|
+
video: screenSharing ? (isDesktop
|
|
6807
|
+
? ({ mandatory: { chromeMediaSource: 'desktop', ...(mandatoryVideo || {}) } }) : { cursor: 'always' })
|
|
6813
6808
|
: this._getVideoConstraints(enableVideo),
|
|
6814
6809
|
screen: screenSharing,
|
|
6815
6810
|
desktop: isDesktop,
|
|
@@ -7144,11 +7139,14 @@ class WebRTCClient extends Emitter {
|
|
|
7144
7139
|
|
|
7145
7140
|
session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
|
|
7146
7141
|
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7142
|
+
if (pc) {
|
|
7143
|
+
pc.oniceconnectionstatechange = () => {
|
|
7144
|
+
logger.info('on ice connection state changed', { state: pc.iceConnectionState });
|
|
7145
|
+
if (pc.iceConnectionState === 'disconnected') {
|
|
7146
|
+
this.eventEmitter.emit(ON_DISCONNECTED);
|
|
7147
|
+
}
|
|
7148
|
+
};
|
|
7149
|
+
}
|
|
7152
7150
|
|
|
7153
7151
|
if (withEvent) {
|
|
7154
7152
|
this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
|
|
@@ -7358,13 +7356,17 @@ class WebRTCClient extends Emitter {
|
|
|
7358
7356
|
const nbStats = this.sessionNetworkStats[sessionId].length;
|
|
7359
7357
|
const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
|
|
7360
7358
|
const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
|
|
7359
|
+
const lastAudioContentSent = lastNetworkStats ? lastNetworkStats.audioContentSent : 0;
|
|
7361
7360
|
const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
|
|
7362
7361
|
const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
|
|
7362
|
+
const lastAudioContentReceived = lastNetworkStats ? lastNetworkStats.audioContentReceived : 0;
|
|
7363
7363
|
const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
|
|
7364
7364
|
const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
|
|
7365
7365
|
const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
|
|
7366
|
-
let audioBytesSent = 0;
|
|
7367
|
-
let audioBytesReceived = 0;
|
|
7366
|
+
let audioBytesSent = 0; // content + header
|
|
7367
|
+
let audioBytesReceived = 0; // content + header
|
|
7368
|
+
let audioContentSent = 0; // useful to detect blank call
|
|
7369
|
+
let audioContentReceived = 0;
|
|
7368
7370
|
let videoBytesSent = 0;
|
|
7369
7371
|
let videoBytesReceived = 0;
|
|
7370
7372
|
let transportSent = 0;
|
|
@@ -7373,25 +7375,27 @@ class WebRTCClient extends Emitter {
|
|
|
7373
7375
|
|
|
7374
7376
|
stats.forEach(report => {
|
|
7375
7377
|
if (report.type === 'outbound-rtp' && report.kind === 'audio') {
|
|
7376
|
-
audioBytesSent += report.bytesSent + report.headerBytesSent;
|
|
7378
|
+
audioBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
|
|
7379
|
+
audioContentSent += Number(report.bytesSent);
|
|
7377
7380
|
}
|
|
7378
7381
|
if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
|
|
7379
|
-
audioBytesSent += report.bytesSent;
|
|
7382
|
+
audioBytesSent += Number(report.bytesSent);
|
|
7380
7383
|
}
|
|
7381
7384
|
if (report.type === 'outbound-rtp' && report.kind === 'video') {
|
|
7382
|
-
videoBytesSent += report.bytesSent + report.headerBytesSent;
|
|
7385
|
+
videoBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
|
|
7383
7386
|
}
|
|
7384
7387
|
if (report.type === 'inbound-rtp' && report.kind === 'audio') {
|
|
7385
|
-
packetsLost += report.packetsLost;
|
|
7386
|
-
networkStats.packetsReceived = report.packetsReceived;
|
|
7387
|
-
audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
|
|
7388
|
+
packetsLost += Number(report.packetsLost);
|
|
7389
|
+
networkStats.packetsReceived = Number(report.packetsReceived);
|
|
7390
|
+
audioBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
7391
|
+
audioContentReceived += Number(report.bytesReceived);
|
|
7388
7392
|
}
|
|
7389
7393
|
if (report.type === 'inbound-rtp' && report.kind === 'video') {
|
|
7390
|
-
videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
|
|
7394
|
+
videoBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
|
|
7391
7395
|
}
|
|
7392
7396
|
if (report.type === 'outbound-rtp' && report.kind === 'video') {
|
|
7393
7397
|
if ('framesPerSecond' in report) {
|
|
7394
|
-
networkStats.framesPerSecond = report.framesPerSecond;
|
|
7398
|
+
networkStats.framesPerSecond = Number(report.framesPerSecond);
|
|
7395
7399
|
}
|
|
7396
7400
|
if ('framerateMean' in report) {
|
|
7397
7401
|
// framerateMean is only available in FF
|
|
@@ -7399,24 +7403,31 @@ class WebRTCClient extends Emitter {
|
|
|
7399
7403
|
}
|
|
7400
7404
|
}
|
|
7401
7405
|
if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
|
|
7402
|
-
packetsLost += report.packetsLost;
|
|
7403
|
-
networkStats.roundTripTime = report.roundTripTime;
|
|
7404
|
-
networkStats.jitter = report.jitter;
|
|
7406
|
+
packetsLost += Number(report.packetsLost);
|
|
7407
|
+
networkStats.roundTripTime = Number(report.roundTripTime);
|
|
7408
|
+
networkStats.jitter = Number(report.jitter);
|
|
7405
7409
|
}
|
|
7406
7410
|
if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
|
|
7407
|
-
packetsLost += report.packetsLost;
|
|
7411
|
+
packetsLost += Number(report.packetsLost);
|
|
7408
7412
|
}
|
|
7409
7413
|
if (report.type === 'transport') {
|
|
7410
|
-
transportSent += report.bytesSent;
|
|
7411
|
-
transportReceived += report.bytesReceived;
|
|
7414
|
+
transportSent += Number(report.bytesSent);
|
|
7415
|
+
transportReceived += Number(report.bytesReceived);
|
|
7412
7416
|
}
|
|
7413
7417
|
});
|
|
7414
7418
|
|
|
7415
7419
|
networkStats.packetsLost = packetsLost;
|
|
7420
|
+
|
|
7416
7421
|
networkStats.totalAudioBytesSent = audioBytesSent;
|
|
7417
7422
|
networkStats.audioBytesSent = audioBytesSent - lastAudioSent;
|
|
7418
7423
|
networkStats.totalAudioBytesReceived = audioBytesReceived - lastAudioReceived;
|
|
7419
7424
|
networkStats.audioBytesReceived = audioBytesReceived;
|
|
7425
|
+
|
|
7426
|
+
networkStats.totalAudioContentSent = audioContentSent;
|
|
7427
|
+
networkStats.audioContentSent = audioContentSent - lastAudioContentSent;
|
|
7428
|
+
networkStats.totalAudioBytesReceived = audioContentReceived - lastAudioContentReceived;
|
|
7429
|
+
networkStats.audioContentReceived = audioContentReceived;
|
|
7430
|
+
|
|
7420
7431
|
networkStats.totalVideoBytesSent = videoBytesSent;
|
|
7421
7432
|
networkStats.videoBytesSent = videoBytesSent - lastVideoSent;
|
|
7422
7433
|
networkStats.totalVideoBytesReceived = videoBytesReceived;
|
package/package.json
CHANGED
package/src/domain/Call.js
CHANGED
package/src/domain/CallLog.js
CHANGED
package/src/domain/ChatRoom.js
CHANGED
package/src/domain/Contact.js
CHANGED
|
@@ -281,6 +281,9 @@ export default class Contact {
|
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
static parseMany(response: ContactsResponse): Array<Contact> {
|
|
284
|
+
if (!response || !response.results) {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
284
287
|
return response.results.map(r => Contact.parse(r, response.column_types));
|
|
285
288
|
}
|
|
286
289
|
|
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,12 +36,16 @@ 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
|
|
|
40
45
|
static parseMany(items: MeetingCreationResponse[]): Array<Meeting> {
|
|
46
|
+
if (!items) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
41
49
|
return items.map(plain => Meeting.parse(plain));
|
|
42
50
|
}
|
|
43
51
|
|
|
@@ -52,8 +60,9 @@ export default class Meeting {
|
|
|
52
60
|
ownerUuids,
|
|
53
61
|
port,
|
|
54
62
|
uri,
|
|
55
|
-
|
|
63
|
+
extension,
|
|
56
64
|
persistent,
|
|
65
|
+
creationTime,
|
|
57
66
|
}: Object = {}) {
|
|
58
67
|
this.guestSipAuthorization = guestSipAuthorization;
|
|
59
68
|
this.uri = uri;
|
|
@@ -61,8 +70,9 @@ export default class Meeting {
|
|
|
61
70
|
this.ownerUuids = ownerUuids;
|
|
62
71
|
this.port = port;
|
|
63
72
|
this.uuid = uuid;
|
|
64
|
-
this.
|
|
73
|
+
this.extension = extension;
|
|
65
74
|
this.persistent = persistent;
|
|
75
|
+
this.creationTime = creationTime;
|
|
66
76
|
|
|
67
77
|
// Useful to compare instead of instanceof with minified code
|
|
68
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;
|
|
@@ -385,7 +396,10 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
385
396
|
|
|
386
397
|
onCancel(message);
|
|
387
398
|
const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
|
|
388
|
-
|
|
399
|
+
const callSession = this._createCallSession(sipSession);
|
|
400
|
+
delete this.callSessions[callSession.getId()];
|
|
401
|
+
|
|
402
|
+
this.eventEmitter.emit(ON_CALL_CANCELED, callSession, elsewhere);
|
|
389
403
|
};
|
|
390
404
|
} else if (sipSession instanceof Invitation) {
|
|
391
405
|
console.warn('sipSession._onCancel not found, please update the wazo SDK accordingly');
|
|
@@ -568,18 +582,20 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
568
582
|
screenTrack,
|
|
569
583
|
});
|
|
570
584
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
585
|
+
if (screenTrack) {
|
|
586
|
+
screenTrack.onended = () => {
|
|
587
|
+
logger.info('WebRTC phone - on screenshare ended', {
|
|
588
|
+
hadVideo,
|
|
589
|
+
id: this.getSipSessionId(sipSession),
|
|
590
|
+
screenTrack,
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
this.eventEmitter.emit(
|
|
594
|
+
ON_SHARE_SCREEN_ENDING,
|
|
595
|
+
this._createCallSession(sipSession, callSession),
|
|
596
|
+
);
|
|
597
|
+
};
|
|
598
|
+
}
|
|
583
599
|
|
|
584
600
|
this.currentScreenShare = {
|
|
585
601
|
stream: screenStream,
|
|
@@ -599,7 +615,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
599
615
|
}
|
|
600
616
|
|
|
601
617
|
_onCallAccepted(sipSession: Session, cameraEnabled: boolean): CallSession {
|
|
602
|
-
logger.info('WebRTC phone -
|
|
618
|
+
logger.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
|
|
603
619
|
|
|
604
620
|
const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
|
|
605
621
|
this.currentSipSession = sipSession;
|
|
@@ -1111,7 +1127,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1111
1127
|
// @TODO: line is not used here
|
|
1112
1128
|
async makeCall(number: string, line: any, cameraEnabled?: boolean,
|
|
1113
1129
|
audioOnly: boolean = false, conference: boolean = false): Promise<?CallSession> {
|
|
1114
|
-
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 });
|
|
1115
1131
|
if (!number) {
|
|
1116
1132
|
return Promise.resolve(null);
|
|
1117
1133
|
}
|
|
@@ -1472,9 +1488,13 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1472
1488
|
if (this.shouldSendReinvite && this.currentSipSession
|
|
1473
1489
|
&& this.currentSipSession.state === SessionState.Established) {
|
|
1474
1490
|
this.shouldSendReinvite = false;
|
|
1491
|
+
const pc = this.currentSipSession.sessionDescriptionHandler.peerConnection;
|
|
1492
|
+
const isConference = pc ? pc.sfu : false;
|
|
1493
|
+
const hasVideo = this.currentCallSession && this.currentCallSession.cameraEnabled;
|
|
1494
|
+
|
|
1475
1495
|
try {
|
|
1476
1496
|
// Send reinvite with iceRestart
|
|
1477
|
-
this.sendReinvite(this.currentCallSession, null,
|
|
1497
|
+
this.sendReinvite(this.currentCallSession, null, isConference, !hasVideo, true);
|
|
1478
1498
|
} catch (e) {
|
|
1479
1499
|
logger.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
|
|
1480
1500
|
}
|
|
@@ -1558,6 +1578,15 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
1558
1578
|
return this.client.getSipSessionId(sipSession);
|
|
1559
1579
|
}
|
|
1560
1580
|
|
|
1581
|
+
_updateCallSession(callSession: CallSession) {
|
|
1582
|
+
const sipSession = this.findSipSession(callSession);
|
|
1583
|
+
const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
|
|
1584
|
+
|
|
1585
|
+
if (sipSessionId) {
|
|
1586
|
+
this.callSessions[sipSessionId] = callSession;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1561
1590
|
_onMessage(message: Message) {
|
|
1562
1591
|
if (!message || message.method !== 'MESSAGE') {
|
|
1563
1592
|
return;
|
package/src/domain/Recording.js
CHANGED
package/src/domain/Voicemail.js
CHANGED
|
@@ -61,6 +61,9 @@ export default class Voicemail {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
static parseMany(plain: Response): Array<Voicemail> {
|
|
64
|
+
if (!plain) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
64
67
|
const plainUnread = plain.folders.filter(folder => folder.type === 'new')[0].messages;
|
|
65
68
|
const plainRead = plain.folders.filter(folder => folder.type === 'old')[0].messages;
|
|
66
69
|
|
|
@@ -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
|
+
});
|