@wazo/sdk 0.37.22 → 0.37.26

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 (118) hide show
  1. package/dist/wazo-sdk.js +5 -5
  2. package/esm/__tests__/api-client.test.js +37 -6
  3. package/esm/__tests__/web-rtc-client.test.js +78 -68
  4. package/esm/api/call-logd.js +7 -0
  5. package/esm/api/calld.js +10 -0
  6. package/esm/api/chatd.js +7 -0
  7. package/esm/api/confd.js +13 -5
  8. package/esm/api/ctid-ng.js +10 -0
  9. package/esm/api/dird.js +4 -1
  10. package/esm/api-client.js +37 -6
  11. package/esm/checker/Checker.js +78 -68
  12. package/esm/checker/checks/aor.js +37 -6
  13. package/esm/checker/checks/api.js +37 -6
  14. package/esm/checker/checks/index.js +78 -68
  15. package/esm/checker/checks/webrtc-transport.js +78 -68
  16. package/esm/checker/checks/webrtc.js +78 -68
  17. package/esm/domain/AdHocAPIConference.js +37 -6
  18. package/esm/domain/Call.js +3 -0
  19. package/esm/domain/CallLog.js +7 -0
  20. package/esm/domain/ChatMessage.js +4 -0
  21. package/esm/domain/ChatRoom.js +3 -0
  22. package/esm/domain/Contact.js +4 -1
  23. package/esm/domain/Features.js +37 -6
  24. package/esm/domain/Meeting.js +15 -5
  25. package/esm/domain/Phone/CTIPhone.js +41 -6
  26. package/esm/domain/Phone/WebRTCPhone.js +41 -15
  27. package/esm/domain/Recording.js +3 -0
  28. package/esm/domain/Voicemail.js +3 -0
  29. package/esm/domain/__tests__/Call.test.js +3 -0
  30. package/esm/domain/__tests__/CallLog.test.js +7 -0
  31. package/esm/domain/__tests__/Contact.test.js +4 -1
  32. package/esm/domain/__tests__/Meeting.test.js +144 -0
  33. package/esm/domain/__tests__/Voicemail.test.js +3 -0
  34. package/esm/index.js +122 -82
  35. package/esm/lib/WazoSessionDescriptionHandler.js +0 -38
  36. package/esm/service/CallApi.js +37 -6
  37. package/esm/service/getApiClient.js +37 -6
  38. package/esm/simple/Auth.js +122 -82
  39. package/esm/simple/Configuration.js +122 -82
  40. package/esm/simple/Directory.js +37 -6
  41. package/esm/simple/Phone.js +122 -82
  42. package/esm/simple/index.js +122 -82
  43. package/esm/simple/room/LocalParticipant.js +122 -82
  44. package/esm/simple/room/Participant.js +122 -82
  45. package/esm/simple/room/RemoteParticipant.js +122 -82
  46. package/esm/simple/room/Room.js +122 -82
  47. package/esm/simple/room/SipRoom.js +122 -82
  48. package/esm/simple/room/Stream.js +122 -82
  49. package/esm/simple/room/__tests__/RemoteParticipant.test.js +122 -82
  50. package/esm/simple/utils.js +122 -82
  51. package/esm/types/WebSocketMessage.js +1 -1
  52. package/esm/web-rtc-client.js +78 -68
  53. package/lib/__tests__/api-client.test.js +37 -6
  54. package/lib/__tests__/web-rtc-client.test.js +78 -68
  55. package/lib/api/call-logd.js +7 -0
  56. package/lib/api/calld.js +10 -0
  57. package/lib/api/chatd.js +7 -0
  58. package/lib/api/confd.js +13 -5
  59. package/lib/api/ctid-ng.js +10 -0
  60. package/lib/api/dird.js +4 -1
  61. package/lib/api-client.js +37 -6
  62. package/lib/checker/Checker.js +78 -68
  63. package/lib/checker/checks/aor.js +37 -6
  64. package/lib/checker/checks/api.js +37 -6
  65. package/lib/checker/checks/index.js +78 -68
  66. package/lib/checker/checks/webrtc-transport.js +78 -68
  67. package/lib/checker/checks/webrtc.js +78 -68
  68. package/lib/domain/AdHocAPIConference.js +37 -6
  69. package/lib/domain/Call.js +3 -0
  70. package/lib/domain/CallLog.js +7 -0
  71. package/lib/domain/ChatMessage.js +4 -0
  72. package/lib/domain/ChatRoom.js +3 -0
  73. package/lib/domain/Contact.js +4 -1
  74. package/lib/domain/Features.js +37 -6
  75. package/lib/domain/Meeting.js +19 -5
  76. package/lib/domain/Phone/CTIPhone.js +41 -6
  77. package/lib/domain/Phone/WebRTCPhone.js +41 -15
  78. package/lib/domain/Recording.js +3 -0
  79. package/lib/domain/Voicemail.js +3 -0
  80. package/lib/domain/__tests__/Call.test.js +3 -0
  81. package/lib/domain/__tests__/CallLog.test.js +7 -0
  82. package/lib/domain/__tests__/Contact.test.js +4 -1
  83. package/lib/domain/__tests__/Meeting.test.js +150 -0
  84. package/lib/domain/__tests__/Voicemail.test.js +3 -0
  85. package/lib/index.js +122 -82
  86. package/lib/lib/WazoSessionDescriptionHandler.js +0 -38
  87. package/lib/service/CallApi.js +37 -6
  88. package/lib/service/getApiClient.js +37 -6
  89. package/lib/simple/Auth.js +122 -82
  90. package/lib/simple/Configuration.js +122 -82
  91. package/lib/simple/Directory.js +37 -6
  92. package/lib/simple/Phone.js +122 -82
  93. package/lib/simple/index.js +122 -82
  94. package/lib/simple/room/LocalParticipant.js +122 -82
  95. package/lib/simple/room/Participant.js +122 -82
  96. package/lib/simple/room/RemoteParticipant.js +122 -82
  97. package/lib/simple/room/Room.js +122 -82
  98. package/lib/simple/room/SipRoom.js +122 -82
  99. package/lib/simple/room/Stream.js +122 -82
  100. package/lib/simple/room/__tests__/RemoteParticipant.test.js +122 -82
  101. package/lib/simple/utils.js +122 -82
  102. package/lib/types/WebSocketMessage.js +2 -0
  103. package/lib/web-rtc-client.js +78 -68
  104. package/package.json +1 -1
  105. package/src/domain/Call.js +3 -0
  106. package/src/domain/CallLog.js +4 -0
  107. package/src/domain/ChatMessage.js +4 -0
  108. package/src/domain/ChatRoom.js +3 -0
  109. package/src/domain/Contact.js +4 -1
  110. package/src/domain/Meeting.js +15 -5
  111. package/src/domain/Phone/CTIPhone.js +4 -0
  112. package/src/domain/Phone/Phone.js +2 -0
  113. package/src/domain/Phone/WebRTCPhone.js +41 -15
  114. package/src/domain/Recording.js +3 -0
  115. package/src/domain/Voicemail.js +3 -0
  116. package/src/domain/__tests__/Meeting.test.js +50 -0
  117. package/src/lib/WazoSessionDescriptionHandler.js +1 -35
  118. package/src/web-rtc-client.js +41 -24
@@ -71,6 +71,9 @@ class Call {
71
71
 
72
72
 
73
73
  static parseMany(plain ) {
74
+ if (!plain) {
75
+ return [];
76
+ }
74
77
  return plain.map((plainCall ) => Call.parse(plainCall));
75
78
  }
76
79
 
@@ -54,6 +54,9 @@ class Recording {
54
54
 
55
55
 
56
56
  static parseMany(recordings = []) {
57
+ if (!recordings) {
58
+ return [];
59
+ }
57
60
  return recordings.map(item => Recording.parse(item));
58
61
  }
59
62
 
@@ -155,6 +158,10 @@ class CallLog {
155
158
  }
156
159
 
157
160
  static parseMany(plain ) {
161
+ if (!plain || !plain.items) {
162
+ return [];
163
+ }
164
+
158
165
  return plain.items.map(item => CallLog.parse(item));
159
166
  }
160
167
 
@@ -325,6 +325,9 @@ class Contact {
325
325
  }
326
326
 
327
327
  static parseMany(response ) {
328
+ if (!response || !response.results) {
329
+ return [];
330
+ }
328
331
  return response.results.map(r => Contact.parse(r, response.column_types));
329
332
  }
330
333
 
@@ -695,7 +698,7 @@ class Contact {
695
698
  this[key] = old[key] || this[key];
696
699
  });
697
700
 
698
- if (old.lineState && !this.lineState) {
701
+ if (old.lineState) {
699
702
  this.lineState = old.lineState;
700
703
  }
701
704
 
@@ -0,0 +1,144 @@
1
+ import moment from 'moment';
2
+
3
+ //
4
+
5
+ var newFrom = (instance , ToClass ) => {
6
+ const args = {};
7
+ Object.getOwnPropertyNames(instance).forEach(prop => {
8
+ args[prop] = instance[prop];
9
+ });
10
+
11
+ return new ToClass(args);
12
+ };
13
+
14
+ //
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+ class Meeting {
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+ static parse(plain ) {
42
+ return new Meeting({
43
+ guestSipAuthorization: plain.guest_sip_authorization,
44
+ uri: plain.ingress_http_uri,
45
+ name: plain.name,
46
+ ownerUuids: plain.owner_uuids,
47
+ port: plain.port,
48
+ uuid: plain.uuid,
49
+ extension: plain.exten,
50
+ persistent: plain.persistent,
51
+ creationTime: moment(plain.creation_time).toDate(),
52
+ });
53
+ }
54
+
55
+ static parseMany(items ) {
56
+ if (!items) {
57
+ return [];
58
+ }
59
+ return items.map(plain => Meeting.parse(plain));
60
+ }
61
+
62
+ static newFrom(meeting ) {
63
+ return newFrom(meeting, Meeting);
64
+ }
65
+
66
+ constructor({
67
+ uuid,
68
+ name,
69
+ guestSipAuthorization,
70
+ ownerUuids,
71
+ port,
72
+ uri,
73
+ extension,
74
+ persistent,
75
+ creationTime,
76
+ } = {}) {
77
+ this.guestSipAuthorization = guestSipAuthorization;
78
+ this.uri = uri;
79
+ this.name = name;
80
+ this.ownerUuids = ownerUuids;
81
+ this.port = port;
82
+ this.uuid = uuid;
83
+ this.extension = extension;
84
+ this.persistent = persistent;
85
+ this.creationTime = creationTime;
86
+
87
+ // Useful to compare instead of instanceof with minified code
88
+ this.type = 'Meeting';
89
+ }
90
+
91
+ getGuestSipCredentials() {
92
+ // eslint-disable-next-line no-undef
93
+ const [username, secret] = atob(this.guestSipAuthorization).split(':');
94
+ return { username, secret };
95
+ }
96
+ }
97
+
98
+ //
99
+
100
+ describe('Meeting domain', () => {
101
+ it('can return username and secret from an base64 encrypted string', () => {
102
+ const USERNAME = 'username';
103
+ const SECRET = 'secret';
104
+
105
+ const args = {
106
+ guest_sip_authorization: btoa(`${USERNAME}:${SECRET}`),
107
+ creation_time: '',
108
+ ingress_http_uri: '',
109
+ name: '',
110
+ owner_uuids: [],
111
+ port: '',
112
+ uuid: '',
113
+ exten: '',
114
+ persistent: false,
115
+ };
116
+
117
+ const meeting = Meeting.parse(args);
118
+
119
+ const { username, secret } = meeting.getGuestSipCredentials();
120
+
121
+ expect(username).toEqual(USERNAME);
122
+ expect(secret).toEqual(SECRET);
123
+ });
124
+
125
+ it('should return a date from a string', () => {
126
+ const args = {
127
+ creation_time: '2021-12-21T15:56:42.880Z',
128
+ guest_sip_authorization: '',
129
+ ingress_http_uri: '',
130
+ name: '',
131
+ owner_uuids: [],
132
+ port: '',
133
+ uuid: '',
134
+ exten: '',
135
+ persistent: false,
136
+ };
137
+
138
+ const { creationTime } = Meeting.parse(args);
139
+
140
+ expect(creationTime.getDate()).toEqual(21);
141
+ expect(creationTime.getFullYear()).toEqual(2021);
142
+ expect(creationTime.getMonth()).toEqual(11);
143
+ });
144
+ });
@@ -71,6 +71,9 @@ class Voicemail {
71
71
  }
72
72
 
73
73
  static parseMany(plain ) {
74
+ if (!plain) {
75
+ return [];
76
+ }
74
77
  const plainUnread = plain.folders.filter(folder => folder.type === 'new')[0].messages;
75
78
  const plainRead = plain.folders.filter(folder => folder.type === 'old')[0].messages;
76
79
 
package/esm/index.js CHANGED
@@ -1551,6 +1551,9 @@ class Contact {
1551
1551
  }
1552
1552
 
1553
1553
  static parseMany(response ) {
1554
+ if (!response || !response.results) {
1555
+ return [];
1556
+ }
1554
1557
  return response.results.map(r => Contact.parse(r, response.column_types));
1555
1558
  }
1556
1559
 
@@ -1921,7 +1924,7 @@ class Contact {
1921
1924
  this[key] = old[key] || this[key];
1922
1925
  });
1923
1926
 
1924
- if (old.lineState && !this.lineState) {
1927
+ if (old.lineState) {
1925
1928
  this.lineState = old.lineState;
1926
1929
  }
1927
1930
 
@@ -2628,8 +2631,9 @@ class ExternalApp {
2628
2631
 
2629
2632
 
2630
2633
 
2631
-
2634
+
2632
2635
 
2636
+
2633
2637
 
2634
2638
 
2635
2639
  class Meeting {
@@ -2640,9 +2644,10 @@ class Meeting {
2640
2644
 
2641
2645
 
2642
2646
 
2643
-
2647
+
2644
2648
 
2645
2649
 
2650
+
2646
2651
 
2647
2652
  static parse(plain ) {
2648
2653
  return new Meeting({
@@ -2652,12 +2657,16 @@ class Meeting {
2652
2657
  ownerUuids: plain.owner_uuids,
2653
2658
  port: plain.port,
2654
2659
  uuid: plain.uuid,
2655
- number: plain.number,
2660
+ extension: plain.exten,
2656
2661
  persistent: plain.persistent,
2662
+ creationTime: moment(plain.creation_time).toDate(),
2657
2663
  });
2658
2664
  }
2659
2665
 
2660
2666
  static parseMany(items ) {
2667
+ if (!items) {
2668
+ return [];
2669
+ }
2661
2670
  return items.map(plain => Meeting.parse(plain));
2662
2671
  }
2663
2672
 
@@ -2672,8 +2681,9 @@ class Meeting {
2672
2681
  ownerUuids,
2673
2682
  port,
2674
2683
  uri,
2675
- number,
2684
+ extension,
2676
2685
  persistent,
2686
+ creationTime,
2677
2687
  } = {}) {
2678
2688
  this.guestSipAuthorization = guestSipAuthorization;
2679
2689
  this.uri = uri;
@@ -2681,8 +2691,9 @@ class Meeting {
2681
2691
  this.ownerUuids = ownerUuids;
2682
2692
  this.port = port;
2683
2693
  this.uuid = uuid;
2684
- this.number = number;
2694
+ this.extension = extension;
2685
2695
  this.persistent = persistent;
2696
+ this.creationTime = creationTime;
2686
2697
 
2687
2698
  // Useful to compare instead of instanceof with minified code
2688
2699
  this.type = 'Meeting';
@@ -2860,6 +2871,10 @@ class ChatMessage {
2860
2871
 
2861
2872
 
2862
2873
  static parseMany(plain ) {
2874
+ if (!plain || !plain.items) {
2875
+ return [];
2876
+ }
2877
+
2863
2878
  return plain.items.map(item => ChatMessage.parse(item));
2864
2879
  }
2865
2880
 
@@ -2969,6 +2984,9 @@ class Voicemail {
2969
2984
  }
2970
2985
 
2971
2986
  static parseMany(plain ) {
2987
+ if (!plain) {
2988
+ return [];
2989
+ }
2972
2990
  const plainUnread = plain.folders.filter(folder => folder.type === 'new')[0].messages;
2973
2991
  const plainRead = plain.folders.filter(folder => folder.type === 'old')[0].messages;
2974
2992
 
@@ -3078,6 +3096,9 @@ class Call {
3078
3096
 
3079
3097
 
3080
3098
  static parseMany(plain ) {
3099
+ if (!plain) {
3100
+ return [];
3101
+ }
3081
3102
  return plain.map((plainCall ) => Call.parse(plainCall));
3082
3103
  }
3083
3104
 
@@ -3621,6 +3642,9 @@ class Recording {
3621
3642
 
3622
3643
 
3623
3644
  static parseMany(recordings = []) {
3645
+ if (!recordings) {
3646
+ return [];
3647
+ }
3624
3648
  return recordings.map(item => Recording.parse(item));
3625
3649
  }
3626
3650
 
@@ -3722,6 +3746,10 @@ class CallLog {
3722
3746
  }
3723
3747
 
3724
3748
  static parseMany(plain ) {
3749
+ if (!plain || !plain.items) {
3750
+ return [];
3751
+ }
3752
+
3725
3753
  return plain.items.map(item => CallLog.parse(item));
3726
3754
  }
3727
3755
 
@@ -4374,6 +4402,10 @@ class CTIPhone extends Emitter {
4374
4402
  return false;
4375
4403
  }
4376
4404
 
4405
+ hasAVideoTrack() {
4406
+ return false;
4407
+ }
4408
+
4377
4409
  getLocalStreamForCall() {
4378
4410
  return null;
4379
4411
  }
@@ -4767,6 +4799,9 @@ class ChatRoom {
4767
4799
 
4768
4800
 
4769
4801
  static parseMany(plain ) {
4802
+ if (!plain || !plain.items) {
4803
+ return [];
4804
+ }
4770
4805
  return plain.items.map(item => ChatRoom.parse(item));
4771
4806
  }
4772
4807
 
@@ -5490,10 +5525,6 @@ const getSrflxOrRelay = (candidates ) =>
5490
5525
  candidates
5491
5526
  .filter(candidate => candidate && (candidate.type === 'srflx' || candidate.type === 'relay'));
5492
5527
 
5493
- const areCandidateValid = (candidates ) =>
5494
- getSrflxOrRelay(candidates)
5495
- .length > 0;
5496
-
5497
5528
  const getVideoDirection = (sdp ) => {
5498
5529
  const parsedSdp = sdpParser.parse(sdp);
5499
5530
  const videoMedia = parsedSdp.media.find(media => media.type === 'video');
@@ -5546,8 +5577,6 @@ const fixSdp = (sdp , candidates , forcePort = true)
5546
5577
  /* global RTCSessionDescriptionInit, navigator */
5547
5578
 
5548
5579
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
5549
- const MAX_WAIT_FOR_ICE_TRIES = 20;
5550
- const WAIT_FOR_ICE_TIMEOUT = 500;
5551
5580
 
5552
5581
  // Customized mediaStreamFactory allowing to send screensharing stream directory when upgrading
5553
5582
  const wazoMediaStreamFactory = (constraints ) => {
@@ -5737,38 +5766,6 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5737
5766
  this._peerConnection = undefined;
5738
5767
  }
5739
5768
 
5740
- async _waitForValidGatheredIce() {
5741
- let tries = 0;
5742
-
5743
- while (!areCandidateValid(this.gatheredCandidates) && tries < MAX_WAIT_FOR_ICE_TRIES) {
5744
- wazoLogger.trace('SessionDescriptionHandler._waitForValidGatheredIce, waiting for ice', {
5745
- tries,
5746
- max: MAX_WAIT_FOR_ICE_TRIES,
5747
- });
5748
-
5749
- tries++;
5750
-
5751
- // eslint-disable-next-line no-await-in-loop
5752
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_ICE_TIMEOUT));
5753
- }
5754
-
5755
- if (tries >= MAX_WAIT_FOR_ICE_TRIES) {
5756
- const errorMsg = 'No valid candidates found, can\'t answer the call';
5757
- const error = new Error(errorMsg);
5758
- wazoLogger.error(errorMsg, { tries, max: MAX_WAIT_FOR_ICE_TRIES });
5759
-
5760
- // Emit an error, because sip.js catches the exception and switch to status Terminated.
5761
- this.eventEmitter.emit('error', error);
5762
-
5763
- wazoLogger.error('No valid candidates found', { tries, candidates: JSON.stringify(this.gatheredCandidates) });
5764
- }
5765
-
5766
- // eslint-disable-next-line
5767
- wazoLogger.trace('Found valid candidates', { tries, candidates: JSON.stringify(this.gatheredCandidates) });
5768
-
5769
- return this.getLocalSessionDescription();
5770
- }
5771
-
5772
5769
  // Overridden to send `inactive` in conference
5773
5770
  updateDirection(options , isConference = false,
5774
5771
  audioOnly = false) {
@@ -6536,7 +6533,7 @@ class WebRTCClient extends Emitter {
6536
6533
  }
6537
6534
 
6538
6535
  call(number , enableVideo , audioOnly = false, conference = false) {
6539
- logger$9.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6536
+ logger$9.info('sdk webrtc creating call', { number, enableVideo, audioOnly, conference });
6540
6537
  const inviterOptions = {
6541
6538
  sessionDescriptionHandlerOptionsReInvite: {
6542
6539
  conference,
@@ -7612,6 +7609,7 @@ class WebRTCClient extends Emitter {
7612
7609
  const screenSharing = constraints && 'screen' in constraints ? constraints.screen : false;
7613
7610
  const isDesktop = constraints && 'desktop' in constraints ? constraints.desktop : false;
7614
7611
  const withAudio = constraints && 'audio' in constraints ? constraints.audio : true;
7612
+ const mandatoryVideo = constraints && typeof constraints.video === 'object' ? constraints.video.mandatory : {};
7615
7613
 
7616
7614
  logger$9.info('Retrieving media a configuration', { enableVideo, screenSharing, isDesktop, withAudio, constraints });
7617
7615
 
@@ -7619,7 +7617,8 @@ class WebRTCClient extends Emitter {
7619
7617
  constraints: {
7620
7618
  // Exact constraint are not supported with `getDisplayMedia` and we must have a video=false in desktop screenshare
7621
7619
  audio: screenSharing ? !isDesktop : (withAudio ? this._getAudioConstraints() : false),
7622
- video: screenSharing ? (isDesktop ? ({ mandatory: { chromeMediaSource: 'desktop' } }) : { cursor: 'always' })
7620
+ video: screenSharing ? (isDesktop
7621
+ ? ({ mandatory: { chromeMediaSource: 'desktop', ...(mandatoryVideo || {}) } }) : { cursor: 'always' })
7623
7622
  : this._getVideoConstraints(enableVideo),
7624
7623
  screen: screenSharing,
7625
7624
  desktop: isDesktop,
@@ -7954,12 +7953,14 @@ class WebRTCClient extends Emitter {
7954
7953
 
7955
7954
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
7956
7955
 
7957
- pc.oniceconnectionstatechange = () => {
7958
- logger$9.info('on ice connection state changed', { state: pc.iceConnectionState });
7959
- if (pc.iceConnectionState === 'disconnected') {
7960
- this.eventEmitter.emit(ON_DISCONNECTED$1);
7961
- }
7962
- };
7956
+ if (pc) {
7957
+ pc.oniceconnectionstatechange = () => {
7958
+ logger$9.info('on ice connection state changed', { state: pc.iceConnectionState });
7959
+ if (pc.iceConnectionState === 'disconnected') {
7960
+ this.eventEmitter.emit(ON_DISCONNECTED$1);
7961
+ }
7962
+ };
7963
+ }
7963
7964
 
7964
7965
  if (withEvent) {
7965
7966
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
@@ -8169,13 +8170,17 @@ class WebRTCClient extends Emitter {
8169
8170
  const nbStats = this.sessionNetworkStats[sessionId].length;
8170
8171
  const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
8171
8172
  const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
8173
+ const lastAudioContentSent = lastNetworkStats ? lastNetworkStats.audioContentSent : 0;
8172
8174
  const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
8173
8175
  const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
8176
+ const lastAudioContentReceived = lastNetworkStats ? lastNetworkStats.audioContentReceived : 0;
8174
8177
  const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
8175
8178
  const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
8176
8179
  const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
8177
- let audioBytesSent = 0;
8178
- let audioBytesReceived = 0;
8180
+ let audioBytesSent = 0; // content + header
8181
+ let audioBytesReceived = 0; // content + header
8182
+ let audioContentSent = 0; // useful to detect blank call
8183
+ let audioContentReceived = 0;
8179
8184
  let videoBytesSent = 0;
8180
8185
  let videoBytesReceived = 0;
8181
8186
  let transportSent = 0;
@@ -8184,25 +8189,27 @@ class WebRTCClient extends Emitter {
8184
8189
 
8185
8190
  stats.forEach(report => {
8186
8191
  if (report.type === 'outbound-rtp' && report.kind === 'audio') {
8187
- audioBytesSent += report.bytesSent + report.headerBytesSent;
8192
+ audioBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
8193
+ audioContentSent += Number(report.bytesSent);
8188
8194
  }
8189
8195
  if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
8190
- audioBytesSent += report.bytesSent;
8196
+ audioBytesSent += Number(report.bytesSent);
8191
8197
  }
8192
8198
  if (report.type === 'outbound-rtp' && report.kind === 'video') {
8193
- videoBytesSent += report.bytesSent + report.headerBytesSent;
8199
+ videoBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
8194
8200
  }
8195
8201
  if (report.type === 'inbound-rtp' && report.kind === 'audio') {
8196
- packetsLost += report.packetsLost;
8197
- networkStats.packetsReceived = report.packetsReceived;
8198
- audioBytesReceived += report.bytesReceived + report.headerBytesReceived;
8202
+ packetsLost += Number(report.packetsLost);
8203
+ networkStats.packetsReceived = Number(report.packetsReceived);
8204
+ audioBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
8205
+ audioContentReceived += Number(report.bytesReceived);
8199
8206
  }
8200
8207
  if (report.type === 'inbound-rtp' && report.kind === 'video') {
8201
- videoBytesReceived += report.bytesReceived + report.headerBytesReceived;
8208
+ videoBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
8202
8209
  }
8203
8210
  if (report.type === 'outbound-rtp' && report.kind === 'video') {
8204
8211
  if ('framesPerSecond' in report) {
8205
- networkStats.framesPerSecond = report.framesPerSecond;
8212
+ networkStats.framesPerSecond = Number(report.framesPerSecond);
8206
8213
  }
8207
8214
  if ('framerateMean' in report) {
8208
8215
  // framerateMean is only available in FF
@@ -8210,24 +8217,31 @@ class WebRTCClient extends Emitter {
8210
8217
  }
8211
8218
  }
8212
8219
  if (report.type === 'remote-inbound-rtp' && report.kind === 'audio') {
8213
- packetsLost += report.packetsLost;
8214
- networkStats.roundTripTime = report.roundTripTime;
8215
- networkStats.jitter = report.jitter;
8220
+ packetsLost += Number(report.packetsLost);
8221
+ networkStats.roundTripTime = Number(report.roundTripTime);
8222
+ networkStats.jitter = Number(report.jitter);
8216
8223
  }
8217
8224
  if (report.type === 'remote-inbound-rtp' && report.kind === 'video') {
8218
- packetsLost += report.packetsLost;
8225
+ packetsLost += Number(report.packetsLost);
8219
8226
  }
8220
8227
  if (report.type === 'transport') {
8221
- transportSent += report.bytesSent;
8222
- transportReceived += report.bytesReceived;
8228
+ transportSent += Number(report.bytesSent);
8229
+ transportReceived += Number(report.bytesReceived);
8223
8230
  }
8224
8231
  });
8225
8232
 
8226
8233
  networkStats.packetsLost = packetsLost;
8234
+
8227
8235
  networkStats.totalAudioBytesSent = audioBytesSent;
8228
8236
  networkStats.audioBytesSent = audioBytesSent - lastAudioSent;
8229
8237
  networkStats.totalAudioBytesReceived = audioBytesReceived - lastAudioReceived;
8230
8238
  networkStats.audioBytesReceived = audioBytesReceived;
8239
+
8240
+ networkStats.totalAudioContentSent = audioContentSent;
8241
+ networkStats.audioContentSent = audioContentSent - lastAudioContentSent;
8242
+ networkStats.totalAudioBytesReceived = audioContentReceived - lastAudioContentReceived;
8243
+ networkStats.audioContentReceived = audioContentReceived;
8244
+
8231
8245
  networkStats.totalVideoBytesSent = videoBytesSent;
8232
8246
  networkStats.videoBytesSent = videoBytesSent - lastVideoSent;
8233
8247
  networkStats.totalVideoBytesReceived = videoBytesReceived;
@@ -9332,6 +9346,7 @@ class WebRTCPhone extends Emitter {
9332
9346
  constraints,
9333
9347
  audioOnly,
9334
9348
  conference,
9349
+ iceRestart,
9335
9350
  });
9336
9351
 
9337
9352
  if (!sipSession) {
@@ -9435,6 +9450,11 @@ class WebRTCPhone extends Emitter {
9435
9450
 
9436
9451
  this.client.downgradeToAudio(sipSession);
9437
9452
 
9453
+ if (callSession) {
9454
+ callSession.cameraEnabled = false;
9455
+ this._updateCallSession(callSession);
9456
+ }
9457
+
9438
9458
  if (withMessage) {
9439
9459
  this._sendReinviteMessage(callSession, false);
9440
9460
  }
@@ -9462,6 +9482,11 @@ class WebRTCPhone extends Emitter {
9462
9482
 
9463
9483
  const newStream = await this.client.upgradeToVideo(sipSession, constraints, isConference);
9464
9484
 
9485
+ if (callSession) {
9486
+ callSession.cameraEnabled = true;
9487
+ this._updateCallSession(callSession);
9488
+ }
9489
+
9465
9490
  // If no stream is returned, it means we have to reinvite
9466
9491
  if (!newStream) {
9467
9492
  return true;
@@ -9698,18 +9723,20 @@ class WebRTCPhone extends Emitter {
9698
9723
  screenTrack,
9699
9724
  });
9700
9725
 
9701
- screenTrack.onended = () => {
9702
- logger$7.info('WebRTC phone - on screenshare ended', {
9703
- hadVideo,
9704
- id: this.getSipSessionId(sipSession),
9705
- screenTrack,
9706
- });
9726
+ if (screenTrack) {
9727
+ screenTrack.onended = () => {
9728
+ logger$7.info('WebRTC phone - on screenshare ended', {
9729
+ hadVideo,
9730
+ id: this.getSipSessionId(sipSession),
9731
+ screenTrack,
9732
+ });
9707
9733
 
9708
- this.eventEmitter.emit(
9709
- ON_SHARE_SCREEN_ENDING,
9710
- this._createCallSession(sipSession, callSession),
9711
- );
9712
- };
9734
+ this.eventEmitter.emit(
9735
+ ON_SHARE_SCREEN_ENDING,
9736
+ this._createCallSession(sipSession, callSession),
9737
+ );
9738
+ };
9739
+ }
9713
9740
 
9714
9741
  this.currentScreenShare = {
9715
9742
  stream: screenStream,
@@ -9729,7 +9756,7 @@ class WebRTCPhone extends Emitter {
9729
9756
  }
9730
9757
 
9731
9758
  _onCallAccepted(sipSession , cameraEnabled ) {
9732
- logger$7.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
9759
+ logger$7.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
9733
9760
 
9734
9761
  const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
9735
9762
  this.currentSipSession = sipSession;
@@ -10241,7 +10268,7 @@ class WebRTCPhone extends Emitter {
10241
10268
  // @TODO: line is not used here
10242
10269
  async makeCall(number , line , cameraEnabled ,
10243
10270
  audioOnly = false, conference = false) {
10244
- logger$7.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
10271
+ logger$7.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled, audioOnly, conference });
10245
10272
  if (!number) {
10246
10273
  return Promise.resolve(null);
10247
10274
  }
@@ -10602,9 +10629,13 @@ class WebRTCPhone extends Emitter {
10602
10629
  if (this.shouldSendReinvite && this.currentSipSession
10603
10630
  && this.currentSipSession.state === SessionState.Established) {
10604
10631
  this.shouldSendReinvite = false;
10632
+ const pc = this.currentSipSession.sessionDescriptionHandler.peerConnection;
10633
+ const isConference = pc ? pc.sfu : false;
10634
+ const hasVideo = this.currentCallSession && this.currentCallSession.cameraEnabled;
10635
+
10605
10636
  try {
10606
10637
  // Send reinvite with iceRestart
10607
- this.sendReinvite(this.currentCallSession, null, false, false, true);
10638
+ this.sendReinvite(this.currentCallSession, null, isConference, !hasVideo, true);
10608
10639
  } catch (e) {
10609
10640
  logger$7.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
10610
10641
  }
@@ -10688,6 +10719,15 @@ class WebRTCPhone extends Emitter {
10688
10719
  return this.client.getSipSessionId(sipSession);
10689
10720
  }
10690
10721
 
10722
+ _updateCallSession(callSession ) {
10723
+ const sipSession = this.findSipSession(callSession);
10724
+ const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
10725
+
10726
+ if (sipSessionId) {
10727
+ this.callSessions[sipSessionId] = callSession;
10728
+ }
10729
+ }
10730
+
10691
10731
  _onMessage(message ) {
10692
10732
  if (!message || message.method !== 'MESSAGE') {
10693
10733
  return;