@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
@@ -400,7 +400,7 @@ class IssueReporter {
400
400
  payload._retry = retry + 1;
401
401
  }
402
402
 
403
- this._sendDebugToGrafana(body, retry + 1);
403
+ this._sendDebugToGrafana(payload, retry + 1);
404
404
  }, 5000 + retry * 1000);
405
405
  });
406
406
  }
@@ -2603,7 +2603,8 @@ class ExternalApp {
2603
2603
 
2604
2604
 
2605
2605
 
2606
-
2606
+
2607
+
2607
2608
 
2608
2609
 
2609
2610
  class Meeting {
@@ -2615,6 +2616,7 @@ class Meeting {
2615
2616
 
2616
2617
 
2617
2618
 
2619
+
2618
2620
 
2619
2621
 
2620
2622
  static parse(plain ) {
@@ -2626,6 +2628,7 @@ class Meeting {
2626
2628
  port: plain.port,
2627
2629
  uuid: plain.uuid,
2628
2630
  number: plain.number,
2631
+ persistent: plain.persistent,
2629
2632
  });
2630
2633
  }
2631
2634
 
@@ -2633,7 +2636,7 @@ class Meeting {
2633
2636
  return newFrom(meeting, Meeting);
2634
2637
  }
2635
2638
 
2636
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
2639
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
2637
2640
  this.guestSipAuthorization = guestSipAuthorization;
2638
2641
  this.uri = uri;
2639
2642
  this.name = name;
@@ -2641,6 +2644,7 @@ class Meeting {
2641
2644
  this.port = port;
2642
2645
  this.uuid = uuid;
2643
2646
  this.number = number;
2647
+ this.persistent = persistent;
2644
2648
 
2645
2649
  // Useful to compare instead of instanceof with minified code
2646
2650
  this.type = 'Meeting';
@@ -3230,7 +3234,7 @@ class Recording {
3230
3234
 
3231
3235
 
3232
3236
 
3233
- static parseMany(recordings ) {
3237
+ static parseMany(recordings = []) {
3234
3238
  return recordings.map(item => Recording.parse(item));
3235
3239
  }
3236
3240
 
@@ -3356,7 +3360,7 @@ class CallLog {
3356
3360
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3357
3361
  start: moment(plain.start).toDate(),
3358
3362
  end: plain.end ? moment(plain.end).toDate() : null,
3359
- recordings: Recording.parseMany(plain.recordings),
3363
+ recordings: Recording.parseMany(plain.recordings || []),
3360
3364
  });
3361
3365
  }
3362
3366
 
@@ -5871,6 +5875,7 @@ const ON_REINVITE = 'reinvite';
5871
5875
  const ON_ERROR = 'onError';
5872
5876
  const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
5873
5877
  const ON_NETWORK_STATS = 'onNetworkStats';
5878
+ const ON_DISCONNECTED = 'onDisconnected';
5874
5879
  class CanceledCallError extends Error {}
5875
5880
 
5876
5881
  const MAX_REGISTER_TRIES = 10;
@@ -5944,6 +5949,7 @@ class WebRTCClient extends Emitter {
5944
5949
 
5945
5950
 
5946
5951
 
5952
+
5947
5953
 
5948
5954
  static isAPrivateIp(ip ) {
5949
5955
  const regex = /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/;
@@ -6009,6 +6015,7 @@ class WebRTCClient extends Emitter {
6009
6015
  this.ON_ERROR = ON_ERROR;
6010
6016
  this.ON_SCREEN_SHARING_REINVITE = ON_SCREEN_SHARING_REINVITE;
6011
6017
  this.ON_NETWORK_STATS = ON_NETWORK_STATS;
6018
+ this.ON_DISCONNECTED = ON_DISCONNECTED;
6012
6019
  }
6013
6020
 
6014
6021
  configureMedia(media ) {
@@ -6610,7 +6617,7 @@ class WebRTCClient extends Emitter {
6610
6617
  // We search for the last transceiver without `video-` in the mid (video- means remote transceiver)
6611
6618
  const transceivers = pc.getTransceivers();
6612
6619
  const transceiverIdx = lastIndexOf(transceivers, transceiver =>
6613
- transceiver.sender.track === null && transceiver.mid.indexOf('video') === -1);
6620
+ transceiver.sender.track === null && transceiver.mid && transceiver.mid.indexOf('video') === -1);
6614
6621
 
6615
6622
  videoSender = transceiverIdx !== -1 ? transceivers[transceiverIdx].sender : null;
6616
6623
  } else {
@@ -6856,10 +6863,13 @@ class WebRTCClient extends Emitter {
6856
6863
  return null;
6857
6864
  }
6858
6865
 
6859
- // let's update the local value
6860
- if (this.audio && this.audio.deviceId) {
6861
- // $FlowFixMe
6862
- this.audio.deviceId.exact = id;
6866
+ // let's update the local audio value
6867
+ if (this.audio) {
6868
+ this.audio = {
6869
+ deviceId: {
6870
+ exact: id,
6871
+ },
6872
+ };
6863
6873
  }
6864
6874
 
6865
6875
  if (session) {
@@ -6872,6 +6882,9 @@ class WebRTCClient extends Emitter {
6872
6882
  const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
6873
6883
 
6874
6884
  if (sender) {
6885
+ if (sender.track) {
6886
+ audioTrack.enabled = sender.track.enabled;
6887
+ }
6875
6888
  sender.replaceTrack(audioTrack);
6876
6889
  }
6877
6890
 
@@ -6896,7 +6909,7 @@ class WebRTCClient extends Emitter {
6896
6909
  return null;
6897
6910
  }
6898
6911
 
6899
- // let's update the local value
6912
+ // let's update the local video value
6900
6913
  if (this.video) {
6901
6914
  this.video = {
6902
6915
  deviceId: {
@@ -6931,12 +6944,21 @@ class WebRTCClient extends Emitter {
6931
6944
  return navigator.mediaDevices.getUserMedia(constraints).then(async stream => {
6932
6945
  const videoTrack = stream.getVideoTracks()[0];
6933
6946
  let sender = pc && pc.getSenders().find(s => videoTrack && s && s.track && s.track.kind === videoTrack.kind);
6947
+ let wasTrackEnabled = false;
6934
6948
  if (!sender) {
6935
6949
  sender = pc && pc.getSenders().find(s => !s.track);
6936
6950
  }
6937
6951
 
6938
6952
  if (sender) {
6939
- sender.replaceTrack(videoTrack);
6953
+ // No video track means video not enabled
6954
+ wasTrackEnabled = sender.track ? sender.track.enabled : false;
6955
+ videoTrack.enabled = wasTrackEnabled;
6956
+
6957
+ if (!wasTrackEnabled) {
6958
+ videoTrack.stop();
6959
+ }
6960
+
6961
+ sender.replaceTrack(wasTrackEnabled ? videoTrack : null);
6940
6962
  }
6941
6963
 
6942
6964
  // let's update the local stream
@@ -7620,6 +7642,7 @@ class WebRTCClient extends Emitter {
7620
7642
 
7621
7643
  this.updateRemoteStream(this.getSipSessionId(session));
7622
7644
 
7645
+ const pc = session.sessionDescriptionHandler.peerConnection;
7623
7646
  const onTrack = (event ) => {
7624
7647
  const isAudioOnly = this._isAudioOnly(session);
7625
7648
  const { kind, label, readyState, id, muted } = event.track;
@@ -7639,6 +7662,12 @@ class WebRTCClient extends Emitter {
7639
7662
 
7640
7663
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
7641
7664
 
7665
+ pc.oniceconnectionstatechange = () => {
7666
+ if (pc.iceConnectionState === 'disconnected') {
7667
+ this.eventEmitter.emit(ON_DISCONNECTED);
7668
+ }
7669
+ };
7670
+
7642
7671
  if (withEvent) {
7643
7672
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
7644
7673
  }
@@ -7834,24 +7863,89 @@ class WebRTCClient extends Emitter {
7834
7863
  const session = this.getSipSession(sessionId);
7835
7864
 
7836
7865
  const stats = session ? await this.getStats(session) : null;
7837
- if (!stats) {
7866
+ if (!stats || !(sessionId in this.sessionNetworkStats)) {
7838
7867
  return;
7839
7868
  }
7840
7869
 
7841
- stats.forEach(report => {
7842
- if (report.type === 'inbound-rtp') {
7843
- if (report.kind === 'audio') {
7844
- const networkStats = {
7845
- packetsLost: report.packetsLost,
7846
- packetsReceived: report.packetsReceived,
7847
- jitter: report.jitter,
7848
- };
7870
+ const networkStats = {
7871
+ audioBytesSent: 0,
7872
+ videoBytesSent: 0,
7873
+ videoBytesReceived: 0,
7874
+ audioBytesReceived: 0,
7875
+ };
7876
+ const nbStats = this.sessionNetworkStats[sessionId].length;
7877
+ const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
7878
+ const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
7879
+ const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
7880
+ const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
7881
+ const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
7882
+ const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
7883
+ const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
7884
+ let audioBytesSent = 0;
7885
+ let audioBytesReceived = 0;
7886
+ let videoBytesSent = 0;
7887
+ let videoBytesReceived = 0;
7888
+ let transportSent = 0;
7889
+ let transportReceived = 0;
7890
+ let packetsLost = 0;
7849
7891
 
7850
- this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7851
- this.sessionNetworkStats[sessionId].push(networkStats);
7892
+ stats.forEach(report => {
7893
+ if (report.type === 'outbound-rtp' && report.kind === 'audio') {
7894
+ audioBytesSent += report.bytesSent + report.headerBytesSent;
7895
+ }
7896
+ if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
7897
+ audioBytesSent += report.bytesSent;
7898
+ }
7899
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7900
+ videoBytesSent += report.bytesSent + report.headerBytesSent;
7901
+ }
7902
+ if (report.type === 'inbound-rtp' && report.kind === 'audio') {
7903
+ packetsLost += report.packetsLost;
7904
+ networkStats.packetsReceived = report.packetsReceived;
7905
+ audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
7906
+ }
7907
+ if (report.type === 'inbound-rtp' && report.kind === 'video') {
7908
+ videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
7909
+ }
7910
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7911
+ if ('framesPerSecond' in report) {
7912
+ networkStats.framesPerSecond = report.framesPerSecond;
7852
7913
  }
7914
+ if ('framerateMean' in report) {
7915
+ // framerateMean is only available in FF
7916
+ networkStats.framesPerSecond = Math.round(report.framerateMean);
7917
+ }
7918
+ }
7919
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
7920
+ packetsLost += report.packetsLost;
7921
+ networkStats.roundTripTime = report.roundTripTime;
7922
+ networkStats.jitter = report.jitter;
7923
+ }
7924
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
7925
+ packetsLost += report.packetsLost;
7926
+ }
7927
+ if (report.type === 'transport') {
7928
+ transportSent += report.bytesSent;
7929
+ transportReceived += report.bytesReceived;
7853
7930
  }
7854
7931
  });
7932
+
7933
+ networkStats.packetsLost = packetsLost;
7934
+ networkStats.audioBytesSent = audioBytesSent;
7935
+ networkStats.audioBytesReceived = audioBytesReceived;
7936
+ networkStats.videoBytesSent = videoBytesSent;
7937
+ networkStats.videoBytesReceived = videoBytesReceived;
7938
+ networkStats.transportSent = transportSent;
7939
+ networkStats.transportReceived = transportReceived;
7940
+
7941
+ const bandwidth = (networkStats.audioBytesSent - lastAudioSent) + (networkStats.videoBytesSent - lastVideoSent)
7942
+ + (networkStats.audioBytesReceived - lastAudioReceived) + (networkStats.videoBytesReceived - lastVideoReceived)
7943
+ + (networkStats.transportReceived - lastTransportReceived) + (networkStats.transportSent - lastTransportSent);
7944
+
7945
+ networkStats.bandwidth = bandwidth;
7946
+
7947
+ this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7948
+ this.sessionNetworkStats[sessionId].push(networkStats);
7855
7949
  }
7856
7950
 
7857
7951
  }
@@ -382,7 +382,7 @@ class IssueReporter {
382
382
  payload._retry = retry + 1;
383
383
  }
384
384
 
385
- this._sendDebugToGrafana(body, retry + 1);
385
+ this._sendDebugToGrafana(payload, retry + 1);
386
386
  }, 5000 + retry * 1000);
387
387
  });
388
388
  }
@@ -2585,7 +2585,8 @@ class ExternalApp {
2585
2585
 
2586
2586
 
2587
2587
 
2588
-
2588
+
2589
+
2589
2590
 
2590
2591
 
2591
2592
  class Meeting {
@@ -2597,6 +2598,7 @@ class Meeting {
2597
2598
 
2598
2599
 
2599
2600
 
2601
+
2600
2602
 
2601
2603
 
2602
2604
  static parse(plain ) {
@@ -2608,6 +2610,7 @@ class Meeting {
2608
2610
  port: plain.port,
2609
2611
  uuid: plain.uuid,
2610
2612
  number: plain.number,
2613
+ persistent: plain.persistent,
2611
2614
  });
2612
2615
  }
2613
2616
 
@@ -2615,7 +2618,7 @@ class Meeting {
2615
2618
  return newFrom(meeting, Meeting);
2616
2619
  }
2617
2620
 
2618
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
2621
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
2619
2622
  this.guestSipAuthorization = guestSipAuthorization;
2620
2623
  this.uri = uri;
2621
2624
  this.name = name;
@@ -2623,6 +2626,7 @@ class Meeting {
2623
2626
  this.port = port;
2624
2627
  this.uuid = uuid;
2625
2628
  this.number = number;
2629
+ this.persistent = persistent;
2626
2630
 
2627
2631
  // Useful to compare instead of instanceof with minified code
2628
2632
  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
 
@@ -382,7 +382,7 @@ class IssueReporter {
382
382
  payload._retry = retry + 1;
383
383
  }
384
384
 
385
- this._sendDebugToGrafana(body, retry + 1);
385
+ this._sendDebugToGrafana(payload, retry + 1);
386
386
  }, 5000 + retry * 1000);
387
387
  });
388
388
  }
@@ -2585,7 +2585,8 @@ class ExternalApp {
2585
2585
 
2586
2586
 
2587
2587
 
2588
-
2588
+
2589
+
2589
2590
 
2590
2591
 
2591
2592
  class Meeting {
@@ -2597,6 +2598,7 @@ class Meeting {
2597
2598
 
2598
2599
 
2599
2600
 
2601
+
2600
2602
 
2601
2603
 
2602
2604
  static parse(plain ) {
@@ -2608,6 +2610,7 @@ class Meeting {
2608
2610
  port: plain.port,
2609
2611
  uuid: plain.uuid,
2610
2612
  number: plain.number,
2613
+ persistent: plain.persistent,
2611
2614
  });
2612
2615
  }
2613
2616
 
@@ -2615,7 +2618,7 @@ class Meeting {
2615
2618
  return newFrom(meeting, Meeting);
2616
2619
  }
2617
2620
 
2618
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
2621
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
2619
2622
  this.guestSipAuthorization = guestSipAuthorization;
2620
2623
  this.uri = uri;
2621
2624
  this.name = name;
@@ -2623,6 +2626,7 @@ class Meeting {
2623
2626
  this.port = port;
2624
2627
  this.uuid = uuid;
2625
2628
  this.number = number;
2629
+ this.persistent = persistent;
2626
2630
 
2627
2631
  // Useful to compare instead of instanceof with minified code
2628
2632
  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
 
@@ -400,7 +400,7 @@ class IssueReporter {
400
400
  payload._retry = retry + 1;
401
401
  }
402
402
 
403
- this._sendDebugToGrafana(body, retry + 1);
403
+ this._sendDebugToGrafana(payload, retry + 1);
404
404
  }, 5000 + retry * 1000);
405
405
  });
406
406
  }
@@ -2603,7 +2603,8 @@ class ExternalApp {
2603
2603
 
2604
2604
 
2605
2605
 
2606
-
2606
+
2607
+
2607
2608
 
2608
2609
 
2609
2610
  class Meeting {
@@ -2615,6 +2616,7 @@ class Meeting {
2615
2616
 
2616
2617
 
2617
2618
 
2619
+
2618
2620
 
2619
2621
 
2620
2622
  static parse(plain ) {
@@ -2626,6 +2628,7 @@ class Meeting {
2626
2628
  port: plain.port,
2627
2629
  uuid: plain.uuid,
2628
2630
  number: plain.number,
2631
+ persistent: plain.persistent,
2629
2632
  });
2630
2633
  }
2631
2634
 
@@ -2633,7 +2636,7 @@ class Meeting {
2633
2636
  return newFrom(meeting, Meeting);
2634
2637
  }
2635
2638
 
2636
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
2639
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
2637
2640
  this.guestSipAuthorization = guestSipAuthorization;
2638
2641
  this.uri = uri;
2639
2642
  this.name = name;
@@ -2641,6 +2644,7 @@ class Meeting {
2641
2644
  this.port = port;
2642
2645
  this.uuid = uuid;
2643
2646
  this.number = number;
2647
+ this.persistent = persistent;
2644
2648
 
2645
2649
  // Useful to compare instead of instanceof with minified code
2646
2650
  this.type = 'Meeting';
@@ -3230,7 +3234,7 @@ class Recording {
3230
3234
 
3231
3235
 
3232
3236
 
3233
- static parseMany(recordings ) {
3237
+ static parseMany(recordings = []) {
3234
3238
  return recordings.map(item => Recording.parse(item));
3235
3239
  }
3236
3240
 
@@ -3356,7 +3360,7 @@ class CallLog {
3356
3360
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3357
3361
  start: moment(plain.start).toDate(),
3358
3362
  end: plain.end ? moment(plain.end).toDate() : null,
3359
- recordings: Recording.parseMany(plain.recordings),
3363
+ recordings: Recording.parseMany(plain.recordings || []),
3360
3364
  });
3361
3365
  }
3362
3366
 
@@ -5871,6 +5875,7 @@ const ON_REINVITE = 'reinvite';
5871
5875
  const ON_ERROR = 'onError';
5872
5876
  const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
5873
5877
  const ON_NETWORK_STATS = 'onNetworkStats';
5878
+ const ON_DISCONNECTED = 'onDisconnected';
5874
5879
  class CanceledCallError extends Error {}
5875
5880
 
5876
5881
  const MAX_REGISTER_TRIES = 10;
@@ -5944,6 +5949,7 @@ class WebRTCClient extends Emitter {
5944
5949
 
5945
5950
 
5946
5951
 
5952
+
5947
5953
 
5948
5954
  static isAPrivateIp(ip ) {
5949
5955
  const regex = /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/;
@@ -6009,6 +6015,7 @@ class WebRTCClient extends Emitter {
6009
6015
  this.ON_ERROR = ON_ERROR;
6010
6016
  this.ON_SCREEN_SHARING_REINVITE = ON_SCREEN_SHARING_REINVITE;
6011
6017
  this.ON_NETWORK_STATS = ON_NETWORK_STATS;
6018
+ this.ON_DISCONNECTED = ON_DISCONNECTED;
6012
6019
  }
6013
6020
 
6014
6021
  configureMedia(media ) {
@@ -6610,7 +6617,7 @@ class WebRTCClient extends Emitter {
6610
6617
  // We search for the last transceiver without `video-` in the mid (video- means remote transceiver)
6611
6618
  const transceivers = pc.getTransceivers();
6612
6619
  const transceiverIdx = lastIndexOf(transceivers, transceiver =>
6613
- transceiver.sender.track === null && transceiver.mid.indexOf('video') === -1);
6620
+ transceiver.sender.track === null && transceiver.mid && transceiver.mid.indexOf('video') === -1);
6614
6621
 
6615
6622
  videoSender = transceiverIdx !== -1 ? transceivers[transceiverIdx].sender : null;
6616
6623
  } else {
@@ -6856,10 +6863,13 @@ class WebRTCClient extends Emitter {
6856
6863
  return null;
6857
6864
  }
6858
6865
 
6859
- // let's update the local value
6860
- if (this.audio && this.audio.deviceId) {
6861
- // $FlowFixMe
6862
- this.audio.deviceId.exact = id;
6866
+ // let's update the local audio value
6867
+ if (this.audio) {
6868
+ this.audio = {
6869
+ deviceId: {
6870
+ exact: id,
6871
+ },
6872
+ };
6863
6873
  }
6864
6874
 
6865
6875
  if (session) {
@@ -6872,6 +6882,9 @@ class WebRTCClient extends Emitter {
6872
6882
  const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
6873
6883
 
6874
6884
  if (sender) {
6885
+ if (sender.track) {
6886
+ audioTrack.enabled = sender.track.enabled;
6887
+ }
6875
6888
  sender.replaceTrack(audioTrack);
6876
6889
  }
6877
6890
 
@@ -6896,7 +6909,7 @@ class WebRTCClient extends Emitter {
6896
6909
  return null;
6897
6910
  }
6898
6911
 
6899
- // let's update the local value
6912
+ // let's update the local video value
6900
6913
  if (this.video) {
6901
6914
  this.video = {
6902
6915
  deviceId: {
@@ -6931,12 +6944,21 @@ class WebRTCClient extends Emitter {
6931
6944
  return navigator.mediaDevices.getUserMedia(constraints).then(async stream => {
6932
6945
  const videoTrack = stream.getVideoTracks()[0];
6933
6946
  let sender = pc && pc.getSenders().find(s => videoTrack && s && s.track && s.track.kind === videoTrack.kind);
6947
+ let wasTrackEnabled = false;
6934
6948
  if (!sender) {
6935
6949
  sender = pc && pc.getSenders().find(s => !s.track);
6936
6950
  }
6937
6951
 
6938
6952
  if (sender) {
6939
- sender.replaceTrack(videoTrack);
6953
+ // No video track means video not enabled
6954
+ wasTrackEnabled = sender.track ? sender.track.enabled : false;
6955
+ videoTrack.enabled = wasTrackEnabled;
6956
+
6957
+ if (!wasTrackEnabled) {
6958
+ videoTrack.stop();
6959
+ }
6960
+
6961
+ sender.replaceTrack(wasTrackEnabled ? videoTrack : null);
6940
6962
  }
6941
6963
 
6942
6964
  // let's update the local stream
@@ -7620,6 +7642,7 @@ class WebRTCClient extends Emitter {
7620
7642
 
7621
7643
  this.updateRemoteStream(this.getSipSessionId(session));
7622
7644
 
7645
+ const pc = session.sessionDescriptionHandler.peerConnection;
7623
7646
  const onTrack = (event ) => {
7624
7647
  const isAudioOnly = this._isAudioOnly(session);
7625
7648
  const { kind, label, readyState, id, muted } = event.track;
@@ -7639,6 +7662,12 @@ class WebRTCClient extends Emitter {
7639
7662
 
7640
7663
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
7641
7664
 
7665
+ pc.oniceconnectionstatechange = () => {
7666
+ if (pc.iceConnectionState === 'disconnected') {
7667
+ this.eventEmitter.emit(ON_DISCONNECTED);
7668
+ }
7669
+ };
7670
+
7642
7671
  if (withEvent) {
7643
7672
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
7644
7673
  }
@@ -7834,24 +7863,89 @@ class WebRTCClient extends Emitter {
7834
7863
  const session = this.getSipSession(sessionId);
7835
7864
 
7836
7865
  const stats = session ? await this.getStats(session) : null;
7837
- if (!stats) {
7866
+ if (!stats || !(sessionId in this.sessionNetworkStats)) {
7838
7867
  return;
7839
7868
  }
7840
7869
 
7841
- stats.forEach(report => {
7842
- if (report.type === 'inbound-rtp') {
7843
- if (report.kind === 'audio') {
7844
- const networkStats = {
7845
- packetsLost: report.packetsLost,
7846
- packetsReceived: report.packetsReceived,
7847
- jitter: report.jitter,
7848
- };
7870
+ const networkStats = {
7871
+ audioBytesSent: 0,
7872
+ videoBytesSent: 0,
7873
+ videoBytesReceived: 0,
7874
+ audioBytesReceived: 0,
7875
+ };
7876
+ const nbStats = this.sessionNetworkStats[sessionId].length;
7877
+ const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
7878
+ const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
7879
+ const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
7880
+ const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
7881
+ const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
7882
+ const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
7883
+ const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
7884
+ let audioBytesSent = 0;
7885
+ let audioBytesReceived = 0;
7886
+ let videoBytesSent = 0;
7887
+ let videoBytesReceived = 0;
7888
+ let transportSent = 0;
7889
+ let transportReceived = 0;
7890
+ let packetsLost = 0;
7849
7891
 
7850
- this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7851
- this.sessionNetworkStats[sessionId].push(networkStats);
7892
+ stats.forEach(report => {
7893
+ if (report.type === 'outbound-rtp' && report.kind === 'audio') {
7894
+ audioBytesSent += report.bytesSent + report.headerBytesSent;
7895
+ }
7896
+ if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
7897
+ audioBytesSent += report.bytesSent;
7898
+ }
7899
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7900
+ videoBytesSent += report.bytesSent + report.headerBytesSent;
7901
+ }
7902
+ if (report.type === 'inbound-rtp' && report.kind === 'audio') {
7903
+ packetsLost += report.packetsLost;
7904
+ networkStats.packetsReceived = report.packetsReceived;
7905
+ audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
7906
+ }
7907
+ if (report.type === 'inbound-rtp' && report.kind === 'video') {
7908
+ videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
7909
+ }
7910
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7911
+ if ('framesPerSecond' in report) {
7912
+ networkStats.framesPerSecond = report.framesPerSecond;
7852
7913
  }
7914
+ if ('framerateMean' in report) {
7915
+ // framerateMean is only available in FF
7916
+ networkStats.framesPerSecond = Math.round(report.framerateMean);
7917
+ }
7918
+ }
7919
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
7920
+ packetsLost += report.packetsLost;
7921
+ networkStats.roundTripTime = report.roundTripTime;
7922
+ networkStats.jitter = report.jitter;
7923
+ }
7924
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
7925
+ packetsLost += report.packetsLost;
7926
+ }
7927
+ if (report.type === 'transport') {
7928
+ transportSent += report.bytesSent;
7929
+ transportReceived += report.bytesReceived;
7853
7930
  }
7854
7931
  });
7932
+
7933
+ networkStats.packetsLost = packetsLost;
7934
+ networkStats.audioBytesSent = audioBytesSent;
7935
+ networkStats.audioBytesReceived = audioBytesReceived;
7936
+ networkStats.videoBytesSent = videoBytesSent;
7937
+ networkStats.videoBytesReceived = videoBytesReceived;
7938
+ networkStats.transportSent = transportSent;
7939
+ networkStats.transportReceived = transportReceived;
7940
+
7941
+ const bandwidth = (networkStats.audioBytesSent - lastAudioSent) + (networkStats.videoBytesSent - lastVideoSent)
7942
+ + (networkStats.audioBytesReceived - lastAudioReceived) + (networkStats.videoBytesReceived - lastVideoReceived)
7943
+ + (networkStats.transportReceived - lastTransportReceived) + (networkStats.transportSent - lastTransportSent);
7944
+
7945
+ networkStats.bandwidth = bandwidth;
7946
+
7947
+ this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7948
+ this.sessionNetworkStats[sessionId].push(networkStats);
7855
7949
  }
7856
7950
 
7857
7951
  }