@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
@@ -1898,7 +1898,7 @@ class IssueReporter {
1898
1898
  payload._retry = retry + 1;
1899
1899
  }
1900
1900
 
1901
- this._sendDebugToGrafana(body, retry + 1);
1901
+ this._sendDebugToGrafana(payload, retry + 1);
1902
1902
  }, 5000 + retry * 1000);
1903
1903
  });
1904
1904
  }
@@ -2616,7 +2616,8 @@ class ExternalApp {
2616
2616
 
2617
2617
 
2618
2618
 
2619
-
2619
+
2620
+
2620
2621
 
2621
2622
 
2622
2623
  class Meeting {
@@ -2628,6 +2629,7 @@ class Meeting {
2628
2629
 
2629
2630
 
2630
2631
 
2632
+
2631
2633
 
2632
2634
 
2633
2635
  static parse(plain ) {
@@ -2639,6 +2641,7 @@ class Meeting {
2639
2641
  port: plain.port,
2640
2642
  uuid: plain.uuid,
2641
2643
  number: plain.number,
2644
+ persistent: plain.persistent,
2642
2645
  });
2643
2646
  }
2644
2647
 
@@ -2646,7 +2649,7 @@ class Meeting {
2646
2649
  return newFrom(meeting, Meeting);
2647
2650
  }
2648
2651
 
2649
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
2652
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
2650
2653
  this.guestSipAuthorization = guestSipAuthorization;
2651
2654
  this.uri = uri;
2652
2655
  this.name = name;
@@ -2654,6 +2657,7 @@ class Meeting {
2654
2657
  this.port = port;
2655
2658
  this.uuid = uuid;
2656
2659
  this.number = number;
2660
+ this.persistent = persistent;
2657
2661
 
2658
2662
  // Useful to compare instead of instanceof with minified code
2659
2663
  this.type = 'Meeting';
@@ -3588,7 +3592,7 @@ class Recording {
3588
3592
 
3589
3593
 
3590
3594
 
3591
- static parseMany(recordings ) {
3595
+ static parseMany(recordings = []) {
3592
3596
  return recordings.map(item => Recording.parse(item));
3593
3597
  }
3594
3598
 
@@ -3714,7 +3718,7 @@ class CallLog {
3714
3718
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3715
3719
  start: moment__default['default'](plain.start).toDate(),
3716
3720
  end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3717
- recordings: Recording.parseMany(plain.recordings),
3721
+ recordings: Recording.parseMany(plain.recordings || []),
3718
3722
  });
3719
3723
  }
3720
3724
 
@@ -6559,6 +6563,7 @@ const ON_REINVITE$1 = 'reinvite';
6559
6563
  const ON_ERROR = 'onError';
6560
6564
  const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
6561
6565
  const ON_NETWORK_STATS$1 = 'onNetworkStats';
6566
+ const ON_DISCONNECTED$1 = 'onDisconnected';
6562
6567
 
6563
6568
  const events$1 = [REGISTERED, UNREGISTERED, REGISTRATION_FAILED, INVITE];
6564
6569
  const transportEvents = [CONNECTED, DISCONNECTED, TRANSPORT_ERROR, MESSAGE];
@@ -6635,6 +6640,7 @@ class WebRTCClient extends Emitter {
6635
6640
 
6636
6641
 
6637
6642
 
6643
+
6638
6644
 
6639
6645
  static isAPrivateIp(ip ) {
6640
6646
  const regex = /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/;
@@ -6700,6 +6706,7 @@ class WebRTCClient extends Emitter {
6700
6706
  this.ON_ERROR = ON_ERROR;
6701
6707
  this.ON_SCREEN_SHARING_REINVITE = ON_SCREEN_SHARING_REINVITE;
6702
6708
  this.ON_NETWORK_STATS = ON_NETWORK_STATS$1;
6709
+ this.ON_DISCONNECTED = ON_DISCONNECTED$1;
6703
6710
  }
6704
6711
 
6705
6712
  configureMedia(media ) {
@@ -7301,7 +7308,7 @@ class WebRTCClient extends Emitter {
7301
7308
  // We search for the last transceiver without `video-` in the mid (video- means remote transceiver)
7302
7309
  const transceivers = pc.getTransceivers();
7303
7310
  const transceiverIdx = lastIndexOf(transceivers, transceiver =>
7304
- transceiver.sender.track === null && transceiver.mid.indexOf('video') === -1);
7311
+ transceiver.sender.track === null && transceiver.mid && transceiver.mid.indexOf('video') === -1);
7305
7312
 
7306
7313
  videoSender = transceiverIdx !== -1 ? transceivers[transceiverIdx].sender : null;
7307
7314
  } else {
@@ -7547,10 +7554,13 @@ class WebRTCClient extends Emitter {
7547
7554
  return null;
7548
7555
  }
7549
7556
 
7550
- // let's update the local value
7551
- if (this.audio && this.audio.deviceId) {
7552
- // $FlowFixMe
7553
- this.audio.deviceId.exact = id;
7557
+ // let's update the local audio value
7558
+ if (this.audio) {
7559
+ this.audio = {
7560
+ deviceId: {
7561
+ exact: id,
7562
+ },
7563
+ };
7554
7564
  }
7555
7565
 
7556
7566
  if (session) {
@@ -7563,6 +7573,9 @@ class WebRTCClient extends Emitter {
7563
7573
  const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
7564
7574
 
7565
7575
  if (sender) {
7576
+ if (sender.track) {
7577
+ audioTrack.enabled = sender.track.enabled;
7578
+ }
7566
7579
  sender.replaceTrack(audioTrack);
7567
7580
  }
7568
7581
 
@@ -7587,7 +7600,7 @@ class WebRTCClient extends Emitter {
7587
7600
  return null;
7588
7601
  }
7589
7602
 
7590
- // let's update the local value
7603
+ // let's update the local video value
7591
7604
  if (this.video) {
7592
7605
  this.video = {
7593
7606
  deviceId: {
@@ -7622,12 +7635,21 @@ class WebRTCClient extends Emitter {
7622
7635
  return navigator.mediaDevices.getUserMedia(constraints).then(async stream => {
7623
7636
  const videoTrack = stream.getVideoTracks()[0];
7624
7637
  let sender = pc && pc.getSenders().find(s => videoTrack && s && s.track && s.track.kind === videoTrack.kind);
7638
+ let wasTrackEnabled = false;
7625
7639
  if (!sender) {
7626
7640
  sender = pc && pc.getSenders().find(s => !s.track);
7627
7641
  }
7628
7642
 
7629
7643
  if (sender) {
7630
- sender.replaceTrack(videoTrack);
7644
+ // No video track means video not enabled
7645
+ wasTrackEnabled = sender.track ? sender.track.enabled : false;
7646
+ videoTrack.enabled = wasTrackEnabled;
7647
+
7648
+ if (!wasTrackEnabled) {
7649
+ videoTrack.stop();
7650
+ }
7651
+
7652
+ sender.replaceTrack(wasTrackEnabled ? videoTrack : null);
7631
7653
  }
7632
7654
 
7633
7655
  // let's update the local stream
@@ -8311,6 +8333,7 @@ class WebRTCClient extends Emitter {
8311
8333
 
8312
8334
  this.updateRemoteStream(this.getSipSessionId(session));
8313
8335
 
8336
+ const pc = session.sessionDescriptionHandler.peerConnection;
8314
8337
  const onTrack = (event ) => {
8315
8338
  const isAudioOnly = this._isAudioOnly(session);
8316
8339
  const { kind, label, readyState, id, muted } = event.track;
@@ -8330,6 +8353,12 @@ class WebRTCClient extends Emitter {
8330
8353
 
8331
8354
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
8332
8355
 
8356
+ pc.oniceconnectionstatechange = () => {
8357
+ if (pc.iceConnectionState === 'disconnected') {
8358
+ this.eventEmitter.emit(ON_DISCONNECTED$1);
8359
+ }
8360
+ };
8361
+
8333
8362
  if (withEvent) {
8334
8363
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
8335
8364
  }
@@ -8525,24 +8554,89 @@ class WebRTCClient extends Emitter {
8525
8554
  const session = this.getSipSession(sessionId);
8526
8555
 
8527
8556
  const stats = session ? await this.getStats(session) : null;
8528
- if (!stats) {
8557
+ if (!stats || !(sessionId in this.sessionNetworkStats)) {
8529
8558
  return;
8530
8559
  }
8531
8560
 
8532
- stats.forEach(report => {
8533
- if (report.type === 'inbound-rtp') {
8534
- if (report.kind === 'audio') {
8535
- const networkStats = {
8536
- packetsLost: report.packetsLost,
8537
- packetsReceived: report.packetsReceived,
8538
- jitter: report.jitter,
8539
- };
8561
+ const networkStats = {
8562
+ audioBytesSent: 0,
8563
+ videoBytesSent: 0,
8564
+ videoBytesReceived: 0,
8565
+ audioBytesReceived: 0,
8566
+ };
8567
+ const nbStats = this.sessionNetworkStats[sessionId].length;
8568
+ const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
8569
+ const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
8570
+ const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
8571
+ const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
8572
+ const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
8573
+ const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
8574
+ const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
8575
+ let audioBytesSent = 0;
8576
+ let audioBytesReceived = 0;
8577
+ let videoBytesSent = 0;
8578
+ let videoBytesReceived = 0;
8579
+ let transportSent = 0;
8580
+ let transportReceived = 0;
8581
+ let packetsLost = 0;
8540
8582
 
8541
- this.eventEmitter.emit(ON_NETWORK_STATS$1, session, networkStats, this.sessionNetworkStats[sessionId]);
8542
- this.sessionNetworkStats[sessionId].push(networkStats);
8583
+ stats.forEach(report => {
8584
+ if (report.type === 'outbound-rtp' && report.kind === 'audio') {
8585
+ audioBytesSent += report.bytesSent + report.headerBytesSent;
8586
+ }
8587
+ if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
8588
+ audioBytesSent += report.bytesSent;
8589
+ }
8590
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
8591
+ videoBytesSent += report.bytesSent + report.headerBytesSent;
8592
+ }
8593
+ if (report.type === 'inbound-rtp' && report.kind === 'audio') {
8594
+ packetsLost += report.packetsLost;
8595
+ networkStats.packetsReceived = report.packetsReceived;
8596
+ audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
8597
+ }
8598
+ if (report.type === 'inbound-rtp' && report.kind === 'video') {
8599
+ videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
8600
+ }
8601
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
8602
+ if ('framesPerSecond' in report) {
8603
+ networkStats.framesPerSecond = report.framesPerSecond;
8604
+ }
8605
+ if ('framerateMean' in report) {
8606
+ // framerateMean is only available in FF
8607
+ networkStats.framesPerSecond = Math.round(report.framerateMean);
8543
8608
  }
8544
8609
  }
8610
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
8611
+ packetsLost += report.packetsLost;
8612
+ networkStats.roundTripTime = report.roundTripTime;
8613
+ networkStats.jitter = report.jitter;
8614
+ }
8615
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
8616
+ packetsLost += report.packetsLost;
8617
+ }
8618
+ if (report.type === 'transport') {
8619
+ transportSent += report.bytesSent;
8620
+ transportReceived += report.bytesReceived;
8621
+ }
8545
8622
  });
8623
+
8624
+ networkStats.packetsLost = packetsLost;
8625
+ networkStats.audioBytesSent = audioBytesSent;
8626
+ networkStats.audioBytesReceived = audioBytesReceived;
8627
+ networkStats.videoBytesSent = videoBytesSent;
8628
+ networkStats.videoBytesReceived = videoBytesReceived;
8629
+ networkStats.transportSent = transportSent;
8630
+ networkStats.transportReceived = transportReceived;
8631
+
8632
+ const bandwidth = (networkStats.audioBytesSent - lastAudioSent) + (networkStats.videoBytesSent - lastVideoSent)
8633
+ + (networkStats.audioBytesReceived - lastAudioReceived) + (networkStats.videoBytesReceived - lastVideoReceived)
8634
+ + (networkStats.transportReceived - lastTransportReceived) + (networkStats.transportSent - lastTransportSent);
8635
+
8636
+ networkStats.bandwidth = bandwidth;
8637
+
8638
+ this.eventEmitter.emit(ON_NETWORK_STATS$1, session, networkStats, this.sessionNetworkStats[sessionId]);
8639
+ this.sessionNetworkStats[sessionId].push(networkStats);
8546
8640
  }
8547
8641
 
8548
8642
  }
@@ -8588,6 +8682,7 @@ const ON_MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
8588
8682
  const ON_NETWORK_STATS = 'onNetworkStats';
8589
8683
  const ON_CHAT = 'phone/ON_CHAT';
8590
8684
  const ON_SIGNAL = 'phone/ON_SIGNAL';
8685
+ const ON_DISCONNECTED = 'onDisconnected';
8591
8686
 
8592
8687
  const MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
8593
8688
  const MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
@@ -8627,6 +8722,7 @@ const events = [
8627
8722
  ON_CHAT,
8628
8723
  ON_SIGNAL,
8629
8724
  ON_NETWORK_STATS,
8725
+ ON_DISCONNECTED,
8630
8726
  ];
8631
8727
 
8632
8728
  const logger$7 = IssueReporter$1.loggerFor('webrtc-phone');
@@ -9979,6 +10075,11 @@ class WebRTCPhone extends Emitter {
9979
10075
  this.eventEmitter.emit(ON_UNREGISTERED);
9980
10076
  });
9981
10077
 
10078
+ this.client.on(this.client.ON_DISCONNECTED, () => {
10079
+ logger$7.info('WebRTC disconnected');
10080
+ this.eventEmitter.emit(ON_DISCONNECTED);
10081
+ });
10082
+
9982
10083
  this.client.on(this.client.REGISTERED, () => {
9983
10084
  logger$7.info('WebRTC registered', {
9984
10085
  shouldSendReinvite: this.shouldSendReinvite,
@@ -10235,6 +10336,7 @@ var PHONE_EVENTS = /*#__PURE__*/Object.freeze({
10235
10336
  ON_NETWORK_STATS: ON_NETWORK_STATS,
10236
10337
  ON_CHAT: ON_CHAT,
10237
10338
  ON_SIGNAL: ON_SIGNAL,
10339
+ ON_DISCONNECTED: ON_DISCONNECTED,
10238
10340
  MESSAGE_TYPE_CHAT: MESSAGE_TYPE_CHAT,
10239
10341
  MESSAGE_TYPE_SIGNAL: MESSAGE_TYPE_SIGNAL,
10240
10342
  events: events,
@@ -384,7 +384,7 @@ class IssueReporter {
384
384
  payload._retry = retry + 1;
385
385
  }
386
386
 
387
- this._sendDebugToGrafana(body, retry + 1);
387
+ this._sendDebugToGrafana(payload, retry + 1);
388
388
  }, 5000 + retry * 1000);
389
389
  });
390
390
  }
@@ -386,7 +386,7 @@ class IssueReporter {
386
386
  payload._retry = retry + 1;
387
387
  }
388
388
 
389
- this._sendDebugToGrafana(body, retry + 1);
389
+ this._sendDebugToGrafana(payload, retry + 1);
390
390
  }, 5000 + retry * 1000);
391
391
  });
392
392
  }
@@ -675,7 +675,7 @@ class IssueReporter {
675
675
  payload._retry = retry + 1;
676
676
  }
677
677
 
678
- this._sendDebugToGrafana(body, retry + 1);
678
+ this._sendDebugToGrafana(payload, retry + 1);
679
679
  }, 5000 + retry * 1000);
680
680
  });
681
681
  }
@@ -3177,7 +3177,8 @@ class ExternalApp {
3177
3177
 
3178
3178
 
3179
3179
 
3180
-
3180
+
3181
+
3181
3182
 
3182
3183
 
3183
3184
  class Meeting {
@@ -3189,6 +3190,7 @@ class Meeting {
3189
3190
 
3190
3191
 
3191
3192
 
3193
+
3192
3194
 
3193
3195
 
3194
3196
  static parse(plain ) {
@@ -3200,6 +3202,7 @@ class Meeting {
3200
3202
  port: plain.port,
3201
3203
  uuid: plain.uuid,
3202
3204
  number: plain.number,
3205
+ persistent: plain.persistent,
3203
3206
  });
3204
3207
  }
3205
3208
 
@@ -3207,7 +3210,7 @@ class Meeting {
3207
3210
  return newFrom(meeting, Meeting);
3208
3211
  }
3209
3212
 
3210
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number } = {}) {
3213
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent } = {}) {
3211
3214
  this.guestSipAuthorization = guestSipAuthorization;
3212
3215
  this.uri = uri;
3213
3216
  this.name = name;
@@ -3215,6 +3218,7 @@ class Meeting {
3215
3218
  this.port = port;
3216
3219
  this.uuid = uuid;
3217
3220
  this.number = number;
3221
+ this.persistent = persistent;
3218
3222
 
3219
3223
  // Useful to compare instead of instanceof with minified code
3220
3224
  this.type = 'Meeting';
@@ -3778,7 +3782,7 @@ class Recording {
3778
3782
 
3779
3783
 
3780
3784
 
3781
- static parseMany(recordings ) {
3785
+ static parseMany(recordings = []) {
3782
3786
  return recordings.map(item => Recording.parse(item));
3783
3787
  }
3784
3788
 
@@ -3904,7 +3908,7 @@ class CallLog {
3904
3908
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3905
3909
  start: moment__default['default'](plain.start).toDate(),
3906
3910
  end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3907
- recordings: Recording.parseMany(plain.recordings),
3911
+ recordings: Recording.parseMany(plain.recordings || []),
3908
3912
  });
3909
3913
  }
3910
3914
 
@@ -5299,6 +5303,7 @@ const ON_REINVITE = 'reinvite';
5299
5303
  const ON_ERROR = 'onError';
5300
5304
  const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
5301
5305
  const ON_NETWORK_STATS = 'onNetworkStats';
5306
+ const ON_DISCONNECTED = 'onDisconnected';
5302
5307
 
5303
5308
  const events = [REGISTERED, UNREGISTERED, REGISTRATION_FAILED, INVITE];
5304
5309
  const transportEvents = [CONNECTED, DISCONNECTED, TRANSPORT_ERROR, MESSAGE];
@@ -5375,6 +5380,7 @@ class WebRTCClient extends Emitter {
5375
5380
 
5376
5381
 
5377
5382
 
5383
+
5378
5384
 
5379
5385
  static isAPrivateIp(ip ) {
5380
5386
  const regex = /^(?:10|127|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\..*/;
@@ -5440,6 +5446,7 @@ class WebRTCClient extends Emitter {
5440
5446
  this.ON_ERROR = ON_ERROR;
5441
5447
  this.ON_SCREEN_SHARING_REINVITE = ON_SCREEN_SHARING_REINVITE;
5442
5448
  this.ON_NETWORK_STATS = ON_NETWORK_STATS;
5449
+ this.ON_DISCONNECTED = ON_DISCONNECTED;
5443
5450
  }
5444
5451
 
5445
5452
  configureMedia(media ) {
@@ -6041,7 +6048,7 @@ class WebRTCClient extends Emitter {
6041
6048
  // We search for the last transceiver without `video-` in the mid (video- means remote transceiver)
6042
6049
  const transceivers = pc.getTransceivers();
6043
6050
  const transceiverIdx = lastIndexOf(transceivers, transceiver =>
6044
- transceiver.sender.track === null && transceiver.mid.indexOf('video') === -1);
6051
+ transceiver.sender.track === null && transceiver.mid && transceiver.mid.indexOf('video') === -1);
6045
6052
 
6046
6053
  videoSender = transceiverIdx !== -1 ? transceivers[transceiverIdx].sender : null;
6047
6054
  } else {
@@ -6287,10 +6294,13 @@ class WebRTCClient extends Emitter {
6287
6294
  return null;
6288
6295
  }
6289
6296
 
6290
- // let's update the local value
6291
- if (this.audio && this.audio.deviceId) {
6292
- // $FlowFixMe
6293
- this.audio.deviceId.exact = id;
6297
+ // let's update the local audio value
6298
+ if (this.audio) {
6299
+ this.audio = {
6300
+ deviceId: {
6301
+ exact: id,
6302
+ },
6303
+ };
6294
6304
  }
6295
6305
 
6296
6306
  if (session) {
@@ -6303,6 +6313,9 @@ class WebRTCClient extends Emitter {
6303
6313
  const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
6304
6314
 
6305
6315
  if (sender) {
6316
+ if (sender.track) {
6317
+ audioTrack.enabled = sender.track.enabled;
6318
+ }
6306
6319
  sender.replaceTrack(audioTrack);
6307
6320
  }
6308
6321
 
@@ -6327,7 +6340,7 @@ class WebRTCClient extends Emitter {
6327
6340
  return null;
6328
6341
  }
6329
6342
 
6330
- // let's update the local value
6343
+ // let's update the local video value
6331
6344
  if (this.video) {
6332
6345
  this.video = {
6333
6346
  deviceId: {
@@ -6362,12 +6375,21 @@ class WebRTCClient extends Emitter {
6362
6375
  return navigator.mediaDevices.getUserMedia(constraints).then(async stream => {
6363
6376
  const videoTrack = stream.getVideoTracks()[0];
6364
6377
  let sender = pc && pc.getSenders().find(s => videoTrack && s && s.track && s.track.kind === videoTrack.kind);
6378
+ let wasTrackEnabled = false;
6365
6379
  if (!sender) {
6366
6380
  sender = pc && pc.getSenders().find(s => !s.track);
6367
6381
  }
6368
6382
 
6369
6383
  if (sender) {
6370
- sender.replaceTrack(videoTrack);
6384
+ // No video track means video not enabled
6385
+ wasTrackEnabled = sender.track ? sender.track.enabled : false;
6386
+ videoTrack.enabled = wasTrackEnabled;
6387
+
6388
+ if (!wasTrackEnabled) {
6389
+ videoTrack.stop();
6390
+ }
6391
+
6392
+ sender.replaceTrack(wasTrackEnabled ? videoTrack : null);
6371
6393
  }
6372
6394
 
6373
6395
  // let's update the local stream
@@ -7051,6 +7073,7 @@ class WebRTCClient extends Emitter {
7051
7073
 
7052
7074
  this.updateRemoteStream(this.getSipSessionId(session));
7053
7075
 
7076
+ const pc = session.sessionDescriptionHandler.peerConnection;
7054
7077
  const onTrack = (event ) => {
7055
7078
  const isAudioOnly = this._isAudioOnly(session);
7056
7079
  const { kind, label, readyState, id, muted } = event.track;
@@ -7070,6 +7093,12 @@ class WebRTCClient extends Emitter {
7070
7093
 
7071
7094
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
7072
7095
 
7096
+ pc.oniceconnectionstatechange = () => {
7097
+ if (pc.iceConnectionState === 'disconnected') {
7098
+ this.eventEmitter.emit(ON_DISCONNECTED);
7099
+ }
7100
+ };
7101
+
7073
7102
  if (withEvent) {
7074
7103
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
7075
7104
  }
@@ -7265,24 +7294,89 @@ class WebRTCClient extends Emitter {
7265
7294
  const session = this.getSipSession(sessionId);
7266
7295
 
7267
7296
  const stats = session ? await this.getStats(session) : null;
7268
- if (!stats) {
7297
+ if (!stats || !(sessionId in this.sessionNetworkStats)) {
7269
7298
  return;
7270
7299
  }
7271
7300
 
7301
+ const networkStats = {
7302
+ audioBytesSent: 0,
7303
+ videoBytesSent: 0,
7304
+ videoBytesReceived: 0,
7305
+ audioBytesReceived: 0,
7306
+ };
7307
+ const nbStats = this.sessionNetworkStats[sessionId].length;
7308
+ const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
7309
+ const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
7310
+ const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
7311
+ const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
7312
+ const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
7313
+ const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
7314
+ const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
7315
+ let audioBytesSent = 0;
7316
+ let audioBytesReceived = 0;
7317
+ let videoBytesSent = 0;
7318
+ let videoBytesReceived = 0;
7319
+ let transportSent = 0;
7320
+ let transportReceived = 0;
7321
+ let packetsLost = 0;
7322
+
7272
7323
  stats.forEach(report => {
7273
- if (report.type === 'inbound-rtp') {
7274
- if (report.kind === 'audio') {
7275
- const networkStats = {
7276
- packetsLost: report.packetsLost,
7277
- packetsReceived: report.packetsReceived,
7278
- jitter: report.jitter,
7279
- };
7280
-
7281
- this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7282
- this.sessionNetworkStats[sessionId].push(networkStats);
7324
+ if (report.type === 'outbound-rtp' && report.kind === 'audio') {
7325
+ audioBytesSent += report.bytesSent + report.headerBytesSent;
7326
+ }
7327
+ if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
7328
+ audioBytesSent += report.bytesSent;
7329
+ }
7330
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7331
+ videoBytesSent += report.bytesSent + report.headerBytesSent;
7332
+ }
7333
+ if (report.type === 'inbound-rtp' && report.kind === 'audio') {
7334
+ packetsLost += report.packetsLost;
7335
+ networkStats.packetsReceived = report.packetsReceived;
7336
+ audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
7337
+ }
7338
+ if (report.type === 'inbound-rtp' && report.kind === 'video') {
7339
+ videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
7340
+ }
7341
+ if (report.type === 'outbound-rtp' && report.kind === 'video') {
7342
+ if ('framesPerSecond' in report) {
7343
+ networkStats.framesPerSecond = report.framesPerSecond;
7283
7344
  }
7345
+ if ('framerateMean' in report) {
7346
+ // framerateMean is only available in FF
7347
+ networkStats.framesPerSecond = Math.round(report.framerateMean);
7348
+ }
7349
+ }
7350
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
7351
+ packetsLost += report.packetsLost;
7352
+ networkStats.roundTripTime = report.roundTripTime;
7353
+ networkStats.jitter = report.jitter;
7354
+ }
7355
+ if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
7356
+ packetsLost += report.packetsLost;
7357
+ }
7358
+ if (report.type === 'transport') {
7359
+ transportSent += report.bytesSent;
7360
+ transportReceived += report.bytesReceived;
7284
7361
  }
7285
7362
  });
7363
+
7364
+ networkStats.packetsLost = packetsLost;
7365
+ networkStats.audioBytesSent = audioBytesSent;
7366
+ networkStats.audioBytesReceived = audioBytesReceived;
7367
+ networkStats.videoBytesSent = videoBytesSent;
7368
+ networkStats.videoBytesReceived = videoBytesReceived;
7369
+ networkStats.transportSent = transportSent;
7370
+ networkStats.transportReceived = transportReceived;
7371
+
7372
+ const bandwidth = (networkStats.audioBytesSent - lastAudioSent) + (networkStats.videoBytesSent - lastVideoSent)
7373
+ + (networkStats.audioBytesReceived - lastAudioReceived) + (networkStats.videoBytesReceived - lastVideoReceived)
7374
+ + (networkStats.transportReceived - lastTransportReceived) + (networkStats.transportSent - lastTransportSent);
7375
+
7376
+ networkStats.bandwidth = bandwidth;
7377
+
7378
+ this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
7379
+ this.sessionNetworkStats[sessionId].push(networkStats);
7286
7380
  }
7287
7381
 
7288
7382
  }
@@ -383,7 +383,7 @@ class IssueReporter {
383
383
  payload._retry = retry + 1;
384
384
  }
385
385
 
386
- this._sendDebugToGrafana(body, retry + 1);
386
+ this._sendDebugToGrafana(payload, retry + 1);
387
387
  }, 5000 + retry * 1000);
388
388
  });
389
389
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wazo/sdk",
3
- "version": "0.37.15",
3
+ "version": "0.37.19",
4
4
  "description": "Wazo's JavaScript Software Development Kit.",
5
5
  "main": "dist/wazo-sdk.js",
6
6
  "author": "Wazo (http://wazo.io)",
@@ -108,7 +108,7 @@ export default class CallLog {
108
108
  duration: (plain.duration || 0) * 1000, // duration is in seconds
109
109
  start: moment(plain.start).toDate(),
110
110
  end: plain.end ? moment(plain.end).toDate() : null,
111
- recordings: Recording.parseMany(plain.recordings),
111
+ recordings: Recording.parseMany(plain.recordings || []),
112
112
  });
113
113
  }
114
114
 
@@ -8,7 +8,8 @@ export type MeetingCreationResponse = {
8
8
  owner_uuids: Array<string>,
9
9
  port: string,
10
10
  uuid: string,
11
- number: string
11
+ number: string,
12
+ persistent: boolean,
12
13
  }
13
14
 
14
15
  export default class Meeting {
@@ -20,6 +21,7 @@ export default class Meeting {
20
21
  name: string;
21
22
  port: string;
22
23
  number: string;
24
+ persistent: boolean;
23
25
  ownerUuids: Array<string>;
24
26
 
25
27
  static parse(plain: MeetingCreationResponse): Meeting {
@@ -31,6 +33,7 @@ export default class Meeting {
31
33
  port: plain.port,
32
34
  uuid: plain.uuid,
33
35
  number: plain.number,
36
+ persistent: plain.persistent,
34
37
  });
35
38
  }
36
39
 
@@ -38,7 +41,7 @@ export default class Meeting {
38
41
  return newFrom(meeting, Meeting);
39
42
  }
40
43
 
41
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number }: Object = {}) {
44
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent }: Object = {}) {
42
45
  this.guestSipAuthorization = guestSipAuthorization;
43
46
  this.uri = uri;
44
47
  this.name = name;
@@ -46,6 +49,7 @@ export default class Meeting {
46
49
  this.port = port;
47
50
  this.uuid = uuid;
48
51
  this.number = number;
52
+ this.persistent = persistent;
49
53
 
50
54
  // Useful to compare instead of instanceof with minified code
51
55
  this.type = 'Meeting';