@wazo/sdk 0.37.23 → 0.37.27

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/README.md +95 -57
  2. package/dist/wazo-sdk.js +3 -3
  3. package/esm/__tests__/api-client.test.js +12 -7
  4. package/esm/__tests__/web-rtc-client.test.js +47 -20
  5. package/esm/api/agentd.js +1 -1
  6. package/esm/api/amid.js +1 -1
  7. package/esm/api/application.js +1 -1
  8. package/esm/api/auth.js +1 -1
  9. package/esm/api/call-logd.js +1 -1
  10. package/esm/api/calld.js +1 -1
  11. package/esm/api/chatd.js +1 -1
  12. package/esm/api/confd.js +11 -6
  13. package/esm/api/ctid-ng.js +1 -1
  14. package/esm/api/dird.js +2 -2
  15. package/esm/api/webhookd.js +1 -1
  16. package/esm/api-client.js +12 -7
  17. package/esm/checker/Checker.js +47 -20
  18. package/esm/checker/checks/aor.js +12 -7
  19. package/esm/checker/checks/api.js +12 -7
  20. package/esm/checker/checks/index.js +47 -20
  21. package/esm/checker/checks/wazo-websocket.js +1 -1
  22. package/esm/checker/checks/webrtc-transport.js +47 -20
  23. package/esm/checker/checks/webrtc.js +47 -20
  24. package/esm/domain/AdHocAPIConference.js +12 -7
  25. package/esm/domain/Contact.js +1 -1
  26. package/esm/domain/Features.js +12 -7
  27. package/esm/domain/Meeting.js +12 -5
  28. package/esm/domain/Phone/CTIPhone.js +12 -7
  29. package/esm/domain/Phone/WebRTCPhone.js +34 -6
  30. package/esm/domain/__tests__/Contact.test.js +1 -1
  31. package/esm/domain/__tests__/Meeting.test.js +144 -0
  32. package/esm/index.js +80 -25
  33. package/esm/lib/WazoSessionDescriptionHandler.js +9 -4
  34. package/esm/service/CallApi.js +12 -7
  35. package/esm/service/IssueReporter.js +1 -1
  36. package/esm/service/__tests__/IssueReporter.test.js +1 -1
  37. package/esm/service/getApiClient.js +12 -7
  38. package/esm/simple/Auth.js +80 -25
  39. package/esm/simple/Configuration.js +80 -25
  40. package/esm/simple/Directory.js +12 -7
  41. package/esm/simple/Phone.js +80 -25
  42. package/esm/simple/Websocket.js +1 -1
  43. package/esm/simple/index.js +80 -25
  44. package/esm/simple/room/LocalParticipant.js +80 -25
  45. package/esm/simple/room/Participant.js +80 -25
  46. package/esm/simple/room/RemoteParticipant.js +80 -25
  47. package/esm/simple/room/Room.js +80 -25
  48. package/esm/simple/room/SipRoom.js +80 -25
  49. package/esm/simple/room/Stream.js +80 -25
  50. package/esm/simple/room/__tests__/RemoteParticipant.test.js +80 -25
  51. package/esm/simple/utils.js +80 -25
  52. package/esm/types/WebSocketMessage.js +1 -1
  53. package/esm/utils/__tests__/api-requester.test.js +1 -1
  54. package/esm/utils/api-requester.js +1 -1
  55. package/esm/web-rtc-client.js +47 -20
  56. package/esm/websocket-client.js +1 -1
  57. package/lib/__tests__/api-client.test.js +12 -7
  58. package/lib/__tests__/web-rtc-client.test.js +47 -20
  59. package/lib/api/agentd.js +1 -1
  60. package/lib/api/amid.js +1 -1
  61. package/lib/api/application.js +1 -1
  62. package/lib/api/auth.js +1 -1
  63. package/lib/api/call-logd.js +1 -1
  64. package/lib/api/calld.js +1 -1
  65. package/lib/api/chatd.js +1 -1
  66. package/lib/api/confd.js +11 -6
  67. package/lib/api/ctid-ng.js +1 -1
  68. package/lib/api/dird.js +2 -2
  69. package/lib/api/webhookd.js +1 -1
  70. package/lib/api-client.js +12 -7
  71. package/lib/checker/Checker.js +47 -20
  72. package/lib/checker/checks/aor.js +12 -7
  73. package/lib/checker/checks/api.js +12 -7
  74. package/lib/checker/checks/index.js +47 -20
  75. package/lib/checker/checks/wazo-websocket.js +1 -1
  76. package/lib/checker/checks/webrtc-transport.js +47 -20
  77. package/lib/checker/checks/webrtc.js +47 -20
  78. package/lib/domain/AdHocAPIConference.js +12 -7
  79. package/lib/domain/Contact.js +1 -1
  80. package/lib/domain/Features.js +12 -7
  81. package/lib/domain/Meeting.js +16 -5
  82. package/lib/domain/Phone/CTIPhone.js +12 -7
  83. package/lib/domain/Phone/WebRTCPhone.js +34 -6
  84. package/lib/domain/__tests__/Contact.test.js +1 -1
  85. package/lib/domain/__tests__/Meeting.test.js +150 -0
  86. package/lib/index.js +80 -25
  87. package/lib/lib/WazoSessionDescriptionHandler.js +9 -4
  88. package/lib/service/CallApi.js +12 -7
  89. package/lib/service/IssueReporter.js +1 -1
  90. package/lib/service/__tests__/IssueReporter.test.js +1 -1
  91. package/lib/service/getApiClient.js +12 -7
  92. package/lib/simple/Auth.js +80 -25
  93. package/lib/simple/Configuration.js +80 -25
  94. package/lib/simple/Directory.js +12 -7
  95. package/lib/simple/Phone.js +80 -25
  96. package/lib/simple/Websocket.js +1 -1
  97. package/lib/simple/index.js +80 -25
  98. package/lib/simple/room/LocalParticipant.js +80 -25
  99. package/lib/simple/room/Participant.js +80 -25
  100. package/lib/simple/room/RemoteParticipant.js +80 -25
  101. package/lib/simple/room/Room.js +80 -25
  102. package/lib/simple/room/SipRoom.js +80 -25
  103. package/lib/simple/room/Stream.js +80 -25
  104. package/lib/simple/room/__tests__/RemoteParticipant.test.js +80 -25
  105. package/lib/simple/utils.js +80 -25
  106. package/lib/types/WebSocketMessage.js +2 -0
  107. package/lib/utils/__tests__/api-requester.test.js +1 -1
  108. package/lib/utils/api-requester.js +1 -1
  109. package/lib/web-rtc-client.js +47 -20
  110. package/lib/websocket-client.js +1 -1
  111. package/package.json +1 -1
  112. package/src/domain/Contact.js +1 -1
  113. package/src/domain/Meeting.js +12 -5
  114. package/src/domain/Phone/WebRTCPhone.js +33 -5
  115. package/src/domain/__tests__/Meeting.test.js +50 -0
  116. package/src/lib/WazoSessionDescriptionHandler.js +8 -3
  117. package/src/utils/api-requester.js +1 -1
  118. package/src/web-rtc-client.js +27 -10
@@ -405,7 +405,7 @@ IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
405
405
 
406
406
  // Use a function here to be able to mock it in tests
407
407
  const realFetch = () => {
408
- if (typeof document !== 'undefined') {
408
+ if (typeof document !== 'undefined' && window.fetch) {
409
409
  // Browser
410
410
  return window.fetch;
411
411
  }
@@ -1051,6 +1051,7 @@ class WebRTCPhone extends Emitter {
1051
1051
  constraints,
1052
1052
  audioOnly,
1053
1053
  conference,
1054
+ iceRestart,
1054
1055
  });
1055
1056
 
1056
1057
  if (!sipSession) {
@@ -1154,6 +1155,11 @@ class WebRTCPhone extends Emitter {
1154
1155
 
1155
1156
  this.client.downgradeToAudio(sipSession);
1156
1157
 
1158
+ if (callSession) {
1159
+ callSession.cameraEnabled = false;
1160
+ this._updateCallSession(callSession);
1161
+ }
1162
+
1157
1163
  if (withMessage) {
1158
1164
  this._sendReinviteMessage(callSession, false);
1159
1165
  }
@@ -1181,6 +1187,11 @@ class WebRTCPhone extends Emitter {
1181
1187
 
1182
1188
  const newStream = await this.client.upgradeToVideo(sipSession, constraints, isConference);
1183
1189
 
1190
+ if (callSession) {
1191
+ callSession.cameraEnabled = true;
1192
+ this._updateCallSession(callSession);
1193
+ }
1194
+
1184
1195
  // If no stream is returned, it means we have to reinvite
1185
1196
  if (!newStream) {
1186
1197
  return true;
@@ -1450,7 +1461,7 @@ class WebRTCPhone extends Emitter {
1450
1461
  }
1451
1462
 
1452
1463
  _onCallAccepted(sipSession , cameraEnabled ) {
1453
- logger.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
1464
+ logger.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
1454
1465
 
1455
1466
  const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
1456
1467
  this.currentSipSession = sipSession;
@@ -1519,6 +1530,7 @@ class WebRTCPhone extends Emitter {
1519
1530
  _onCallTerminated(sipSession ) {
1520
1531
  logger.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
1521
1532
 
1533
+ const sipSessionId = this.getSipSessionId(sipSession);
1522
1534
  const callSession = this._createCallSession(sipSession);
1523
1535
  const isCurrentSession = this.isCurrentCallSipSession(callSession);
1524
1536
  const isCurrentIncomingCall = callSession.is(this.getIncomingCallSession());
@@ -1536,7 +1548,6 @@ class WebRTCPhone extends Emitter {
1536
1548
  }, 5);
1537
1549
  }
1538
1550
 
1539
- const sipSessionId = this.getSipSessionId(sipSession);
1540
1551
  if (sipSessionId) {
1541
1552
  this.removeIncomingSessions(sipSessionId);
1542
1553
  }
@@ -1962,7 +1973,7 @@ class WebRTCPhone extends Emitter {
1962
1973
  // @TODO: line is not used here
1963
1974
  async makeCall(number , line , cameraEnabled ,
1964
1975
  audioOnly = false, conference = false) {
1965
- logger.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
1976
+ logger.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled, audioOnly, conference });
1966
1977
  if (!number) {
1967
1978
  return Promise.resolve(null);
1968
1979
  }
@@ -2181,8 +2192,12 @@ class WebRTCPhone extends Emitter {
2181
2192
  }
2182
2193
 
2183
2194
  const sessionId = this.incomingSessions[0];
2195
+ const sipSession = this.client.getSipSession(sessionId);
2196
+ if (!sipSession) {
2197
+ return null;
2198
+ }
2184
2199
 
2185
- return this._createCallSession(this.client.getSipSession(sessionId));
2200
+ return this._createCallSession(sipSession);
2186
2201
  }
2187
2202
 
2188
2203
  sendMessage(sipSession = null, body , contentType = 'text/plain') {
@@ -2323,9 +2338,13 @@ class WebRTCPhone extends Emitter {
2323
2338
  if (this.shouldSendReinvite && this.currentSipSession
2324
2339
  && this.currentSipSession.state === SessionState.Established) {
2325
2340
  this.shouldSendReinvite = false;
2341
+ const pc = this.currentSipSession.sessionDescriptionHandler.peerConnection;
2342
+ const isConference = pc ? pc.sfu : false;
2343
+ const hasVideo = this.currentCallSession && this.currentCallSession.cameraEnabled;
2344
+
2326
2345
  try {
2327
2346
  // Send reinvite with iceRestart
2328
- this.sendReinvite(this.currentCallSession, null, false, false, true);
2347
+ this.sendReinvite(this.currentCallSession, null, isConference, !hasVideo, true);
2329
2348
  } catch (e) {
2330
2349
  logger.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
2331
2350
  }
@@ -2409,6 +2428,15 @@ class WebRTCPhone extends Emitter {
2409
2428
  return this.client.getSipSessionId(sipSession);
2410
2429
  }
2411
2430
 
2431
+ _updateCallSession(callSession ) {
2432
+ const sipSession = this.findSipSession(callSession);
2433
+ const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
2434
+
2435
+ if (sipSessionId) {
2436
+ this.callSessions[sipSessionId] = callSession;
2437
+ }
2438
+ }
2439
+
2412
2440
  _onMessage(message ) {
2413
2441
  if (!message || message.method !== 'MESSAGE') {
2414
2442
  return;
@@ -698,7 +698,7 @@ class Contact {
698
698
  this[key] = old[key] || this[key];
699
699
  });
700
700
 
701
- if (old.lineState && !this.lineState) {
701
+ if (old.lineState) {
702
702
  this.lineState = old.lineState;
703
703
  }
704
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
+ });
package/esm/index.js CHANGED
@@ -464,7 +464,7 @@ const logger$c = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
464
464
 
465
465
  // Use a function here to be able to mock it in tests
466
466
  const realFetch = () => {
467
- if (typeof document !== 'undefined') {
467
+ if (typeof document !== 'undefined' && window.fetch) {
468
468
  // Browser
469
469
  return window.fetch;
470
470
  }
@@ -1924,7 +1924,7 @@ class Contact {
1924
1924
  this[key] = old[key] || this[key];
1925
1925
  });
1926
1926
 
1927
- if (old.lineState && !this.lineState) {
1927
+ if (old.lineState) {
1928
1928
  this.lineState = old.lineState;
1929
1929
  }
1930
1930
 
@@ -2631,8 +2631,9 @@ class ExternalApp {
2631
2631
 
2632
2632
 
2633
2633
 
2634
-
2634
+
2635
2635
 
2636
+
2636
2637
 
2637
2638
 
2638
2639
  class Meeting {
@@ -2643,9 +2644,10 @@ class Meeting {
2643
2644
 
2644
2645
 
2645
2646
 
2646
-
2647
+
2647
2648
 
2648
2649
 
2650
+
2649
2651
 
2650
2652
  static parse(plain ) {
2651
2653
  return new Meeting({
@@ -2655,8 +2657,9 @@ class Meeting {
2655
2657
  ownerUuids: plain.owner_uuids,
2656
2658
  port: plain.port,
2657
2659
  uuid: plain.uuid,
2658
- number: plain.number,
2660
+ extension: plain.exten,
2659
2661
  persistent: plain.persistent,
2662
+ creationTime: moment(plain.creation_time).toDate(),
2660
2663
  });
2661
2664
  }
2662
2665
 
@@ -2678,8 +2681,9 @@ class Meeting {
2678
2681
  ownerUuids,
2679
2682
  port,
2680
2683
  uri,
2681
- number,
2684
+ extension,
2682
2685
  persistent,
2686
+ creationTime,
2683
2687
  } = {}) {
2684
2688
  this.guestSipAuthorization = guestSipAuthorization;
2685
2689
  this.uri = uri;
@@ -2687,8 +2691,9 @@ class Meeting {
2687
2691
  this.ownerUuids = ownerUuids;
2688
2692
  this.port = port;
2689
2693
  this.uuid = uuid;
2690
- this.number = number;
2694
+ this.extension = extension;
2691
2695
  this.persistent = persistent;
2696
+ this.creationTime = creationTime;
2692
2697
 
2693
2698
  // Useful to compare instead of instanceof with minified code
2694
2699
  this.type = 'Meeting';
@@ -5619,11 +5624,16 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5619
5624
 
5620
5625
  // $FlowFixMe
5621
5626
  setRemoteSessionDescription(sessionDescription ) {
5622
- const result = super.setRemoteSessionDescription(sessionDescription);
5627
+ try {
5628
+ const result = super.setRemoteSessionDescription(sessionDescription);
5623
5629
 
5624
- this.eventEmitter.emit('setDescription', sessionDescription);
5630
+ this.eventEmitter.emit('setDescription', sessionDescription);
5625
5631
 
5626
- return result;
5632
+ return result;
5633
+ } catch (error) {
5634
+ this.logger.error('SessionDescriptionHandler.setRemoteSessionDescription error', error);
5635
+ throw error;
5636
+ }
5627
5637
  }
5628
5638
 
5629
5639
  // Overridden to avoid to fix ice-candidates missing in the SDP in react-native and chrome canary.
@@ -6528,7 +6538,7 @@ class WebRTCClient extends Emitter {
6528
6538
  }
6529
6539
 
6530
6540
  call(number , enableVideo , audioOnly = false, conference = false) {
6531
- logger$9.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6541
+ logger$9.info('sdk webrtc creating call', { number, enableVideo, audioOnly, conference });
6532
6542
  const inviterOptions = {
6533
6543
  sessionDescriptionHandlerOptionsReInvite: {
6534
6544
  conference,
@@ -7604,6 +7614,7 @@ class WebRTCClient extends Emitter {
7604
7614
  const screenSharing = constraints && 'screen' in constraints ? constraints.screen : false;
7605
7615
  const isDesktop = constraints && 'desktop' in constraints ? constraints.desktop : false;
7606
7616
  const withAudio = constraints && 'audio' in constraints ? constraints.audio : true;
7617
+ const mandatoryVideo = constraints && typeof constraints.video === 'object' ? constraints.video.mandatory : {};
7607
7618
 
7608
7619
  logger$9.info('Retrieving media a configuration', { enableVideo, screenSharing, isDesktop, withAudio, constraints });
7609
7620
 
@@ -7611,7 +7622,8 @@ class WebRTCClient extends Emitter {
7611
7622
  constraints: {
7612
7623
  // Exact constraint are not supported with `getDisplayMedia` and we must have a video=false in desktop screenshare
7613
7624
  audio: screenSharing ? !isDesktop : (withAudio ? this._getAudioConstraints() : false),
7614
- video: screenSharing ? (isDesktop ? ({ mandatory: { chromeMediaSource: 'desktop' } }) : { cursor: 'always' })
7625
+ video: screenSharing ? (isDesktop
7626
+ ? ({ mandatory: { chromeMediaSource: 'desktop', ...(mandatoryVideo || {}) } }) : { cursor: 'always' })
7615
7627
  : this._getVideoConstraints(enableVideo),
7616
7628
  screen: screenSharing,
7617
7629
  desktop: isDesktop,
@@ -7946,12 +7958,14 @@ class WebRTCClient extends Emitter {
7946
7958
 
7947
7959
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
7948
7960
 
7949
- pc.oniceconnectionstatechange = () => {
7950
- logger$9.info('on ice connection state changed', { state: pc.iceConnectionState });
7951
- if (pc.iceConnectionState === 'disconnected') {
7952
- this.eventEmitter.emit(ON_DISCONNECTED$1);
7953
- }
7954
- };
7961
+ if (pc) {
7962
+ pc.oniceconnectionstatechange = () => {
7963
+ logger$9.info('on ice connection state changed', { state: pc.iceConnectionState });
7964
+ if (pc.iceConnectionState === 'disconnected') {
7965
+ this.eventEmitter.emit(ON_DISCONNECTED$1);
7966
+ }
7967
+ };
7968
+ }
7955
7969
 
7956
7970
  if (withEvent) {
7957
7971
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
@@ -8161,13 +8175,17 @@ class WebRTCClient extends Emitter {
8161
8175
  const nbStats = this.sessionNetworkStats[sessionId].length;
8162
8176
  const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
8163
8177
  const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
8178
+ const lastAudioContentSent = lastNetworkStats ? lastNetworkStats.audioContentSent : 0;
8164
8179
  const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
8165
8180
  const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
8181
+ const lastAudioContentReceived = lastNetworkStats ? lastNetworkStats.audioContentReceived : 0;
8166
8182
  const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
8167
8183
  const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
8168
8184
  const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
8169
- let audioBytesSent = 0;
8170
- let audioBytesReceived = 0;
8185
+ let audioBytesSent = 0; // content + header
8186
+ let audioBytesReceived = 0; // content + header
8187
+ let audioContentSent = 0; // useful to detect blank call
8188
+ let audioContentReceived = 0;
8171
8189
  let videoBytesSent = 0;
8172
8190
  let videoBytesReceived = 0;
8173
8191
  let transportSent = 0;
@@ -8177,6 +8195,7 @@ class WebRTCClient extends Emitter {
8177
8195
  stats.forEach(report => {
8178
8196
  if (report.type === 'outbound-rtp' && report.kind === 'audio') {
8179
8197
  audioBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
8198
+ audioContentSent += Number(report.bytesSent);
8180
8199
  }
8181
8200
  if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
8182
8201
  audioBytesSent += Number(report.bytesSent);
@@ -8188,6 +8207,7 @@ class WebRTCClient extends Emitter {
8188
8207
  packetsLost += Number(report.packetsLost);
8189
8208
  networkStats.packetsReceived = Number(report.packetsReceived);
8190
8209
  audioBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
8210
+ audioContentReceived += Number(report.bytesReceived);
8191
8211
  }
8192
8212
  if (report.type === 'inbound-rtp' && report.kind === 'video') {
8193
8213
  videoBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
@@ -8216,10 +8236,17 @@ class WebRTCClient extends Emitter {
8216
8236
  });
8217
8237
 
8218
8238
  networkStats.packetsLost = packetsLost;
8239
+
8219
8240
  networkStats.totalAudioBytesSent = audioBytesSent;
8220
8241
  networkStats.audioBytesSent = audioBytesSent - lastAudioSent;
8221
8242
  networkStats.totalAudioBytesReceived = audioBytesReceived - lastAudioReceived;
8222
8243
  networkStats.audioBytesReceived = audioBytesReceived;
8244
+
8245
+ networkStats.totalAudioContentSent = audioContentSent;
8246
+ networkStats.audioContentSent = audioContentSent - lastAudioContentSent;
8247
+ networkStats.totalAudioBytesReceived = audioContentReceived - lastAudioContentReceived;
8248
+ networkStats.audioContentReceived = audioContentReceived;
8249
+
8223
8250
  networkStats.totalVideoBytesSent = videoBytesSent;
8224
8251
  networkStats.videoBytesSent = videoBytesSent - lastVideoSent;
8225
8252
  networkStats.totalVideoBytesReceived = videoBytesReceived;
@@ -9324,6 +9351,7 @@ class WebRTCPhone extends Emitter {
9324
9351
  constraints,
9325
9352
  audioOnly,
9326
9353
  conference,
9354
+ iceRestart,
9327
9355
  });
9328
9356
 
9329
9357
  if (!sipSession) {
@@ -9427,6 +9455,11 @@ class WebRTCPhone extends Emitter {
9427
9455
 
9428
9456
  this.client.downgradeToAudio(sipSession);
9429
9457
 
9458
+ if (callSession) {
9459
+ callSession.cameraEnabled = false;
9460
+ this._updateCallSession(callSession);
9461
+ }
9462
+
9430
9463
  if (withMessage) {
9431
9464
  this._sendReinviteMessage(callSession, false);
9432
9465
  }
@@ -9454,6 +9487,11 @@ class WebRTCPhone extends Emitter {
9454
9487
 
9455
9488
  const newStream = await this.client.upgradeToVideo(sipSession, constraints, isConference);
9456
9489
 
9490
+ if (callSession) {
9491
+ callSession.cameraEnabled = true;
9492
+ this._updateCallSession(callSession);
9493
+ }
9494
+
9457
9495
  // If no stream is returned, it means we have to reinvite
9458
9496
  if (!newStream) {
9459
9497
  return true;
@@ -9723,7 +9761,7 @@ class WebRTCPhone extends Emitter {
9723
9761
  }
9724
9762
 
9725
9763
  _onCallAccepted(sipSession , cameraEnabled ) {
9726
- logger$7.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
9764
+ logger$7.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
9727
9765
 
9728
9766
  const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
9729
9767
  this.currentSipSession = sipSession;
@@ -9792,6 +9830,7 @@ class WebRTCPhone extends Emitter {
9792
9830
  _onCallTerminated(sipSession ) {
9793
9831
  logger$7.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
9794
9832
 
9833
+ const sipSessionId = this.getSipSessionId(sipSession);
9795
9834
  const callSession = this._createCallSession(sipSession);
9796
9835
  const isCurrentSession = this.isCurrentCallSipSession(callSession);
9797
9836
  const isCurrentIncomingCall = callSession.is(this.getIncomingCallSession());
@@ -9809,7 +9848,6 @@ class WebRTCPhone extends Emitter {
9809
9848
  }, 5);
9810
9849
  }
9811
9850
 
9812
- const sipSessionId = this.getSipSessionId(sipSession);
9813
9851
  if (sipSessionId) {
9814
9852
  this.removeIncomingSessions(sipSessionId);
9815
9853
  }
@@ -10235,7 +10273,7 @@ class WebRTCPhone extends Emitter {
10235
10273
  // @TODO: line is not used here
10236
10274
  async makeCall(number , line , cameraEnabled ,
10237
10275
  audioOnly = false, conference = false) {
10238
- logger$7.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
10276
+ logger$7.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled, audioOnly, conference });
10239
10277
  if (!number) {
10240
10278
  return Promise.resolve(null);
10241
10279
  }
@@ -10454,8 +10492,12 @@ class WebRTCPhone extends Emitter {
10454
10492
  }
10455
10493
 
10456
10494
  const sessionId = this.incomingSessions[0];
10495
+ const sipSession = this.client.getSipSession(sessionId);
10496
+ if (!sipSession) {
10497
+ return null;
10498
+ }
10457
10499
 
10458
- return this._createCallSession(this.client.getSipSession(sessionId));
10500
+ return this._createCallSession(sipSession);
10459
10501
  }
10460
10502
 
10461
10503
  sendMessage(sipSession = null, body , contentType = 'text/plain') {
@@ -10596,9 +10638,13 @@ class WebRTCPhone extends Emitter {
10596
10638
  if (this.shouldSendReinvite && this.currentSipSession
10597
10639
  && this.currentSipSession.state === SessionState.Established) {
10598
10640
  this.shouldSendReinvite = false;
10641
+ const pc = this.currentSipSession.sessionDescriptionHandler.peerConnection;
10642
+ const isConference = pc ? pc.sfu : false;
10643
+ const hasVideo = this.currentCallSession && this.currentCallSession.cameraEnabled;
10644
+
10599
10645
  try {
10600
10646
  // Send reinvite with iceRestart
10601
- this.sendReinvite(this.currentCallSession, null, false, false, true);
10647
+ this.sendReinvite(this.currentCallSession, null, isConference, !hasVideo, true);
10602
10648
  } catch (e) {
10603
10649
  logger$7.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
10604
10650
  }
@@ -10682,6 +10728,15 @@ class WebRTCPhone extends Emitter {
10682
10728
  return this.client.getSipSessionId(sipSession);
10683
10729
  }
10684
10730
 
10731
+ _updateCallSession(callSession ) {
10732
+ const sipSession = this.findSipSession(callSession);
10733
+ const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
10734
+
10735
+ if (sipSessionId) {
10736
+ this.callSessions[sipSessionId] = callSession;
10737
+ }
10738
+ }
10739
+
10685
10740
  _onMessage(message ) {
10686
10741
  if (!message || message.method !== 'MESSAGE') {
10687
10742
  return;
@@ -15,7 +15,7 @@ IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
15
15
 
16
16
  // Use a function here to be able to mock it in tests
17
17
  const realFetch = () => {
18
- if (typeof document !== 'undefined') {
18
+ if (typeof document !== 'undefined' && window.fetch) {
19
19
  // Browser
20
20
  return window.fetch;
21
21
  }
@@ -487,11 +487,16 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
487
487
 
488
488
  // $FlowFixMe
489
489
  setRemoteSessionDescription(sessionDescription ) {
490
- const result = super.setRemoteSessionDescription(sessionDescription);
490
+ try {
491
+ const result = super.setRemoteSessionDescription(sessionDescription);
491
492
 
492
- this.eventEmitter.emit('setDescription', sessionDescription);
493
+ this.eventEmitter.emit('setDescription', sessionDescription);
493
494
 
494
- return result;
495
+ return result;
496
+ } catch (error) {
497
+ this.logger.error('SessionDescriptionHandler.setRemoteSessionDescription error', error);
498
+ throw error;
499
+ }
495
500
  }
496
501
 
497
502
  // Overridden to avoid to fix ice-candidates missing in the SDP in react-native and chrome canary.
@@ -1410,7 +1410,7 @@ class Contact {
1410
1410
  this[key] = old[key] || this[key];
1411
1411
  });
1412
1412
 
1413
- if (old.lineState && !this.lineState) {
1413
+ if (old.lineState) {
1414
1414
  this.lineState = old.lineState;
1415
1415
  }
1416
1416
 
@@ -2466,7 +2466,7 @@ const logger$1 = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
2466
2466
 
2467
2467
  // Use a function here to be able to mock it in tests
2468
2468
  const realFetch = () => {
2469
- if (typeof document !== 'undefined') {
2469
+ if (typeof document !== 'undefined' && window.fetch) {
2470
2470
  // Browser
2471
2471
  return window.fetch;
2472
2472
  }
@@ -3145,8 +3145,9 @@ class ExternalApp {
3145
3145
 
3146
3146
 
3147
3147
 
3148
-
3148
+
3149
3149
 
3150
+
3150
3151
 
3151
3152
 
3152
3153
  class Meeting {
@@ -3157,9 +3158,10 @@ class Meeting {
3157
3158
 
3158
3159
 
3159
3160
 
3160
-
3161
+
3161
3162
 
3162
3163
 
3164
+
3163
3165
 
3164
3166
  static parse(plain ) {
3165
3167
  return new Meeting({
@@ -3169,8 +3171,9 @@ class Meeting {
3169
3171
  ownerUuids: plain.owner_uuids,
3170
3172
  port: plain.port,
3171
3173
  uuid: plain.uuid,
3172
- number: plain.number,
3174
+ extension: plain.exten,
3173
3175
  persistent: plain.persistent,
3176
+ creationTime: moment(plain.creation_time).toDate(),
3174
3177
  });
3175
3178
  }
3176
3179
 
@@ -3192,8 +3195,9 @@ class Meeting {
3192
3195
  ownerUuids,
3193
3196
  port,
3194
3197
  uri,
3195
- number,
3198
+ extension,
3196
3199
  persistent,
3200
+ creationTime,
3197
3201
  } = {}) {
3198
3202
  this.guestSipAuthorization = guestSipAuthorization;
3199
3203
  this.uri = uri;
@@ -3201,8 +3205,9 @@ class Meeting {
3201
3205
  this.ownerUuids = ownerUuids;
3202
3206
  this.port = port;
3203
3207
  this.uuid = uuid;
3204
- this.number = number;
3208
+ this.extension = extension;
3205
3209
  this.persistent = persistent;
3210
+ this.creationTime = creationTime;
3206
3211
 
3207
3212
  // Useful to compare instead of instanceof with minified code
3208
3213
  this.type = 'Meeting';
@@ -11,7 +11,7 @@ IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
11
11
 
12
12
  // Use a function here to be able to mock it in tests
13
13
  const realFetch = () => {
14
- if (typeof document !== 'undefined') {
14
+ if (typeof document !== 'undefined' && window.fetch) {
15
15
  // Browser
16
16
  return window.fetch;
17
17
  }
@@ -11,7 +11,7 @@ IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
11
11
 
12
12
  // Use a function here to be able to mock it in tests
13
13
  const realFetch = () => {
14
- if (typeof document !== 'undefined') {
14
+ if (typeof document !== 'undefined' && window.fetch) {
15
15
  // Browser
16
16
  return window.fetch;
17
17
  }