@wazo/sdk 0.37.27 → 0.37.31

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 (63) hide show
  1. package/README.md +3 -2
  2. package/dist/wazo-sdk.js +4 -4
  3. package/esm/__tests__/web-rtc-client.test.js +9 -1
  4. package/esm/checker/Checker.js +9 -1
  5. package/esm/checker/checks/index.js +9 -1
  6. package/esm/checker/checks/webrtc-transport.js +9 -1
  7. package/esm/checker/checks/webrtc.js +9 -1
  8. package/esm/domain/CallSession.js +29 -2
  9. package/esm/domain/Phone/CTIPhone.js +29 -2
  10. package/esm/domain/Phone/WebRTCPhone.js +57 -4
  11. package/esm/domain/SFUNotAvailableError.js +9 -0
  12. package/esm/domain/__tests__/CallSession.test.js +46 -2
  13. package/esm/domain/__tests__/IndirectTransfer.test.js +29 -2
  14. package/esm/domain/__tests__/Room.test.js +29 -2
  15. package/esm/index.js +77 -5
  16. package/esm/simple/Auth.js +76 -5
  17. package/esm/simple/Configuration.js +76 -5
  18. package/esm/simple/Phone.js +76 -5
  19. package/esm/simple/index.js +76 -5
  20. package/esm/simple/room/LocalParticipant.js +76 -5
  21. package/esm/simple/room/Participant.js +76 -5
  22. package/esm/simple/room/RemoteParticipant.js +76 -5
  23. package/esm/simple/room/Room.js +76 -5
  24. package/esm/simple/room/SipRoom.js +76 -5
  25. package/esm/simple/room/Stream.js +76 -5
  26. package/esm/simple/room/__tests__/RemoteParticipant.test.js +76 -5
  27. package/esm/simple/utils.js +76 -5
  28. package/esm/web-rtc-client.js +9 -1
  29. package/lib/__tests__/web-rtc-client.test.js +9 -1
  30. package/lib/checker/Checker.js +9 -1
  31. package/lib/checker/checks/index.js +9 -1
  32. package/lib/checker/checks/webrtc-transport.js +9 -1
  33. package/lib/checker/checks/webrtc.js +9 -1
  34. package/lib/domain/CallSession.js +29 -2
  35. package/lib/domain/Phone/CTIPhone.js +29 -2
  36. package/lib/domain/Phone/WebRTCPhone.js +57 -3
  37. package/lib/domain/SFUNotAvailableError.js +11 -0
  38. package/lib/domain/__tests__/CallSession.test.js +46 -2
  39. package/lib/domain/__tests__/IndirectTransfer.test.js +29 -2
  40. package/lib/domain/__tests__/Room.test.js +29 -2
  41. package/lib/index.js +77 -5
  42. package/lib/simple/Auth.js +76 -5
  43. package/lib/simple/Configuration.js +76 -5
  44. package/lib/simple/Phone.js +76 -5
  45. package/lib/simple/index.js +76 -5
  46. package/lib/simple/room/LocalParticipant.js +76 -5
  47. package/lib/simple/room/Participant.js +76 -5
  48. package/lib/simple/room/RemoteParticipant.js +76 -5
  49. package/lib/simple/room/Room.js +76 -5
  50. package/lib/simple/room/SipRoom.js +76 -5
  51. package/lib/simple/room/Stream.js +76 -5
  52. package/lib/simple/room/__tests__/RemoteParticipant.test.js +76 -5
  53. package/lib/simple/utils.js +76 -5
  54. package/lib/web-rtc-client.js +9 -1
  55. package/package.json +1 -1
  56. package/src/domain/CallSession.js +32 -4
  57. package/src/domain/Phone/WebRTCPhone.js +27 -1
  58. package/src/domain/SFUNotAvailableError.js +7 -0
  59. package/src/domain/__tests__/CallSession.test.js +17 -0
  60. package/src/index.js +2 -0
  61. package/src/simple/Phone.js +2 -1
  62. package/src/simple/index.js +2 -0
  63. package/src/web-rtc-client.js +9 -1
@@ -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';
@@ -7,13 +8,16 @@ import updateFrom from '../utils/update-from';
7
8
 
8
9
  type CallSessionArguments = {
9
10
  answered: boolean,
11
+ answerTime?: ?Date,
10
12
  answeredBySystem: boolean,
11
13
  call: ?Call,
12
14
  callId: string,
13
15
  callerNumber: string,
14
16
  cameraEnabled: boolean,
17
+ creationTime?: ?Date,
15
18
  dialedExtension?: string | null,
16
19
  displayName: string,
20
+ endTime?: ?Date,
17
21
  isCaller: boolean,
18
22
  muted: boolean,
19
23
  videoMuted: boolean,
@@ -30,6 +34,7 @@ type CallSessionArguments = {
30
34
  screensharing: boolean,
31
35
  recording: boolean,
32
36
  recordingPaused: boolean,
37
+ sipSession?: Session,
33
38
  };
34
39
 
35
40
  export default class CallSession {
@@ -49,11 +54,15 @@ export default class CallSession {
49
54
 
50
55
  callerNumber: string;
51
56
 
52
- startTime: number;
57
+ creationTime: ?Date;
53
58
 
54
- isCaller: boolean;
59
+ startTime: number; // = creationTime
60
+
61
+ answerTime: ?Date;
55
62
 
56
- answered: boolean;
63
+ endTime: ?Date;
64
+
65
+ isCaller: boolean;
57
66
 
58
67
  answeredBySystem: boolean;
59
68
 
@@ -89,6 +98,8 @@ export default class CallSession {
89
98
 
90
99
  recordingPaused: boolean;
91
100
 
101
+ sipSession: Session;
102
+
92
103
  constructor({
93
104
  answered,
94
105
  answeredBySystem,
@@ -101,6 +112,8 @@ export default class CallSession {
101
112
  paused,
102
113
  ringing,
103
114
  startTime,
115
+ creationTime,
116
+ endTime,
104
117
  cameraEnabled,
105
118
  dialedExtension,
106
119
  sipCallId,
@@ -113,12 +126,16 @@ export default class CallSession {
113
126
  recording,
114
127
  recordingPaused,
115
128
  videoRemotelyDowngraded,
129
+ sipSession,
130
+ answerTime,
116
131
  }: CallSessionArguments) {
117
132
  this.callId = callId;
118
133
  this.sipCallId = sipCallId;
119
134
  this.displayName = displayName;
120
135
  this.number = number;
136
+ this.creationTime = creationTime;
121
137
  this.startTime = startTime;
138
+ this.endTime = endTime;
122
139
  this.isCaller = isCaller;
123
140
  this.answered = answered;
124
141
  this.answeredBySystem = answeredBySystem;
@@ -137,6 +154,8 @@ export default class CallSession {
137
154
  this.recording = recording || false;
138
155
  this.recordingPaused = recordingPaused || false;
139
156
  this.videoRemotelyDowngraded = videoRemotelyDowngraded;
157
+ this.sipSession = sipSession;
158
+ this.answerTime = answerTime || this.answerTime;
140
159
 
141
160
  // Useful to compare instead of instanceof with minified code
142
161
  this.type = 'CallSession';
@@ -167,7 +186,7 @@ export default class CallSession {
167
186
  }
168
187
 
169
188
  answer() {
170
- this.answered = true;
189
+ this.answerTime = new Date();
171
190
  }
172
191
 
173
192
  systemAnswer() {
@@ -323,6 +342,15 @@ export default class CallSession {
323
342
  return newFrom(callSession, CallSession);
324
343
  }
325
344
 
345
+ // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
346
+ set answered(value: boolean) {
347
+ this.answerTime = value ? this.answerTime || new Date() : null;
348
+ }
349
+
350
+ get answered(): boolean {
351
+ return !!this.answerTime;
352
+ }
353
+
326
354
  static parseCall(call: Call): CallSession {
327
355
  return new CallSession({
328
356
  callId: call.id,
@@ -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,
@@ -430,6 +432,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
430
432
 
431
433
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
432
434
  const callSession = this._createCallSession(sipSession);
435
+ callSession.endTime = new Date();
433
436
  const wasCurrentSession = this._onCallTerminated(sipSession);
434
437
 
435
438
  return this.eventEmitter.emit(ON_CALL_ENDED, callSession, wasCurrentSession);
@@ -627,6 +630,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
627
630
  this.removeIncomingSessions(sipSessionId);
628
631
  }
629
632
 
633
+ callSession.answerTime = new Date();
634
+ this._updateCallSession(callSession);
630
635
  this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
631
636
 
632
637
  return callSession;
@@ -842,6 +847,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
842
847
  }
843
848
 
844
849
  this.shouldSendReinvite = false;
850
+ callSession.answerTime = new Date();
851
+ this._updateCallSession(callSession);
845
852
  this.acceptedSessions[callSession.getId()] = true;
846
853
 
847
854
  this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
@@ -941,7 +948,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
941
948
  // Hold current session if different from the current one (we don't want 2 sessions active at the same time).
942
949
  if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
943
950
  logger.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
944
- this.holdSipSession(this.currentSipSession, callSession);
951
+ this.holdSipSession(this.currentSipSession, this.currentCallSession);
945
952
  }
946
953
 
947
954
  const promise = this.unholdSipSession(sipSession, callSession, withEvent, isConference);
@@ -1151,6 +1158,8 @@ export default class WebRTCPhone extends Emitter implements Phone {
1151
1158
  return Promise.resolve(null);
1152
1159
  }
1153
1160
  const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
1161
+ callSession.creationTime = new Date();
1162
+ this._updateCallSession(callSession);
1154
1163
 
1155
1164
  this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
1156
1165
 
@@ -1429,6 +1438,9 @@ export default class WebRTCPhone extends Emitter implements Phone {
1429
1438
  callSession);
1430
1439
  }
1431
1440
 
1441
+ callSession.creationTime = new Date();
1442
+ this._updateCallSession(callSession);
1443
+
1432
1444
  this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
1433
1445
  });
1434
1446
 
@@ -1468,6 +1480,15 @@ export default class WebRTCPhone extends Emitter implements Phone {
1468
1480
  this.eventEmitter.emit(ON_CALL_ERROR, e);
1469
1481
  });
1470
1482
 
1483
+ this.client.on(this.client.REJECTED, session => {
1484
+ logger.info('WebRTC call rejected', session.id);
1485
+ const callSession = this._createCallSession(session);
1486
+ callSession.endTime = new Date();
1487
+ this._updateCallSession(callSession);
1488
+
1489
+ this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
1490
+ });
1491
+
1471
1492
  this.client.on(this.client.UNREGISTERED, () => {
1472
1493
  logger.info('WebRTC unregistered');
1473
1494
  this.eventEmitter.emit(ON_UNREGISTERED);
@@ -1682,6 +1703,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1682
1703
  const number = identity ? identity.uri._normal.user : null;
1683
1704
  const { state } = sipSession || {};
1684
1705
  const sessionId = this.getSipSessionId(sipSession);
1706
+ fromSession = fromSession || this.callSessions[sessionId];
1685
1707
 
1686
1708
  const callSession = new CallSession({
1687
1709
  callId: fromSession && fromSession.callId,
@@ -1689,6 +1711,9 @@ export default class WebRTCPhone extends Emitter implements Phone {
1689
1711
  sipStatus: state,
1690
1712
  displayName: identity ? identity.displayName || number : number,
1691
1713
  startTime: fromSession ? fromSession.startTime : new Date(),
1714
+ creationTime: fromSession ? fromSession.creationTime : null,
1715
+ answerTime: fromSession ? fromSession.answerTime : null,
1716
+ endTime: fromSession ? fromSession.endTime : null,
1692
1717
  answered: state === SessionState.Established,
1693
1718
  paused: this.client.isCallHeld(sipSession),
1694
1719
  isCaller: 'incoming' in extra ? !extra.incoming : false,
@@ -1699,6 +1724,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1699
1724
  videoMuted: fromSession ? fromSession.isVideoMuted() : false,
1700
1725
  recording: fromSession ? fromSession.isRecording() : false,
1701
1726
  recordingPaused: false, // @TODO
1727
+ sipSession,
1702
1728
  ...extra,
1703
1729
  });
1704
1730
 
@@ -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
+ }
@@ -37,4 +37,21 @@ describe('CallSession domain', () => {
37
37
  expect(cs1.is(cs2)).toBeTruthy();
38
38
  expect(cs2.is(cs1)).toBeTruthy();
39
39
  });
40
+
41
+ it('should set answerTime when setting answered', () => {
42
+ const cs1 = new CallSession({});
43
+ cs1.answered = true;
44
+
45
+ const cs2 = new CallSession({});
46
+ cs2.answer();
47
+
48
+ const cs3 = new CallSession({ answered: true });
49
+
50
+ expect(cs1.answered).toBeTruthy();
51
+ expect(cs1.answerTime).not.toBeNull();
52
+ expect(cs2.answered).toBeTruthy();
53
+ expect(cs2.answerTime).not.toBeNull();
54
+ expect(cs3.answered).toBeTruthy();
55
+ expect(cs3.answerTime).not.toBeNull();
56
+ });
40
57
  });
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,
@@ -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) {
@@ -87,6 +87,7 @@ type WebRtcConfig = {
87
87
  displayName: string,
88
88
  host: string,
89
89
  port?: number,
90
+ websocketSip?: ?string,
90
91
  authorizationUser: ?string,
91
92
  password: ?string,
92
93
  uri: string,
@@ -1703,6 +1704,13 @@ export default class WebRTCClient extends Emitter {
1703
1704
  }
1704
1705
 
1705
1706
  _createWebRTCConfiguration(configOverrides: Object = {}) {
1707
+ let { host } = this.config;
1708
+ let port = this.config.port || 443;
1709
+
1710
+ if (this.config.websocketSip) {
1711
+ [host, port = 443] = this.config.websocketSip.split(':');
1712
+ }
1713
+
1706
1714
  const config: Object = {
1707
1715
  authorizationUsername: this.config.authorizationUser,
1708
1716
  authorizationPassword: this.config.password,
@@ -1738,7 +1746,7 @@ export default class WebRTCClient extends Emitter {
1738
1746
  },
1739
1747
  transportOptions: {
1740
1748
  traceSip: configOverrides.traceSip || false,
1741
- wsServers: `wss://${this.config.host}:${this.config.port || 443}/api/asterisk/ws`,
1749
+ wsServers: `wss://${host}:${port}/api/asterisk/ws`,
1742
1750
  },
1743
1751
  sessionDescriptionHandlerFactoryOptions: {
1744
1752
  modifiers: [replaceLocalIpModifier],