@wazo/sdk 0.37.24 → 0.37.28

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 (129) hide show
  1. package/README.md +96 -58
  2. package/dist/wazo-sdk.js +6 -6
  3. package/esm/__tests__/api-client.test.js +14 -14
  4. package/esm/__tests__/web-rtc-client.test.js +130 -108
  5. package/esm/api/agentd.js +1 -1
  6. package/esm/api/amid.js +2 -2
  7. package/esm/api/application.js +1 -1
  8. package/esm/api/auth.js +1 -1
  9. package/esm/api/call-logd.js +3 -3
  10. package/esm/api/calld.js +1 -1
  11. package/esm/api/chatd.js +1 -1
  12. package/esm/api/confd.js +1 -1
  13. package/esm/api/ctid-ng.js +4 -4
  14. package/esm/api/dird.js +3 -3
  15. package/esm/api/webhookd.js +2 -2
  16. package/esm/api-client.js +14 -14
  17. package/esm/checker/Checker.js +155 -133
  18. package/esm/checker/checks/aor.js +14 -14
  19. package/esm/checker/checks/api.js +14 -14
  20. package/esm/checker/checks/index.js +145 -123
  21. package/esm/checker/checks/wazo-websocket.js +16 -16
  22. package/esm/checker/checks/webrtc-transport.js +130 -108
  23. package/esm/checker/checks/webrtc.js +130 -108
  24. package/esm/domain/AdHocAPIConference.js +14 -14
  25. package/esm/domain/CallLog.js +1 -1
  26. package/esm/domain/CallSession.js +15 -0
  27. package/esm/domain/Contact.js +2 -2
  28. package/esm/domain/Features.js +14 -14
  29. package/esm/domain/Phone/CTIPhone.js +43 -28
  30. package/esm/domain/Phone/WebRTCPhone.js +126 -90
  31. package/esm/domain/SFUNotAvailableError.js +9 -0
  32. package/esm/domain/__tests__/CallLog.test.js +1 -1
  33. package/esm/domain/__tests__/CallSession.test.js +15 -0
  34. package/esm/domain/__tests__/Contact.test.js +2 -2
  35. package/esm/domain/__tests__/IndirectTransfer.test.js +15 -0
  36. package/esm/domain/__tests__/Room.test.js +15 -0
  37. package/esm/index.js +415 -346
  38. package/esm/lib/WazoSessionDescriptionHandler.js +10 -5
  39. package/esm/service/CallApi.js +14 -14
  40. package/esm/service/IssueReporter.js +2 -2
  41. package/esm/service/__tests__/IssueReporter.test.js +2 -2
  42. package/esm/service/getApiClient.js +14 -14
  43. package/esm/simple/Auth.js +404 -336
  44. package/esm/simple/Configuration.js +404 -336
  45. package/esm/simple/Directory.js +14 -14
  46. package/esm/simple/Phone.js +404 -336
  47. package/esm/simple/Websocket.js +18 -18
  48. package/esm/simple/index.js +408 -340
  49. package/esm/simple/room/LocalParticipant.js +408 -340
  50. package/esm/simple/room/Participant.js +408 -340
  51. package/esm/simple/room/RemoteParticipant.js +408 -340
  52. package/esm/simple/room/Room.js +409 -341
  53. package/esm/simple/room/SipRoom.js +408 -340
  54. package/esm/simple/room/Stream.js +408 -340
  55. package/esm/simple/room/__tests__/RemoteParticipant.test.js +408 -340
  56. package/esm/simple/utils.js +408 -340
  57. package/esm/utils/__tests__/api-requester.test.js +1 -1
  58. package/esm/utils/api-requester.js +1 -1
  59. package/esm/web-rtc-client.js +130 -108
  60. package/esm/websocket-client.js +16 -16
  61. package/lib/__tests__/api-client.test.js +14 -14
  62. package/lib/__tests__/web-rtc-client.test.js +130 -108
  63. package/lib/api/agentd.js +1 -1
  64. package/lib/api/amid.js +2 -2
  65. package/lib/api/application.js +1 -1
  66. package/lib/api/auth.js +1 -1
  67. package/lib/api/call-logd.js +3 -3
  68. package/lib/api/calld.js +1 -1
  69. package/lib/api/chatd.js +1 -1
  70. package/lib/api/confd.js +1 -1
  71. package/lib/api/ctid-ng.js +4 -4
  72. package/lib/api/dird.js +3 -3
  73. package/lib/api/webhookd.js +2 -2
  74. package/lib/api-client.js +14 -14
  75. package/lib/checker/Checker.js +155 -133
  76. package/lib/checker/checks/aor.js +14 -14
  77. package/lib/checker/checks/api.js +14 -14
  78. package/lib/checker/checks/index.js +145 -123
  79. package/lib/checker/checks/wazo-websocket.js +16 -16
  80. package/lib/checker/checks/webrtc-transport.js +130 -108
  81. package/lib/checker/checks/webrtc.js +130 -108
  82. package/lib/domain/AdHocAPIConference.js +14 -14
  83. package/lib/domain/CallLog.js +1 -1
  84. package/lib/domain/CallSession.js +15 -0
  85. package/lib/domain/Contact.js +2 -2
  86. package/lib/domain/Features.js +14 -14
  87. package/lib/domain/Phone/CTIPhone.js +43 -28
  88. package/lib/domain/Phone/WebRTCPhone.js +126 -89
  89. package/lib/domain/SFUNotAvailableError.js +11 -0
  90. package/lib/domain/__tests__/CallLog.test.js +1 -1
  91. package/lib/domain/__tests__/CallSession.test.js +15 -0
  92. package/lib/domain/__tests__/Contact.test.js +2 -2
  93. package/lib/domain/__tests__/IndirectTransfer.test.js +15 -0
  94. package/lib/domain/__tests__/Room.test.js +15 -0
  95. package/lib/index.js +415 -346
  96. package/lib/lib/WazoSessionDescriptionHandler.js +10 -5
  97. package/lib/service/CallApi.js +14 -14
  98. package/lib/service/IssueReporter.js +2 -2
  99. package/lib/service/__tests__/IssueReporter.test.js +2 -2
  100. package/lib/service/getApiClient.js +14 -14
  101. package/lib/simple/Auth.js +404 -336
  102. package/lib/simple/Configuration.js +404 -336
  103. package/lib/simple/Directory.js +14 -14
  104. package/lib/simple/Phone.js +404 -336
  105. package/lib/simple/Websocket.js +18 -18
  106. package/lib/simple/index.js +408 -340
  107. package/lib/simple/room/LocalParticipant.js +408 -340
  108. package/lib/simple/room/Participant.js +408 -340
  109. package/lib/simple/room/RemoteParticipant.js +408 -340
  110. package/lib/simple/room/Room.js +409 -341
  111. package/lib/simple/room/SipRoom.js +408 -340
  112. package/lib/simple/room/Stream.js +408 -340
  113. package/lib/simple/room/__tests__/RemoteParticipant.test.js +408 -340
  114. package/lib/simple/utils.js +408 -340
  115. package/lib/utils/__tests__/api-requester.test.js +1 -1
  116. package/lib/utils/api-requester.js +1 -1
  117. package/lib/web-rtc-client.js +130 -108
  118. package/lib/websocket-client.js +16 -16
  119. package/package.json +1 -1
  120. package/src/domain/CallSession.js +16 -0
  121. package/src/domain/Contact.js +1 -1
  122. package/src/domain/Phone/WebRTCPhone.js +25 -4
  123. package/src/domain/SFUNotAvailableError.js +7 -0
  124. package/src/index.js +2 -0
  125. package/src/lib/WazoSessionDescriptionHandler.js +8 -3
  126. package/src/simple/Phone.js +2 -1
  127. package/src/simple/index.js +2 -0
  128. package/src/utils/api-requester.js +1 -1
  129. package/src/web-rtc-client.js +27 -10
@@ -45,11 +45,11 @@ const isMobile = () => typeof navigator !== 'undefined' && navigator.product ===
45
45
 
46
46
  /* */
47
47
 
48
- const logger = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
48
+ IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
49
49
 
50
50
  // Use a function here to be able to mock it in tests
51
51
  const realFetch = () => {
52
- if (typeof document !== 'undefined') {
52
+ if (typeof document !== 'undefined' && window.fetch) {
53
53
  // Browser
54
54
  return window.fetch;
55
55
  }
@@ -621,7 +621,7 @@ const BLACKLIST_EVENTS = [
621
621
  ];
622
622
 
623
623
  const HEARTBEAT_ENGINE_VERSION = '20.09';
624
- const logger$1 = IssueReporter$1.loggerFor('wazo-ws');
624
+ const logger = IssueReporter$1.loggerFor('wazo-ws');
625
625
  const messageLogger = IssueReporter$1.loggerFor('wazo-ws-message');
626
626
 
627
627
  class WebSocketClient extends Emitter {
@@ -670,19 +670,19 @@ class WebSocketClient extends Emitter {
670
670
  }
671
671
 
672
672
  connect() {
673
- logger$1.info('connect method started', { host: this.host, token: this.token });
673
+ logger.info('connect method started', { host: this.host, token: this.token });
674
674
  this.socket = new ReconnectingWebSocket__default['default'](this._getUrl.bind(this), [], this.options);
675
675
  if (this.options.binaryType) {
676
676
  this.socket.binaryType = this.options.binaryType;
677
677
  }
678
678
 
679
679
  this.socket.onopen = () => {
680
- logger$1.info('on Wazo WS open', { method: 'connect', host: this.host });
680
+ logger.info('on Wazo WS open', { method: 'connect', host: this.host });
681
681
  this.eventEmitter.emit(SOCKET_EVENTS.ON_OPEN);
682
682
  };
683
683
 
684
684
  this.socket.onerror = event => {
685
- logger$1.error('on Wazo WS error', event.target);
685
+ logger.error('on Wazo WS error', event.target);
686
686
  this.eventEmitter.emit(SOCKET_EVENTS.ON_ERROR, event);
687
687
  };
688
688
 
@@ -712,7 +712,7 @@ class WebSocketClient extends Emitter {
712
712
 
713
713
  this.socket.onclose = event => {
714
714
  // Can't be converted to JSON (circular structure)
715
- logger$1.info('on Wazo WS close', {
715
+ logger.info('on Wazo WS close', {
716
716
  reason: event.reason,
717
717
  code: event.code,
718
718
  readyState: event.target.readyState,
@@ -730,12 +730,12 @@ class WebSocketClient extends Emitter {
730
730
  };
731
731
 
732
732
  this.socket.onerror = event => {
733
- logger$1.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
733
+ logger.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
734
734
  };
735
735
  }
736
736
 
737
737
  close(force = false) {
738
- logger$1.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
738
+ logger.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
739
739
 
740
740
  if (!this.socket) {
741
741
  return;
@@ -753,7 +753,7 @@ class WebSocketClient extends Emitter {
753
753
 
754
754
  updateToken(token ) {
755
755
  this.token = token;
756
- logger$1.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
756
+ logger.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
757
757
 
758
758
  if (this.socket) {
759
759
  // If still connected, send the token to the WS
@@ -771,7 +771,7 @@ class WebSocketClient extends Emitter {
771
771
  }
772
772
 
773
773
  startHeartbeat() {
774
- logger$1.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
774
+ logger.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
775
775
 
776
776
  if (!this.socket) {
777
777
  this.heartbeat.stop();
@@ -785,7 +785,7 @@ class WebSocketClient extends Emitter {
785
785
  }
786
786
 
787
787
  stopHeartbeat() {
788
- logger$1.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
788
+ logger.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
789
789
 
790
790
  this.heartbeat.stop();
791
791
  }
@@ -815,7 +815,7 @@ class WebSocketClient extends Emitter {
815
815
  }
816
816
 
817
817
  reconnect(reason ) {
818
- logger$1.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
818
+ logger.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
819
819
  if (!this.socket) {
820
820
  return;
821
821
  }
@@ -871,7 +871,7 @@ class WebSocketClient extends Emitter {
871
871
  this.close();
872
872
  }
873
873
  const url = `wss://${this.host || ''}/api/websocketd/?token=${this.token || ''}&version=${this.version}`;
874
- logger$1.log('Wazo WS url computed to reconnect', { url });
874
+ logger.log('Wazo WS url computed to reconnect', { url });
875
875
 
876
876
  return url;
877
877
  }
@@ -879,12 +879,12 @@ class WebSocketClient extends Emitter {
879
879
  _onHeartbeat(message ) {
880
880
  if (message.payload === 'pong') {
881
881
  this.heartbeat.onHeartbeat();
882
- logger$1.log('on heartbeat received from Wazo WS');
882
+ logger.log('on heartbeat received from Wazo WS');
883
883
  }
884
884
  }
885
885
 
886
886
  async _onHeartbeatTimeout() {
887
- logger$1.log('heartbeat timed out', { host: this.host, token: this.token });
887
+ logger.log('heartbeat timed out', { host: this.host, token: this.token });
888
888
 
889
889
  this.close();
890
890
  this.eventEmitter.emit(SOCKET_EVENTS.ON_CLOSE, new Error('Websocket ping failure.'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wazo/sdk",
3
- "version": "0.37.24",
3
+ "version": "0.37.28",
4
4
  "description": "Wazo's JavaScript Software Development Kit.",
5
5
  "main": "dist/wazo-sdk.js",
6
6
  "author": "Wazo (http://wazo.io)",
@@ -1,5 +1,6 @@
1
1
  // @flow
2
2
  import { SessionState } from 'sip.js/lib/api/session-state';
3
+ import type { Session } from 'sip.js/lib/api/session';
3
4
 
4
5
  import Call from './Call';
5
6
  import newFrom from '../utils/new-from';
@@ -12,8 +13,10 @@ type CallSessionArguments = {
12
13
  callId: string,
13
14
  callerNumber: string,
14
15
  cameraEnabled: boolean,
16
+ creationTime?: ?Date,
15
17
  dialedExtension?: string | null,
16
18
  displayName: string,
19
+ endTime?: ?Date,
17
20
  isCaller: boolean,
18
21
  muted: boolean,
19
22
  videoMuted: boolean,
@@ -30,6 +33,7 @@ type CallSessionArguments = {
30
33
  screensharing: boolean,
31
34
  recording: boolean,
32
35
  recordingPaused: boolean,
36
+ sipSession?: Session,
33
37
  };
34
38
 
35
39
  export default class CallSession {
@@ -49,8 +53,12 @@ export default class CallSession {
49
53
 
50
54
  callerNumber: string;
51
55
 
56
+ creationTime: ?Date;
57
+
52
58
  startTime: number;
53
59
 
60
+ endTime: ?Date;
61
+
54
62
  isCaller: boolean;
55
63
 
56
64
  answered: boolean;
@@ -89,6 +97,8 @@ export default class CallSession {
89
97
 
90
98
  recordingPaused: boolean;
91
99
 
100
+ sipSession: Session;
101
+
92
102
  constructor({
93
103
  answered,
94
104
  answeredBySystem,
@@ -101,6 +111,8 @@ export default class CallSession {
101
111
  paused,
102
112
  ringing,
103
113
  startTime,
114
+ creationTime,
115
+ endTime,
104
116
  cameraEnabled,
105
117
  dialedExtension,
106
118
  sipCallId,
@@ -113,12 +125,15 @@ export default class CallSession {
113
125
  recording,
114
126
  recordingPaused,
115
127
  videoRemotelyDowngraded,
128
+ sipSession,
116
129
  }: CallSessionArguments) {
117
130
  this.callId = callId;
118
131
  this.sipCallId = sipCallId;
119
132
  this.displayName = displayName;
120
133
  this.number = number;
134
+ this.creationTime = creationTime;
121
135
  this.startTime = startTime;
136
+ this.endTime = endTime;
122
137
  this.isCaller = isCaller;
123
138
  this.answered = answered;
124
139
  this.answeredBySystem = answeredBySystem;
@@ -137,6 +152,7 @@ export default class CallSession {
137
152
  this.recording = recording || false;
138
153
  this.recordingPaused = recordingPaused || false;
139
154
  this.videoRemotelyDowngraded = videoRemotelyDowngraded;
155
+ this.sipSession = sipSession;
140
156
 
141
157
  // Useful to compare instead of instanceof with minified code
142
158
  this.type = 'CallSession';
@@ -654,7 +654,7 @@ export default class Contact {
654
654
  this[key] = old[key] || this[key];
655
655
  });
656
656
 
657
- if (old.lineState && !this.lineState) {
657
+ if (old.lineState) {
658
658
  this.lineState = old.lineState;
659
659
  }
660
660
 
@@ -30,6 +30,7 @@ export const ON_CAMERA_DISABLED = 'onCameraDisabled';
30
30
  export const ON_CAMERA_RESUMED = 'onCameraResumed';
31
31
  export const ON_CALL_CANCELED = 'onCallCanceled';
32
32
  export const ON_CALL_FAILED = 'onCallFailed';
33
+ export const ON_CALL_REJECTED = 'onCallRejected';
33
34
  export const ON_CALL_ENDED = 'onCallEnded';
34
35
  export const ON_CALL_ENDING = 'onCallEnding';
35
36
  export const ON_MESSAGE = 'onMessage';
@@ -74,6 +75,7 @@ export const events = [
74
75
  ON_CAMERA_DISABLED,
75
76
  ON_CALL_FAILED,
76
77
  ON_CALL_ENDED,
78
+ ON_CALL_REJECTED,
77
79
  ON_MESSAGE,
78
80
  ON_REINVITE,
79
81
  ON_TRACK,
@@ -203,6 +205,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
203
205
  constraints,
204
206
  audioOnly,
205
207
  conference,
208
+ iceRestart,
206
209
  });
207
210
 
208
211
  if (!sipSession) {
@@ -429,6 +432,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
429
432
 
430
433
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
431
434
  const callSession = this._createCallSession(sipSession);
435
+ callSession.endTime = new Date();
432
436
  const wasCurrentSession = this._onCallTerminated(sipSession);
433
437
 
434
438
  return this.eventEmitter.emit(ON_CALL_ENDED, callSession, wasCurrentSession);
@@ -614,7 +618,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
614
618
  }
615
619
 
616
620
  _onCallAccepted(sipSession: Session, cameraEnabled: boolean): CallSession {
617
- logger.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
621
+ logger.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
618
622
 
619
623
  const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
620
624
  this.currentSipSession = sipSession;
@@ -683,6 +687,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
683
687
  _onCallTerminated(sipSession: Session) {
684
688
  logger.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
685
689
 
690
+ const sipSessionId = this.getSipSessionId(sipSession);
686
691
  const callSession = this._createCallSession(sipSession);
687
692
  const isCurrentSession = this.isCurrentCallSipSession(callSession);
688
693
  const isCurrentIncomingCall = callSession.is(this.getIncomingCallSession());
@@ -700,7 +705,6 @@ export default class WebRTCPhone extends Emitter implements Phone {
700
705
  }, 5);
701
706
  }
702
707
 
703
- const sipSessionId = this.getSipSessionId(sipSession);
704
708
  if (sipSessionId) {
705
709
  this.removeIncomingSessions(sipSessionId);
706
710
  }
@@ -1126,7 +1130,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1126
1130
  // @TODO: line is not used here
1127
1131
  async makeCall(number: string, line: any, cameraEnabled?: boolean,
1128
1132
  audioOnly: boolean = false, conference: boolean = false): Promise<?CallSession> {
1129
- logger.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
1133
+ logger.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled, audioOnly, conference });
1130
1134
  if (!number) {
1131
1135
  return Promise.resolve(null);
1132
1136
  }
@@ -1150,6 +1154,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1150
1154
  return Promise.resolve(null);
1151
1155
  }
1152
1156
  const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
1157
+ callSession.creationTime = new Date();
1153
1158
 
1154
1159
  this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
1155
1160
 
@@ -1345,8 +1350,12 @@ export default class WebRTCPhone extends Emitter implements Phone {
1345
1350
  }
1346
1351
 
1347
1352
  const sessionId = this.incomingSessions[0];
1353
+ const sipSession = this.client.getSipSession(sessionId);
1354
+ if (!sipSession) {
1355
+ return null;
1356
+ }
1348
1357
 
1349
- return this._createCallSession(this.client.getSipSession(sessionId));
1358
+ return this._createCallSession(sipSession);
1350
1359
  }
1351
1360
 
1352
1361
  sendMessage(sipSession: Session = null, body: string, contentType: string = 'text/plain') {
@@ -1424,6 +1433,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1424
1433
  callSession);
1425
1434
  }
1426
1435
 
1436
+ callSession.creationTime = new Date();
1427
1437
  this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
1428
1438
  });
1429
1439
 
@@ -1463,6 +1473,13 @@ export default class WebRTCPhone extends Emitter implements Phone {
1463
1473
  this.eventEmitter.emit(ON_CALL_ERROR, e);
1464
1474
  });
1465
1475
 
1476
+ this.client.on(this.client.REJECTED, session => {
1477
+ logger.info('WebRTC call rejected', session.id);
1478
+ const callSession = this._createCallSession(session);
1479
+ callSession.endTime = new Date();
1480
+ this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
1481
+ });
1482
+
1466
1483
  this.client.on(this.client.UNREGISTERED, () => {
1467
1484
  logger.info('WebRTC unregistered');
1468
1485
  this.eventEmitter.emit(ON_UNREGISTERED);
@@ -1677,6 +1694,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1677
1694
  const number = identity ? identity.uri._normal.user : null;
1678
1695
  const { state } = sipSession || {};
1679
1696
  const sessionId = this.getSipSessionId(sipSession);
1697
+ fromSession = fromSession || this.callSessions[sessionId];
1680
1698
 
1681
1699
  const callSession = new CallSession({
1682
1700
  callId: fromSession && fromSession.callId,
@@ -1684,6 +1702,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
1684
1702
  sipStatus: state,
1685
1703
  displayName: identity ? identity.displayName || number : number,
1686
1704
  startTime: fromSession ? fromSession.startTime : new Date(),
1705
+ creationTime: fromSession ? fromSession.creationTime : null,
1706
+ endTime: fromSession ? fromSession.endTime : null,
1687
1707
  answered: state === SessionState.Established,
1688
1708
  paused: this.client.isCallHeld(sipSession),
1689
1709
  isCaller: 'incoming' in extra ? !extra.incoming : false,
@@ -1694,6 +1714,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1694
1714
  videoMuted: fromSession ? fromSession.isVideoMuted() : false,
1695
1715
  recording: fromSession ? fromSession.isRecording() : false,
1696
1716
  recordingPaused: false, // @TODO
1717
+ sipSession,
1697
1718
  ...extra,
1698
1719
  });
1699
1720
 
@@ -0,0 +1,7 @@
1
+ /* @flow */
2
+ export default class SFUNotAvailableError extends Error {
3
+ constructor(message: string = 'Sorry your user is not configured to support video conference') {
4
+ super(message);
5
+ this.name = 'SFUNotAvailableError';
6
+ }
7
+ }
package/src/index.js CHANGED
@@ -9,6 +9,7 @@ import IssueReporter from './service/IssueReporter';
9
9
  // Domain
10
10
  import BadResponse from './domain/BadResponse';
11
11
  import ServerError from './domain/ServerError';
12
+ import SFUNotAvailableError from './domain/SFUNotAvailableError';
12
13
  import Call from './domain/Call';
13
14
  import CallLog from './domain/CallLog';
14
15
  import Recording from './domain/Recording';
@@ -95,6 +96,7 @@ export default {
95
96
  WazoWebSocketClient: WebSocketClient,
96
97
  BadResponse,
97
98
  ServerError,
99
+ SFUNotAvailableError,
98
100
  Call,
99
101
  CallSession,
100
102
  CTIPhone,
@@ -62,11 +62,16 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
62
62
 
63
63
  // $FlowFixMe
64
64
  setRemoteSessionDescription(sessionDescription: RTCSessionDescriptionInit): Promise<void> {
65
- const result = super.setRemoteSessionDescription(sessionDescription);
65
+ try {
66
+ const result = super.setRemoteSessionDescription(sessionDescription);
66
67
 
67
- this.eventEmitter.emit('setDescription', sessionDescription);
68
+ this.eventEmitter.emit('setDescription', sessionDescription);
68
69
 
69
- return result;
70
+ return result;
71
+ } catch (error) {
72
+ this.logger.error('SessionDescriptionHandler.setRemoteSessionDescription error', error);
73
+ throw error;
74
+ }
70
75
  }
71
76
 
72
77
  // Overridden to avoid to fix ice-candidates missing in the SDP in react-native and chrome canary.
@@ -14,6 +14,7 @@ import IssueReporter from '../service/IssueReporter';
14
14
  import Emitter from '../utils/Emitter';
15
15
 
16
16
  import Wazo from './index';
17
+ import SFUNotAvailableError from '../domain/SFUNotAvailableError';
17
18
 
18
19
  const logger = IssueReporter.loggerFor('simple-phone');
19
20
  const sipLogger = IssueReporter.loggerFor('sip.js');
@@ -397,7 +398,7 @@ class Phone extends Emitter {
397
398
 
398
399
  checkSfu() {
399
400
  if (!this.hasSfu()) {
400
- throw new Error('Sorry your user is not configured to support video conference');
401
+ throw new SFUNotAvailableError();
401
402
  }
402
403
  }
403
404
 
@@ -15,6 +15,7 @@ import { CanceledCallError } from '../web-rtc-client';
15
15
 
16
16
  import BadResponse from '../domain/BadResponse';
17
17
  import ServerError from '../domain/ServerError';
18
+ import SFUNotAvailableError from '../domain/SFUNotAvailableError';
18
19
  import Call from '../domain/Call';
19
20
  import CallLog from '../domain/CallLog';
20
21
  import Recording from '../domain/Recording';
@@ -101,6 +102,7 @@ const Wazo = {
101
102
  InvalidSubscription,
102
103
  InvalidAuthorization,
103
104
  CanceledCallError,
105
+ SFUNotAvailableError,
104
106
  };
105
107
 
106
108
  if (window) {
@@ -25,7 +25,7 @@ const logger = IssueReporter ? IssueReporter.loggerFor('api') : console;
25
25
 
26
26
  // Use a function here to be able to mock it in tests
27
27
  export const realFetch = () => {
28
- if (typeof document !== 'undefined') {
28
+ if (typeof document !== 'undefined' && window.fetch) {
29
29
  // Browser
30
30
  return window.fetch;
31
31
  }
@@ -453,7 +453,7 @@ export default class WebRTCClient extends Emitter {
453
453
  }
454
454
 
455
455
  call(number: string, enableVideo?: boolean, audioOnly: boolean = false, conference: boolean = false): Session {
456
- logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
456
+ logger.info('sdk webrtc creating call', { number, enableVideo, audioOnly, conference });
457
457
  const inviterOptions: Object = {
458
458
  sessionDescriptionHandlerOptionsReInvite: {
459
459
  conference,
@@ -1529,6 +1529,7 @@ export default class WebRTCClient extends Emitter {
1529
1529
  const screenSharing = constraints && 'screen' in constraints ? constraints.screen : false;
1530
1530
  const isDesktop = constraints && 'desktop' in constraints ? constraints.desktop : false;
1531
1531
  const withAudio = constraints && 'audio' in constraints ? constraints.audio : true;
1532
+ const mandatoryVideo = constraints && typeof constraints.video === 'object' ? constraints.video.mandatory : {};
1532
1533
 
1533
1534
  logger.info('Retrieving media a configuration', { enableVideo, screenSharing, isDesktop, withAudio, constraints });
1534
1535
 
@@ -1536,7 +1537,8 @@ export default class WebRTCClient extends Emitter {
1536
1537
  constraints: {
1537
1538
  // Exact constraint are not supported with `getDisplayMedia` and we must have a video=false in desktop screenshare
1538
1539
  audio: screenSharing ? !isDesktop : (withAudio ? this._getAudioConstraints() : false),
1539
- video: screenSharing ? (isDesktop ? ({ mandatory: { chromeMediaSource: 'desktop' } }) : { cursor: 'always' })
1540
+ video: screenSharing ? (isDesktop
1541
+ ? ({ mandatory: { chromeMediaSource: 'desktop', ...(mandatoryVideo || {}) } }) : { cursor: 'always' })
1540
1542
  : this._getVideoConstraints(enableVideo),
1541
1543
  screen: screenSharing,
1542
1544
  desktop: isDesktop,
@@ -1871,12 +1873,14 @@ export default class WebRTCClient extends Emitter {
1871
1873
 
1872
1874
  session.sessionDescriptionHandler.remoteMediaStream.onaddtrack = onTrack;
1873
1875
 
1874
- pc.oniceconnectionstatechange = () => {
1875
- logger.info('on ice connection state changed', { state: pc.iceConnectionState });
1876
- if (pc.iceConnectionState === 'disconnected') {
1877
- this.eventEmitter.emit(ON_DISCONNECTED);
1878
- }
1879
- };
1876
+ if (pc) {
1877
+ pc.oniceconnectionstatechange = () => {
1878
+ logger.info('on ice connection state changed', { state: pc.iceConnectionState });
1879
+ if (pc.iceConnectionState === 'disconnected') {
1880
+ this.eventEmitter.emit(ON_DISCONNECTED);
1881
+ }
1882
+ };
1883
+ }
1880
1884
 
1881
1885
  if (withEvent) {
1882
1886
  this.eventEmitter.emit(ACCEPTED, session, sessionDialog);
@@ -2086,13 +2090,17 @@ export default class WebRTCClient extends Emitter {
2086
2090
  const nbStats = this.sessionNetworkStats[sessionId].length;
2087
2091
  const lastNetworkStats = this.sessionNetworkStats[sessionId][nbStats - 1];
2088
2092
  const lastAudioSent = lastNetworkStats ? lastNetworkStats.audioBytesSent : 0;
2093
+ const lastAudioContentSent = lastNetworkStats ? lastNetworkStats.audioContentSent : 0;
2089
2094
  const lastVideoSent = lastNetworkStats ? lastNetworkStats.videoBytesSent : 0;
2090
2095
  const lastAudioReceived = lastNetworkStats ? lastNetworkStats.audioBytesReceived : 0;
2096
+ const lastAudioContentReceived = lastNetworkStats ? lastNetworkStats.audioContentReceived : 0;
2091
2097
  const lastVideoReceived = lastNetworkStats ? lastNetworkStats.videoBytesReceived : 0;
2092
2098
  const lastTransportSent = lastNetworkStats ? lastNetworkStats.transportSent : 0;
2093
2099
  const lastTransportReceived = lastNetworkStats ? lastNetworkStats.transportReceived : 0;
2094
- let audioBytesSent = 0;
2095
- let audioBytesReceived = 0;
2100
+ let audioBytesSent = 0; // content + header
2101
+ let audioBytesReceived = 0; // content + header
2102
+ let audioContentSent = 0; // useful to detect blank call
2103
+ let audioContentReceived = 0;
2096
2104
  let videoBytesSent = 0;
2097
2105
  let videoBytesReceived = 0;
2098
2106
  let transportSent = 0;
@@ -2102,6 +2110,7 @@ export default class WebRTCClient extends Emitter {
2102
2110
  stats.forEach(report => {
2103
2111
  if (report.type === 'outbound-rtp' && report.kind === 'audio') {
2104
2112
  audioBytesSent += Number(report.bytesSent) + Number(report.headerBytesSent);
2113
+ audioContentSent += Number(report.bytesSent);
2105
2114
  }
2106
2115
  if (report.type === 'remote-outbound-rtp' && report.kind === 'audio') {
2107
2116
  audioBytesSent += Number(report.bytesSent);
@@ -2113,6 +2122,7 @@ export default class WebRTCClient extends Emitter {
2113
2122
  packetsLost += Number(report.packetsLost);
2114
2123
  networkStats.packetsReceived = Number(report.packetsReceived);
2115
2124
  audioBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
2125
+ audioContentReceived += Number(report.bytesReceived);
2116
2126
  }
2117
2127
  if (report.type === 'inbound-rtp' && report.kind === 'video') {
2118
2128
  videoBytesReceived += Number(report.bytesReceived) + Number(report.headerBytesReceived);
@@ -2141,10 +2151,17 @@ export default class WebRTCClient extends Emitter {
2141
2151
  });
2142
2152
 
2143
2153
  networkStats.packetsLost = packetsLost;
2154
+
2144
2155
  networkStats.totalAudioBytesSent = audioBytesSent;
2145
2156
  networkStats.audioBytesSent = audioBytesSent - lastAudioSent;
2146
2157
  networkStats.totalAudioBytesReceived = audioBytesReceived - lastAudioReceived;
2147
2158
  networkStats.audioBytesReceived = audioBytesReceived;
2159
+
2160
+ networkStats.totalAudioContentSent = audioContentSent;
2161
+ networkStats.audioContentSent = audioContentSent - lastAudioContentSent;
2162
+ networkStats.totalAudioBytesReceived = audioContentReceived - lastAudioContentReceived;
2163
+ networkStats.audioContentReceived = audioContentReceived;
2164
+
2148
2165
  networkStats.totalVideoBytesSent = videoBytesSent;
2149
2166
  networkStats.videoBytesSent = videoBytesSent - lastVideoSent;
2150
2167
  networkStats.totalVideoBytesReceived = videoBytesReceived;