@wazo/sdk 0.37.15 → 0.37.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.
Files changed (114) hide show
  1. package/dist/wazo-sdk.js +3 -3
  2. package/esm/__tests__/api-client.test.js +9 -5
  3. package/esm/__tests__/web-rtc-client.test.js +117 -23
  4. package/esm/api/agentd.js +1 -1
  5. package/esm/api/amid.js +1 -1
  6. package/esm/api/application.js +1 -1
  7. package/esm/api/auth.js +1 -1
  8. package/esm/api/call-logd.js +3 -3
  9. package/esm/api/calld.js +1 -1
  10. package/esm/api/chatd.js +1 -1
  11. package/esm/api/confd.js +7 -3
  12. package/esm/api/ctid-ng.js +1 -1
  13. package/esm/api/dird.js +1 -1
  14. package/esm/api/webhookd.js +1 -1
  15. package/esm/api-client.js +9 -5
  16. package/esm/checker/Checker.js +117 -23
  17. package/esm/checker/checks/aor.js +9 -5
  18. package/esm/checker/checks/api.js +9 -5
  19. package/esm/checker/checks/index.js +117 -23
  20. package/esm/checker/checks/wazo-websocket.js +1 -1
  21. package/esm/checker/checks/webrtc-transport.js +117 -23
  22. package/esm/checker/checks/webrtc.js +117 -23
  23. package/esm/domain/AdHocAPIConference.js +9 -5
  24. package/esm/domain/CallLog.js +2 -2
  25. package/esm/domain/Features.js +9 -5
  26. package/esm/domain/Meeting.js +6 -2
  27. package/esm/domain/Phone/CTIPhone.js +9 -5
  28. package/esm/domain/Phone/WebRTCPhone.js +9 -2
  29. package/esm/domain/Recording.js +1 -1
  30. package/esm/domain/__tests__/CallLog.test.js +2 -2
  31. package/esm/index.js +125 -23
  32. package/esm/lib/WazoSessionDescriptionHandler.js +1 -1
  33. package/esm/service/CallApi.js +9 -5
  34. package/esm/service/IssueReporter.js +1 -1
  35. package/esm/service/__tests__/IssueReporter.test.js +1 -1
  36. package/esm/service/getApiClient.js +9 -5
  37. package/esm/simple/Auth.js +125 -23
  38. package/esm/simple/Configuration.js +125 -23
  39. package/esm/simple/Directory.js +9 -5
  40. package/esm/simple/Phone.js +125 -23
  41. package/esm/simple/Websocket.js +1 -1
  42. package/esm/simple/index.js +125 -23
  43. package/esm/simple/room/LocalParticipant.js +125 -23
  44. package/esm/simple/room/Participant.js +125 -23
  45. package/esm/simple/room/RemoteParticipant.js +125 -23
  46. package/esm/simple/room/Room.js +125 -23
  47. package/esm/simple/room/SipRoom.js +125 -23
  48. package/esm/simple/room/Stream.js +125 -23
  49. package/esm/simple/room/__tests__/RemoteParticipant.test.js +125 -23
  50. package/esm/simple/utils.js +125 -23
  51. package/esm/utils/__tests__/api-requester.test.js +1 -1
  52. package/esm/utils/api-requester.js +1 -1
  53. package/esm/web-rtc-client.js +117 -23
  54. package/esm/websocket-client.js +1 -1
  55. package/lib/__tests__/api-client.test.js +9 -5
  56. package/lib/__tests__/web-rtc-client.test.js +117 -23
  57. package/lib/api/agentd.js +1 -1
  58. package/lib/api/amid.js +1 -1
  59. package/lib/api/application.js +1 -1
  60. package/lib/api/auth.js +1 -1
  61. package/lib/api/call-logd.js +3 -3
  62. package/lib/api/calld.js +1 -1
  63. package/lib/api/chatd.js +1 -1
  64. package/lib/api/confd.js +7 -3
  65. package/lib/api/ctid-ng.js +1 -1
  66. package/lib/api/dird.js +1 -1
  67. package/lib/api/webhookd.js +1 -1
  68. package/lib/api-client.js +9 -5
  69. package/lib/checker/Checker.js +117 -23
  70. package/lib/checker/checks/aor.js +9 -5
  71. package/lib/checker/checks/api.js +9 -5
  72. package/lib/checker/checks/index.js +117 -23
  73. package/lib/checker/checks/wazo-websocket.js +1 -1
  74. package/lib/checker/checks/webrtc-transport.js +117 -23
  75. package/lib/checker/checks/webrtc.js +117 -23
  76. package/lib/domain/AdHocAPIConference.js +9 -5
  77. package/lib/domain/CallLog.js +2 -2
  78. package/lib/domain/Features.js +9 -5
  79. package/lib/domain/Meeting.js +6 -2
  80. package/lib/domain/Phone/CTIPhone.js +9 -5
  81. package/lib/domain/Phone/WebRTCPhone.js +9 -1
  82. package/lib/domain/Recording.js +1 -1
  83. package/lib/domain/__tests__/CallLog.test.js +2 -2
  84. package/lib/index.js +125 -23
  85. package/lib/lib/WazoSessionDescriptionHandler.js +1 -1
  86. package/lib/service/CallApi.js +9 -5
  87. package/lib/service/IssueReporter.js +1 -1
  88. package/lib/service/__tests__/IssueReporter.test.js +1 -1
  89. package/lib/service/getApiClient.js +9 -5
  90. package/lib/simple/Auth.js +125 -23
  91. package/lib/simple/Configuration.js +125 -23
  92. package/lib/simple/Directory.js +9 -5
  93. package/lib/simple/Phone.js +125 -23
  94. package/lib/simple/Websocket.js +1 -1
  95. package/lib/simple/index.js +125 -23
  96. package/lib/simple/room/LocalParticipant.js +125 -23
  97. package/lib/simple/room/Participant.js +125 -23
  98. package/lib/simple/room/RemoteParticipant.js +125 -23
  99. package/lib/simple/room/Room.js +125 -23
  100. package/lib/simple/room/SipRoom.js +125 -23
  101. package/lib/simple/room/Stream.js +125 -23
  102. package/lib/simple/room/__tests__/RemoteParticipant.test.js +125 -23
  103. package/lib/simple/utils.js +125 -23
  104. package/lib/utils/__tests__/api-requester.test.js +1 -1
  105. package/lib/utils/api-requester.js +1 -1
  106. package/lib/web-rtc-client.js +117 -23
  107. package/lib/websocket-client.js +1 -1
  108. package/package.json +1 -1
  109. package/src/domain/CallLog.js +1 -1
  110. package/src/domain/Meeting.js +6 -2
  111. package/src/domain/Phone/WebRTCPhone.js +7 -0
  112. package/src/domain/Recording.js +1 -1
  113. package/src/service/IssueReporter.js +1 -1
  114. package/src/web-rtc-client.js +108 -18
@@ -373,7 +373,7 @@ class IssueReporter {
373
373
  payload._retry = retry + 1;
374
374
  }
375
375
 
376
- this._sendDebugToGrafana(body, retry + 1);
376
+ this._sendDebugToGrafana(payload, retry + 1);
377
377
  }, 5000 + retry * 1000);
378
378
  });
379
379
  }
@@ -664,7 +664,7 @@ class IssueReporter {
664
664
  payload._retry = retry + 1;
665
665
  }
666
666
 
667
- this._sendDebugToGrafana(body, retry + 1);
667
+ this._sendDebugToGrafana(payload, retry + 1);
668
668
  }, 5000 + retry * 1000);
669
669
  });
670
670
  }
@@ -3166,7 +3166,8 @@ class ExternalApp {
3166
3166
 
3167
3167
 
3168
3168
 
3169
-
3169
+
3170
+
3170
3171
 
3171
3172
 
3172
3173
  class Meeting {
@@ -3178,6 +3179,7 @@ class Meeting {
3178
3179
 
3179
3180
 
3180
3181
 
3182
+
3181
3183
 
3182
3184
 
3183
3185
  static parse(plain ) {
@@ -3189,6 +3191,7 @@ class Meeting {
3189
3191
  port: plain.port,
3190
3192
  uuid: plain.uuid,
3191
3193
  number: plain.number,
3194
+ persistent: plain.persistent,
3192
3195
  });
3193
3196
  }
3194
3197
 
@@ -3196,7 +3199,7 @@ class Meeting {
3196
3199
  return newFrom(meeting, Meeting);
3197
3200
  }
3198
3201
 
3199
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
3202
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
3200
3203
  this.guestSipAuthorization = guestSipAuthorization;
3201
3204
  this.uri = uri;
3202
3205
  this.name = name;
@@ -3204,6 +3207,7 @@ class Meeting {
3204
3207
  this.port = port;
3205
3208
  this.uuid = uuid;
3206
3209
  this.number = number;
3210
+ this.persistent = persistent;
3207
3211
 
3208
3212
  // Useful to compare instead of instanceof with minified code
3209
3213
  this.type = 'Meeting';
@@ -3767,7 +3771,7 @@ class Recording {
3767
3771
 
3768
3772
 
3769
3773
 
3770
- static parseMany(recordings ) {
3774
+ static parseMany(recordings = []) {
3771
3775
  return recordings.map(item => Recording.parse(item));
3772
3776
  }
3773
3777
 
@@ -3893,7 +3897,7 @@ class CallLog {
3893
3897
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3894
3898
  start: moment(plain.start).toDate(),
3895
3899
  end: plain.end ? moment(plain.end).toDate() : null,
3896
- recordings: Recording.parseMany(plain.recordings),
3900
+ recordings: Recording.parseMany(plain.recordings || []),
3897
3901
  });
3898
3902
  }
3899
3903
 
@@ -5288,6 +5292,7 @@ const ON_REINVITE = 'reinvite';
5288
5292
  const ON_ERROR = 'onError';
5289
5293
  const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
5290
5294
  const ON_NETWORK_STATS = 'onNetworkStats';
5295
+ const ON_DISCONNECTED = 'onDisconnected';
5291
5296
  class CanceledCallError extends Error {}
5292
5297
 
5293
5298
  const MAX_REGISTER_TRIES = 10;
@@ -5361,6 +5366,7 @@ class WebRTCClient extends Emitter {
5361
5366
 
5362
5367
 
5363
5368
 
5369
+
5364
5370
 
5365
5371
  static isAPrivateIp(ip ) {
5366
5372
  const regex = /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/;
@@ -5426,6 +5432,7 @@ class WebRTCClient extends Emitter {
5426
5432
  this.ON_ERROR = ON_ERROR;
5427
5433
  this.ON_SCREEN_SHARING_REINVITE = ON_SCREEN_SHARING_REINVITE;
5428
5434
  this.ON_NETWORK_STATS = ON_NETWORK_STATS;
5435
+ this.ON_DISCONNECTED = ON_DISCONNECTED;
5429
5436
  }
5430
5437
 
5431
5438
  configureMedia(media ) {
@@ -6027,7 +6034,7 @@ class WebRTCClient extends Emitter {
6027
6034
  // We search for the last transceiver without `video-` in the mid (video- means remote transceiver)
6028
6035
  const transceivers = pc.getTransceivers();
6029
6036
  const transceiverIdx = lastIndexOf(transceivers, transceiver =>
6030
- transceiver.sender.track === null && transceiver.mid.indexOf('video') === -1);
6037
+ transceiver.sender.track === null && transceiver.mid && transceiver.mid.indexOf('video') === -1);
6031
6038
 
6032
6039
  videoSender = transceiverIdx !== -1 ? transceivers[transceiverIdx].sender : null;
6033
6040
  } else {
@@ -6273,10 +6280,13 @@ class WebRTCClient extends Emitter {
6273
6280
  return null;
6274
6281
  }
6275
6282
 
6276
- // let's update the local value
6277
- if (this.audio && this.audio.deviceId) {
6278
- // $FlowFixMe
6279
- this.audio.deviceId.exact = id;
6283
+ // let's update the local audio value
6284
+ if (this.audio) {
6285
+ this.audio = {
6286
+ deviceId: {
6287
+ exact: id,
6288
+ },
6289
+ };
6280
6290
  }
6281
6291
 
6282
6292
  if (session) {
@@ -6289,6 +6299,9 @@ class WebRTCClient extends Emitter {
6289
6299
  const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
6290
6300
 
6291
6301
  if (sender) {
6302
+ if (sender.track) {
6303
+ audioTrack.enabled = sender.track.enabled;
6304
+ }
6292
6305
  sender.replaceTrack(audioTrack);
6293
6306
  }
6294
6307
 
@@ -6313,7 +6326,7 @@ class WebRTCClient extends Emitter {
6313
6326
  return null;
6314
6327
  }
6315
6328
 
6316
- // let's update the local value
6329
+ // let's update the local video value
6317
6330
  if (this.video) {
6318
6331
  this.video = {
6319
6332
  deviceId: {
@@ -6348,12 +6361,21 @@ class WebRTCClient extends Emitter {
6348
6361
  return navigator.mediaDevices.getUserMedia(constraints).then(async stream => {
6349
6362
  const videoTrack = stream.getVideoTracks()[0];
6350
6363
  let sender = pc && pc.getSenders().find(s => videoTrack && s && s.track && s.track.kind === videoTrack.kind);
6364
+ let wasTrackEnabled = false;
6351
6365
  if (!sender) {
6352
6366
  sender = pc && pc.getSenders().find(s => !s.track);
6353
6367
  }
6354
6368
 
6355
6369
  if (sender) {
6356
- sender.replaceTrack(videoTrack);
6370
+ // No video track means video not enabled
6371
+ wasTrackEnabled = sender.track ? sender.track.enabled : false;
6372
+ videoTrack.enabled = wasTrackEnabled;
6373
+
6374
+ if (!wasTrackEnabled) {
6375
+ videoTrack.stop();
6376
+ }
6377
+
6378
+ sender.replaceTrack(wasTrackEnabled ? videoTrack : null);
6357
6379
  }
6358
6380
 
6359
6381
  // let's update the local stream
@@ -7037,6 +7059,7 @@ class WebRTCClient extends Emitter {
7037
7059
 
7038
7060
  this.updateRemoteStream(this.getSipSessionId(session));
7039
7061
 
7062
+ const pc = session.sessionDescriptionHandler.peerConnection;
7040
7063
  const onTrack = (event ) => {
7041
7064
  const isAudioOnly = this._isAudioOnly(session);
7042
7065
  const { kind, label, readyState, id, muted } = event.track;
@@ -7056,6 +7079,12 @@ class WebRTCClient extends Emitter {
7056
7079
 
7057
7080
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
7058
7081
 
7082
+ pc.oniceconnectionstatechange = () => {
7083
+ if (pc.iceConnectionState === 'disconnected') {
7084
+ this.eventEmitter.emit(ON_DISCONNECTED);
7085
+ }
7086
+ };
7087
+
7059
7088
  if (withEvent) {
7060
7089
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
7061
7090
  }
@@ -7251,24 +7280,89 @@ class WebRTCClient extends Emitter {
7251
7280
  const session = this.getSipSession(sessionId);
7252
7281
 
7253
7282
  const stats = session ? await this.getStats(session) : null;
7254
- if (!stats) {
7283
+ if (!stats || !(sessionId in this.sessionNetworkStats)) {
7255
7284
  return;
7256
7285
  }
7257
7286
 
7287
+ const networkStats = {
7288
+ audioBytesSent: 0,
7289
+ videoBytesSent: 0,
7290
+ videoBytesReceived: 0,
7291
+ audioBytesReceived: 0,
7292
+ };
7293
+ const nbStats = this.sessionNetworkStats[sessionId].length;
7294
+ const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
7295
+ const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
7296
+ const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
7297
+ const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
7298
+ const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
7299
+ const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
7300
+ const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
7301
+ let audioBytesSent = 0;
7302
+ let audioBytesReceived = 0;
7303
+ let videoBytesSent = 0;
7304
+ let videoBytesReceived = 0;
7305
+ let transportSent = 0;
7306
+ let transportReceived = 0;
7307
+ let packetsLost = 0;
7308
+
7258
7309
  stats.forEach(report => {
7259
- if (report.type === 'inbound-rtp') {
7260
- if (report.kind === 'audio') {
7261
- const networkStats = {
7262
- packetsLost: report.packetsLost,
7263
- packetsReceived: report.packetsReceived,
7264
- jitter: report.jitter,
7265
- };
7266
-
7267
- this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7268
- this.sessionNetworkStats[sessionId].push(networkStats);
7310
+ if (report.type === 'outbound-rtp' && report.kind === 'audio') {
7311
+ audioBytesSent += report.bytesSent + report.headerBytesSent;
7312
+ }
7313
+ if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
7314
+ audioBytesSent += report.bytesSent;
7315
+ }
7316
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7317
+ videoBytesSent += report.bytesSent + report.headerBytesSent;
7318
+ }
7319
+ if (report.type === 'inbound-rtp' && report.kind === 'audio') {
7320
+ packetsLost += report.packetsLost;
7321
+ networkStats.packetsReceived = report.packetsReceived;
7322
+ audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
7323
+ }
7324
+ if (report.type === 'inbound-rtp' && report.kind === 'video') {
7325
+ videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
7326
+ }
7327
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7328
+ if ('framesPerSecond' in report) {
7329
+ networkStats.framesPerSecond = report.framesPerSecond;
7269
7330
  }
7331
+ if ('framerateMean' in report) {
7332
+ // framerateMean is only available in FF
7333
+ networkStats.framesPerSecond = Math.round(report.framerateMean);
7334
+ }
7335
+ }
7336
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
7337
+ packetsLost += report.packetsLost;
7338
+ networkStats.roundTripTime = report.roundTripTime;
7339
+ networkStats.jitter = report.jitter;
7340
+ }
7341
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
7342
+ packetsLost += report.packetsLost;
7343
+ }
7344
+ if (report.type === 'transport') {
7345
+ transportSent += report.bytesSent;
7346
+ transportReceived += report.bytesReceived;
7270
7347
  }
7271
7348
  });
7349
+
7350
+ networkStats.packetsLost = packetsLost;
7351
+ networkStats.audioBytesSent = audioBytesSent;
7352
+ networkStats.audioBytesReceived = audioBytesReceived;
7353
+ networkStats.videoBytesSent = videoBytesSent;
7354
+ networkStats.videoBytesReceived = videoBytesReceived;
7355
+ networkStats.transportSent = transportSent;
7356
+ networkStats.transportReceived = transportReceived;
7357
+
7358
+ const bandwidth = (networkStats.audioBytesSent - lastAudioSent) + (networkStats.videoBytesSent - lastVideoSent)
7359
+ + (networkStats.audioBytesReceived - lastAudioReceived) + (networkStats.videoBytesReceived - lastVideoReceived)
7360
+ + (networkStats.transportReceived - lastTransportReceived) + (networkStats.transportSent - lastTransportSent);
7361
+
7362
+ networkStats.bandwidth = bandwidth;
7363
+
7364
+ this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7365
+ this.sessionNetworkStats[sessionId].push(networkStats);
7272
7366
  }
7273
7367
 
7274
7368
  }
@@ -664,7 +664,7 @@ class IssueReporter {
664
664
  payload._retry = retry + 1;
665
665
  }
666
666
 
667
- this._sendDebugToGrafana(body, retry + 1);
667
+ this._sendDebugToGrafana(payload, retry + 1);
668
668
  }, 5000 + retry * 1000);
669
669
  });
670
670
  }
@@ -3166,7 +3166,8 @@ class ExternalApp {
3166
3166
 
3167
3167
 
3168
3168
 
3169
-
3169
+
3170
+
3170
3171
 
3171
3172
 
3172
3173
  class Meeting {
@@ -3178,6 +3179,7 @@ class Meeting {
3178
3179
 
3179
3180
 
3180
3181
 
3182
+
3181
3183
 
3182
3184
 
3183
3185
  static parse(plain ) {
@@ -3189,6 +3191,7 @@ class Meeting {
3189
3191
  port: plain.port,
3190
3192
  uuid: plain.uuid,
3191
3193
  number: plain.number,
3194
+ persistent: plain.persistent,
3192
3195
  });
3193
3196
  }
3194
3197
 
@@ -3196,7 +3199,7 @@ class Meeting {
3196
3199
  return newFrom(meeting, Meeting);
3197
3200
  }
3198
3201
 
3199
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
3202
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
3200
3203
  this.guestSipAuthorization = guestSipAuthorization;
3201
3204
  this.uri = uri;
3202
3205
  this.name = name;
@@ -3204,6 +3207,7 @@ class Meeting {
3204
3207
  this.port = port;
3205
3208
  this.uuid = uuid;
3206
3209
  this.number = number;
3210
+ this.persistent = persistent;
3207
3211
 
3208
3212
  // Useful to compare instead of instanceof with minified code
3209
3213
  this.type = 'Meeting';
@@ -3767,7 +3771,7 @@ class Recording {
3767
3771
 
3768
3772
 
3769
3773
 
3770
- static parseMany(recordings ) {
3774
+ static parseMany(recordings = []) {
3771
3775
  return recordings.map(item => Recording.parse(item));
3772
3776
  }
3773
3777
 
@@ -3893,7 +3897,7 @@ class CallLog {
3893
3897
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3894
3898
  start: moment(plain.start).toDate(),
3895
3899
  end: plain.end ? moment(plain.end).toDate() : null,
3896
- recordings: Recording.parseMany(plain.recordings),
3900
+ recordings: Recording.parseMany(plain.recordings || []),
3897
3901
  });
3898
3902
  }
3899
3903
 
@@ -5288,6 +5292,7 @@ const ON_REINVITE = 'reinvite';
5288
5292
  const ON_ERROR = 'onError';
5289
5293
  const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
5290
5294
  const ON_NETWORK_STATS = 'onNetworkStats';
5295
+ const ON_DISCONNECTED = 'onDisconnected';
5291
5296
  class CanceledCallError extends Error {}
5292
5297
 
5293
5298
  const MAX_REGISTER_TRIES = 10;
@@ -5361,6 +5366,7 @@ class WebRTCClient extends Emitter {
5361
5366
 
5362
5367
 
5363
5368
 
5369
+
5364
5370
 
5365
5371
  static isAPrivateIp(ip ) {
5366
5372
  const regex = /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/;
@@ -5426,6 +5432,7 @@ class WebRTCClient extends Emitter {
5426
5432
  this.ON_ERROR = ON_ERROR;
5427
5433
  this.ON_SCREEN_SHARING_REINVITE = ON_SCREEN_SHARING_REINVITE;
5428
5434
  this.ON_NETWORK_STATS = ON_NETWORK_STATS;
5435
+ this.ON_DISCONNECTED = ON_DISCONNECTED;
5429
5436
  }
5430
5437
 
5431
5438
  configureMedia(media ) {
@@ -6027,7 +6034,7 @@ class WebRTCClient extends Emitter {
6027
6034
  // We search for the last transceiver without `video-` in the mid (video- means remote transceiver)
6028
6035
  const transceivers = pc.getTransceivers();
6029
6036
  const transceiverIdx = lastIndexOf(transceivers, transceiver =>
6030
- transceiver.sender.track === null && transceiver.mid.indexOf('video') === -1);
6037
+ transceiver.sender.track === null && transceiver.mid && transceiver.mid.indexOf('video') === -1);
6031
6038
 
6032
6039
  videoSender = transceiverIdx !== -1 ? transceivers[transceiverIdx].sender : null;
6033
6040
  } else {
@@ -6273,10 +6280,13 @@ class WebRTCClient extends Emitter {
6273
6280
  return null;
6274
6281
  }
6275
6282
 
6276
- // let's update the local value
6277
- if (this.audio && this.audio.deviceId) {
6278
- // $FlowFixMe
6279
- this.audio.deviceId.exact = id;
6283
+ // let's update the local audio value
6284
+ if (this.audio) {
6285
+ this.audio = {
6286
+ deviceId: {
6287
+ exact: id,
6288
+ },
6289
+ };
6280
6290
  }
6281
6291
 
6282
6292
  if (session) {
@@ -6289,6 +6299,9 @@ class WebRTCClient extends Emitter {
6289
6299
  const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
6290
6300
 
6291
6301
  if (sender) {
6302
+ if (sender.track) {
6303
+ audioTrack.enabled = sender.track.enabled;
6304
+ }
6292
6305
  sender.replaceTrack(audioTrack);
6293
6306
  }
6294
6307
 
@@ -6313,7 +6326,7 @@ class WebRTCClient extends Emitter {
6313
6326
  return null;
6314
6327
  }
6315
6328
 
6316
- // let's update the local value
6329
+ // let's update the local video value
6317
6330
  if (this.video) {
6318
6331
  this.video = {
6319
6332
  deviceId: {
@@ -6348,12 +6361,21 @@ class WebRTCClient extends Emitter {
6348
6361
  return navigator.mediaDevices.getUserMedia(constraints).then(async stream => {
6349
6362
  const videoTrack = stream.getVideoTracks()[0];
6350
6363
  let sender = pc && pc.getSenders().find(s => videoTrack && s && s.track && s.track.kind === videoTrack.kind);
6364
+ let wasTrackEnabled = false;
6351
6365
  if (!sender) {
6352
6366
  sender = pc && pc.getSenders().find(s => !s.track);
6353
6367
  }
6354
6368
 
6355
6369
  if (sender) {
6356
- sender.replaceTrack(videoTrack);
6370
+ // No video track means video not enabled
6371
+ wasTrackEnabled = sender.track ? sender.track.enabled : false;
6372
+ videoTrack.enabled = wasTrackEnabled;
6373
+
6374
+ if (!wasTrackEnabled) {
6375
+ videoTrack.stop();
6376
+ }
6377
+
6378
+ sender.replaceTrack(wasTrackEnabled ? videoTrack : null);
6357
6379
  }
6358
6380
 
6359
6381
  // let's update the local stream
@@ -7037,6 +7059,7 @@ class WebRTCClient extends Emitter {
7037
7059
 
7038
7060
  this.updateRemoteStream(this.getSipSessionId(session));
7039
7061
 
7062
+ const pc = session.sessionDescriptionHandler.peerConnection;
7040
7063
  const onTrack = (event ) => {
7041
7064
  const isAudioOnly = this._isAudioOnly(session);
7042
7065
  const { kind, label, readyState, id, muted } = event.track;
@@ -7056,6 +7079,12 @@ class WebRTCClient extends Emitter {
7056
7079
 
7057
7080
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
7058
7081
 
7082
+ pc.oniceconnectionstatechange = () => {
7083
+ if (pc.iceConnectionState === 'disconnected') {
7084
+ this.eventEmitter.emit(ON_DISCONNECTED);
7085
+ }
7086
+ };
7087
+
7059
7088
  if (withEvent) {
7060
7089
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
7061
7090
  }
@@ -7251,24 +7280,89 @@ class WebRTCClient extends Emitter {
7251
7280
  const session = this.getSipSession(sessionId);
7252
7281
 
7253
7282
  const stats = session ? await this.getStats(session) : null;
7254
- if (!stats) {
7283
+ if (!stats || !(sessionId in this.sessionNetworkStats)) {
7255
7284
  return;
7256
7285
  }
7257
7286
 
7287
+ const networkStats = {
7288
+ audioBytesSent: 0,
7289
+ videoBytesSent: 0,
7290
+ videoBytesReceived: 0,
7291
+ audioBytesReceived: 0,
7292
+ };
7293
+ const nbStats = this.sessionNetworkStats[sessionId].length;
7294
+ const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
7295
+ const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
7296
+ const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
7297
+ const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
7298
+ const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
7299
+ const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
7300
+ const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
7301
+ let audioBytesSent = 0;
7302
+ let audioBytesReceived = 0;
7303
+ let videoBytesSent = 0;
7304
+ let videoBytesReceived = 0;
7305
+ let transportSent = 0;
7306
+ let transportReceived = 0;
7307
+ let packetsLost = 0;
7308
+
7258
7309
  stats.forEach(report => {
7259
- if (report.type === 'inbound-rtp') {
7260
- if (report.kind === 'audio') {
7261
- const networkStats = {
7262
- packetsLost: report.packetsLost,
7263
- packetsReceived: report.packetsReceived,
7264
- jitter: report.jitter,
7265
- };
7266
-
7267
- this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7268
- this.sessionNetworkStats[sessionId].push(networkStats);
7310
+ if (report.type === 'outbound-rtp' && report.kind === 'audio') {
7311
+ audioBytesSent += report.bytesSent + report.headerBytesSent;
7312
+ }
7313
+ if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
7314
+ audioBytesSent += report.bytesSent;
7315
+ }
7316
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7317
+ videoBytesSent += report.bytesSent + report.headerBytesSent;
7318
+ }
7319
+ if (report.type === 'inbound-rtp' && report.kind === 'audio') {
7320
+ packetsLost += report.packetsLost;
7321
+ networkStats.packetsReceived = report.packetsReceived;
7322
+ audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
7323
+ }
7324
+ if (report.type === 'inbound-rtp' && report.kind === 'video') {
7325
+ videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
7326
+ }
7327
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7328
+ if ('framesPerSecond' in report) {
7329
+ networkStats.framesPerSecond = report.framesPerSecond;
7269
7330
  }
7331
+ if ('framerateMean' in report) {
7332
+ // framerateMean is only available in FF
7333
+ networkStats.framesPerSecond = Math.round(report.framerateMean);
7334
+ }
7335
+ }
7336
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
7337
+ packetsLost += report.packetsLost;
7338
+ networkStats.roundTripTime = report.roundTripTime;
7339
+ networkStats.jitter = report.jitter;
7340
+ }
7341
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
7342
+ packetsLost += report.packetsLost;
7343
+ }
7344
+ if (report.type === 'transport') {
7345
+ transportSent += report.bytesSent;
7346
+ transportReceived += report.bytesReceived;
7270
7347
  }
7271
7348
  });
7349
+
7350
+ networkStats.packetsLost = packetsLost;
7351
+ networkStats.audioBytesSent = audioBytesSent;
7352
+ networkStats.audioBytesReceived = audioBytesReceived;
7353
+ networkStats.videoBytesSent = videoBytesSent;
7354
+ networkStats.videoBytesReceived = videoBytesReceived;
7355
+ networkStats.transportSent = transportSent;
7356
+ networkStats.transportReceived = transportReceived;
7357
+
7358
+ const bandwidth = (networkStats.audioBytesSent - lastAudioSent) + (networkStats.videoBytesSent - lastVideoSent)
7359
+ + (networkStats.audioBytesReceived - lastAudioReceived) + (networkStats.videoBytesReceived - lastVideoReceived)
7360
+ + (networkStats.transportReceived - lastTransportReceived) + (networkStats.transportSent - lastTransportSent);
7361
+
7362
+ networkStats.bandwidth = bandwidth;
7363
+
7364
+ this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7365
+ this.sessionNetworkStats[sessionId].push(networkStats);
7272
7366
  }
7273
7367
 
7274
7368
  }
@@ -599,7 +599,7 @@ class IssueReporter {
599
599
  payload._retry = retry + 1;
600
600
  }
601
601
 
602
- this._sendDebugToGrafana(body, retry + 1);
602
+ this._sendDebugToGrafana(payload, retry + 1);
603
603
  }, 5000 + retry * 1000);
604
604
  });
605
605
  }
@@ -2791,7 +2791,8 @@ class ExternalApp {
2791
2791
 
2792
2792
 
2793
2793
 
2794
-
2794
+
2795
+
2795
2796
 
2796
2797
 
2797
2798
  class Meeting {
@@ -2803,6 +2804,7 @@ class Meeting {
2803
2804
 
2804
2805
 
2805
2806
 
2807
+
2806
2808
 
2807
2809
 
2808
2810
  static parse(plain ) {
@@ -2814,6 +2816,7 @@ class Meeting {
2814
2816
  port: plain.port,
2815
2817
  uuid: plain.uuid,
2816
2818
  number: plain.number,
2819
+ persistent: plain.persistent,
2817
2820
  });
2818
2821
  }
2819
2822
 
@@ -2821,7 +2824,7 @@ class Meeting {
2821
2824
  return newFrom(meeting, Meeting);
2822
2825
  }
2823
2826
 
2824
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
2827
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
2825
2828
  this.guestSipAuthorization = guestSipAuthorization;
2826
2829
  this.uri = uri;
2827
2830
  this.name = name;
@@ -2829,6 +2832,7 @@ class Meeting {
2829
2832
  this.port = port;
2830
2833
  this.uuid = uuid;
2831
2834
  this.number = number;
2835
+ this.persistent = persistent;
2832
2836
 
2833
2837
  // Useful to compare instead of instanceof with minified code
2834
2838
  this.type = 'Meeting';
@@ -3186,7 +3190,7 @@ class Recording {
3186
3190
 
3187
3191
 
3188
3192
 
3189
- static parseMany(recordings ) {
3193
+ static parseMany(recordings = []) {
3190
3194
  return recordings.map(item => Recording.parse(item));
3191
3195
  }
3192
3196
 
@@ -3312,7 +3316,7 @@ class CallLog {
3312
3316
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3313
3317
  start: moment(plain.start).toDate(),
3314
3318
  end: plain.end ? moment(plain.end).toDate() : null,
3315
- recordings: Recording.parseMany(plain.recordings),
3319
+ recordings: Recording.parseMany(plain.recordings || []),
3316
3320
  });
3317
3321
  }
3318
3322
 
@@ -53,7 +53,7 @@ class Recording {
53
53
 
54
54
 
55
55
 
56
- static parseMany(recordings ) {
56
+ static parseMany(recordings = []) {
57
57
  return recordings.map(item => Recording.parse(item));
58
58
  }
59
59
 
@@ -179,7 +179,7 @@ class CallLog {
179
179
  duration: (plain.duration || 0) * 1000, // duration is in seconds
180
180
  start: moment(plain.start).toDate(),
181
181
  end: plain.end ? moment(plain.end).toDate() : null,
182
- recordings: Recording.parseMany(plain.recordings),
182
+ recordings: Recording.parseMany(plain.recordings || []),
183
183
  });
184
184
  }
185
185