@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
@@ -5353,6 +5353,7 @@ const MAX_REGISTER_TRIES = 10;
5353
5353
 
5354
5354
 
5355
5355
 
5356
+
5356
5357
 
5357
5358
 
5358
5359
 
@@ -6969,6 +6970,13 @@ class WebRTCClient extends Emitter {
6969
6970
  }
6970
6971
 
6971
6972
  _createWebRTCConfiguration(configOverrides = {}) {
6973
+ let { host } = this.config;
6974
+ let port = this.config.port || 443;
6975
+
6976
+ if (this.config.websocketSip) {
6977
+ [host, port = 443] = this.config.websocketSip.split(':');
6978
+ }
6979
+
6972
6980
  const config = {
6973
6981
  authorizationUsername: this.config.authorizationUser,
6974
6982
  authorizationPassword: this.config.password,
@@ -7004,7 +7012,7 @@ class WebRTCClient extends Emitter {
7004
7012
  },
7005
7013
  transportOptions: {
7006
7014
  traceSip: configOverrides.traceSip || false,
7007
- wsServers: `wss://${this.config.host}:${this.config.port || 443}/api/asterisk/ws`,
7015
+ wsServers: `wss://${host}:${port}/api/asterisk/ws`,
7008
7016
  },
7009
7017
  sessionDescriptionHandlerFactoryOptions: {
7010
7018
  modifiers: [replaceLocalIpModifier],
@@ -5353,6 +5353,7 @@ const MAX_REGISTER_TRIES = 10;
5353
5353
 
5354
5354
 
5355
5355
 
5356
+
5356
5357
 
5357
5358
 
5358
5359
 
@@ -6969,6 +6970,13 @@ class WebRTCClient extends Emitter {
6969
6970
  }
6970
6971
 
6971
6972
  _createWebRTCConfiguration(configOverrides = {}) {
6973
+ let { host } = this.config;
6974
+ let port = this.config.port || 443;
6975
+
6976
+ if (this.config.websocketSip) {
6977
+ [host, port = 443] = this.config.websocketSip.split(':');
6978
+ }
6979
+
6972
6980
  const config = {
6973
6981
  authorizationUsername: this.config.authorizationUser,
6974
6982
  authorizationPassword: this.config.password,
@@ -7004,7 +7012,7 @@ class WebRTCClient extends Emitter {
7004
7012
  },
7005
7013
  transportOptions: {
7006
7014
  traceSip: configOverrides.traceSip || false,
7007
- wsServers: `wss://${this.config.host}:${this.config.port || 443}/api/asterisk/ws`,
7015
+ wsServers: `wss://${host}:${port}/api/asterisk/ws`,
7008
7016
  },
7009
7017
  sessionDescriptionHandlerFactoryOptions: {
7010
7018
  modifiers: [replaceLocalIpModifier],
@@ -34,13 +34,16 @@ var updateFrom = (instance , from ) => {
34
34
 
35
35
 
36
36
 
37
+
37
38
 
38
39
 
39
40
 
40
41
 
41
42
 
43
+
42
44
 
43
45
 
46
+
44
47
 
45
48
 
46
49
 
@@ -57,6 +60,7 @@ var updateFrom = (instance , from ) => {
57
60
 
58
61
 
59
62
 
63
+
60
64
 
61
65
 
62
66
  class CallSession {
@@ -76,10 +80,14 @@ class CallSession {
76
80
 
77
81
 
78
82
 
79
-
83
+
84
+
85
+ // = creationTime
80
86
 
81
87
 
82
88
 
89
+
90
+
83
91
 
84
92
 
85
93
 
@@ -115,6 +123,8 @@ class CallSession {
115
123
 
116
124
 
117
125
 
126
+
127
+
118
128
 
119
129
  constructor({
120
130
  answered,
@@ -128,6 +138,8 @@ class CallSession {
128
138
  paused,
129
139
  ringing,
130
140
  startTime,
141
+ creationTime,
142
+ endTime,
131
143
  cameraEnabled,
132
144
  dialedExtension,
133
145
  sipCallId,
@@ -140,12 +152,16 @@ class CallSession {
140
152
  recording,
141
153
  recordingPaused,
142
154
  videoRemotelyDowngraded,
155
+ sipSession,
156
+ answerTime,
143
157
  } ) {
144
158
  this.callId = callId;
145
159
  this.sipCallId = sipCallId;
146
160
  this.displayName = displayName;
147
161
  this.number = number;
162
+ this.creationTime = creationTime;
148
163
  this.startTime = startTime;
164
+ this.endTime = endTime;
149
165
  this.isCaller = isCaller;
150
166
  this.answered = answered;
151
167
  this.answeredBySystem = answeredBySystem;
@@ -164,6 +180,8 @@ class CallSession {
164
180
  this.recording = recording || false;
165
181
  this.recordingPaused = recordingPaused || false;
166
182
  this.videoRemotelyDowngraded = videoRemotelyDowngraded;
183
+ this.sipSession = sipSession;
184
+ this.answerTime = answerTime || this.answerTime;
167
185
 
168
186
  // Useful to compare instead of instanceof with minified code
169
187
  this.type = 'CallSession';
@@ -194,7 +212,7 @@ class CallSession {
194
212
  }
195
213
 
196
214
  answer() {
197
- this.answered = true;
215
+ this.answerTime = new Date();
198
216
  }
199
217
 
200
218
  systemAnswer() {
@@ -350,6 +368,15 @@ class CallSession {
350
368
  return newFrom(callSession, CallSession);
351
369
  }
352
370
 
371
+ // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
372
+ set answered(value ) {
373
+ this.answerTime = value ? this.answerTime || new Date() : null;
374
+ }
375
+
376
+ get answered() {
377
+ return !!this.answerTime;
378
+ }
379
+
353
380
  static parseCall(call ) {
354
381
  return new CallSession({
355
382
  callId: call.id,
@@ -1715,13 +1715,16 @@ var updateFrom = (instance , from ) => {
1715
1715
 
1716
1716
 
1717
1717
 
1718
+
1718
1719
 
1719
1720
 
1720
1721
 
1721
1722
 
1722
1723
 
1724
+
1723
1725
 
1724
1726
 
1727
+
1725
1728
 
1726
1729
 
1727
1730
 
@@ -1738,6 +1741,7 @@ var updateFrom = (instance , from ) => {
1738
1741
 
1739
1742
 
1740
1743
 
1744
+
1741
1745
 
1742
1746
 
1743
1747
  class CallSession {
@@ -1757,10 +1761,14 @@ class CallSession {
1757
1761
 
1758
1762
 
1759
1763
 
1760
-
1764
+
1765
+
1766
+ // = creationTime
1761
1767
 
1762
1768
 
1763
1769
 
1770
+
1771
+
1764
1772
 
1765
1773
 
1766
1774
 
@@ -1796,6 +1804,8 @@ class CallSession {
1796
1804
 
1797
1805
 
1798
1806
 
1807
+
1808
+
1799
1809
 
1800
1810
  constructor({
1801
1811
  answered,
@@ -1809,6 +1819,8 @@ class CallSession {
1809
1819
  paused,
1810
1820
  ringing,
1811
1821
  startTime,
1822
+ creationTime,
1823
+ endTime,
1812
1824
  cameraEnabled,
1813
1825
  dialedExtension,
1814
1826
  sipCallId,
@@ -1821,12 +1833,16 @@ class CallSession {
1821
1833
  recording,
1822
1834
  recordingPaused,
1823
1835
  videoRemotelyDowngraded,
1836
+ sipSession,
1837
+ answerTime,
1824
1838
  } ) {
1825
1839
  this.callId = callId;
1826
1840
  this.sipCallId = sipCallId;
1827
1841
  this.displayName = displayName;
1828
1842
  this.number = number;
1843
+ this.creationTime = creationTime;
1829
1844
  this.startTime = startTime;
1845
+ this.endTime = endTime;
1830
1846
  this.isCaller = isCaller;
1831
1847
  this.answered = answered;
1832
1848
  this.answeredBySystem = answeredBySystem;
@@ -1845,6 +1861,8 @@ class CallSession {
1845
1861
  this.recording = recording || false;
1846
1862
  this.recordingPaused = recordingPaused || false;
1847
1863
  this.videoRemotelyDowngraded = videoRemotelyDowngraded;
1864
+ this.sipSession = sipSession;
1865
+ this.answerTime = answerTime || this.answerTime;
1848
1866
 
1849
1867
  // Useful to compare instead of instanceof with minified code
1850
1868
  this.type = 'CallSession';
@@ -1875,7 +1893,7 @@ class CallSession {
1875
1893
  }
1876
1894
 
1877
1895
  answer() {
1878
- this.answered = true;
1896
+ this.answerTime = new Date();
1879
1897
  }
1880
1898
 
1881
1899
  systemAnswer() {
@@ -2031,6 +2049,15 @@ class CallSession {
2031
2049
  return newFrom(callSession, CallSession);
2032
2050
  }
2033
2051
 
2052
+ // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
2053
+ set answered(value ) {
2054
+ this.answerTime = value ? this.answerTime || new Date() : null;
2055
+ }
2056
+
2057
+ get answered() {
2058
+ return !!this.answerTime;
2059
+ }
2060
+
2034
2061
  static parseCall(call ) {
2035
2062
  return new CallSession({
2036
2063
  callId: call.id,
@@ -63,13 +63,16 @@ var updateFrom = (instance , from ) => {
63
63
 
64
64
 
65
65
 
66
+
66
67
 
67
68
 
68
69
 
69
70
 
70
71
 
72
+
71
73
 
72
74
 
75
+
73
76
 
74
77
 
75
78
 
@@ -86,6 +89,7 @@ var updateFrom = (instance , from ) => {
86
89
 
87
90
 
88
91
 
92
+
89
93
 
90
94
 
91
95
  class CallSession {
@@ -105,10 +109,14 @@ class CallSession {
105
109
 
106
110
 
107
111
 
108
-
112
+
113
+
114
+ // = creationTime
109
115
 
110
116
 
111
117
 
118
+
119
+
112
120
 
113
121
 
114
122
 
@@ -144,6 +152,8 @@ class CallSession {
144
152
 
145
153
 
146
154
 
155
+
156
+
147
157
 
148
158
  constructor({
149
159
  answered,
@@ -157,6 +167,8 @@ class CallSession {
157
167
  paused,
158
168
  ringing,
159
169
  startTime,
170
+ creationTime,
171
+ endTime,
160
172
  cameraEnabled,
161
173
  dialedExtension,
162
174
  sipCallId,
@@ -169,12 +181,16 @@ class CallSession {
169
181
  recording,
170
182
  recordingPaused,
171
183
  videoRemotelyDowngraded,
184
+ sipSession,
185
+ answerTime,
172
186
  } ) {
173
187
  this.callId = callId;
174
188
  this.sipCallId = sipCallId;
175
189
  this.displayName = displayName;
176
190
  this.number = number;
191
+ this.creationTime = creationTime;
177
192
  this.startTime = startTime;
193
+ this.endTime = endTime;
178
194
  this.isCaller = isCaller;
179
195
  this.answered = answered;
180
196
  this.answeredBySystem = answeredBySystem;
@@ -193,6 +209,8 @@ class CallSession {
193
209
  this.recording = recording || false;
194
210
  this.recordingPaused = recordingPaused || false;
195
211
  this.videoRemotelyDowngraded = videoRemotelyDowngraded;
212
+ this.sipSession = sipSession;
213
+ this.answerTime = answerTime || this.answerTime;
196
214
 
197
215
  // Useful to compare instead of instanceof with minified code
198
216
  this.type = 'CallSession';
@@ -223,7 +241,7 @@ class CallSession {
223
241
  }
224
242
 
225
243
  answer() {
226
- this.answered = true;
244
+ this.answerTime = new Date();
227
245
  }
228
246
 
229
247
  systemAnswer() {
@@ -379,6 +397,15 @@ class CallSession {
379
397
  return newFrom(callSession, CallSession);
380
398
  }
381
399
 
400
+ // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
401
+ set answered(value ) {
402
+ this.answerTime = value ? this.answerTime || new Date() : null;
403
+ }
404
+
405
+ get answered() {
406
+ return !!this.answerTime;
407
+ }
408
+
382
409
  static parseCall(call ) {
383
410
  return new CallSession({
384
411
  callId: call.id,
@@ -887,6 +914,7 @@ const ON_CAMERA_DISABLED = 'onCameraDisabled';
887
914
  const ON_CAMERA_RESUMED = 'onCameraResumed';
888
915
  const ON_CALL_CANCELED = 'onCallCanceled';
889
916
  const ON_CALL_FAILED = 'onCallFailed';
917
+ const ON_CALL_REJECTED = 'onCallRejected';
890
918
  const ON_CALL_ENDED = 'onCallEnded';
891
919
  const ON_CALL_ENDING = 'onCallEnding';
892
920
  const ON_MESSAGE = 'onMessage';
@@ -931,6 +959,7 @@ const events = [
931
959
  ON_CAMERA_DISABLED,
932
960
  ON_CALL_FAILED,
933
961
  ON_CALL_ENDED,
962
+ ON_CALL_REJECTED,
934
963
  ON_MESSAGE,
935
964
  ON_REINVITE,
936
965
  ON_TRACK,
@@ -1287,6 +1316,7 @@ class WebRTCPhone extends Emitter {
1287
1316
 
1288
1317
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
1289
1318
  const callSession = this._createCallSession(sipSession);
1319
+ callSession.endTime = new Date();
1290
1320
  const wasCurrentSession = this._onCallTerminated(sipSession);
1291
1321
 
1292
1322
  return this.eventEmitter.emit(ON_CALL_ENDED, callSession, wasCurrentSession);
@@ -1482,6 +1512,8 @@ class WebRTCPhone extends Emitter {
1482
1512
  this.removeIncomingSessions(sipSessionId);
1483
1513
  }
1484
1514
 
1515
+ callSession.answerTime = new Date();
1516
+ this._updateCallSession(callSession);
1485
1517
  this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
1486
1518
 
1487
1519
  return callSession;
@@ -1697,6 +1729,8 @@ class WebRTCPhone extends Emitter {
1697
1729
  }
1698
1730
 
1699
1731
  this.shouldSendReinvite = false;
1732
+ callSession.answerTime = new Date();
1733
+ this._updateCallSession(callSession);
1700
1734
  this.acceptedSessions[callSession.getId()] = true;
1701
1735
 
1702
1736
  this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
@@ -1796,7 +1830,7 @@ class WebRTCPhone extends Emitter {
1796
1830
  // Hold current session if different from the current one (we don't want 2 sessions active at the same time).
1797
1831
  if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
1798
1832
  logger.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
1799
- this.holdSipSession(this.currentSipSession, callSession);
1833
+ this.holdSipSession(this.currentSipSession, this.currentCallSession);
1800
1834
  }
1801
1835
 
1802
1836
  const promise = this.unholdSipSession(sipSession, callSession, withEvent, isConference);
@@ -2006,6 +2040,8 @@ class WebRTCPhone extends Emitter {
2006
2040
  return Promise.resolve(null);
2007
2041
  }
2008
2042
  const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
2043
+ callSession.creationTime = new Date();
2044
+ this._updateCallSession(callSession);
2009
2045
 
2010
2046
  this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
2011
2047
 
@@ -2284,6 +2320,9 @@ class WebRTCPhone extends Emitter {
2284
2320
  callSession);
2285
2321
  }
2286
2322
 
2323
+ callSession.creationTime = new Date();
2324
+ this._updateCallSession(callSession);
2325
+
2287
2326
  this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
2288
2327
  });
2289
2328
 
@@ -2323,6 +2362,15 @@ class WebRTCPhone extends Emitter {
2323
2362
  this.eventEmitter.emit(ON_CALL_ERROR, e);
2324
2363
  });
2325
2364
 
2365
+ this.client.on(this.client.REJECTED, session => {
2366
+ logger.info('WebRTC call rejected', session.id);
2367
+ const callSession = this._createCallSession(session);
2368
+ callSession.endTime = new Date();
2369
+ this._updateCallSession(callSession);
2370
+
2371
+ this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
2372
+ });
2373
+
2326
2374
  this.client.on(this.client.UNREGISTERED, () => {
2327
2375
  logger.info('WebRTC unregistered');
2328
2376
  this.eventEmitter.emit(ON_UNREGISTERED);
@@ -2535,6 +2583,7 @@ class WebRTCPhone extends Emitter {
2535
2583
  const number = identity ? identity.uri._normal.user : null;
2536
2584
  const { state } = sipSession || {};
2537
2585
  const sessionId = this.getSipSessionId(sipSession);
2586
+ fromSession = fromSession || this.callSessions[sessionId];
2538
2587
 
2539
2588
  const callSession = new CallSession({
2540
2589
  callId: fromSession && fromSession.callId,
@@ -2542,6 +2591,9 @@ class WebRTCPhone extends Emitter {
2542
2591
  sipStatus: state,
2543
2592
  displayName: identity ? identity.displayName || number : number,
2544
2593
  startTime: fromSession ? fromSession.startTime : new Date(),
2594
+ creationTime: fromSession ? fromSession.creationTime : null,
2595
+ answerTime: fromSession ? fromSession.answerTime : null,
2596
+ endTime: fromSession ? fromSession.endTime : null,
2545
2597
  answered: state === sessionState.SessionState.Established,
2546
2598
  paused: this.client.isCallHeld(sipSession),
2547
2599
  isCaller: 'incoming' in extra ? !extra.incoming : false,
@@ -2552,6 +2604,7 @@ class WebRTCPhone extends Emitter {
2552
2604
  videoMuted: fromSession ? fromSession.isVideoMuted() : false,
2553
2605
  recording: fromSession ? fromSession.isRecording() : false,
2554
2606
  recordingPaused: false, // @TODO
2607
+ sipSession,
2555
2608
  ...extra,
2556
2609
  });
2557
2610
 
@@ -2575,6 +2628,7 @@ exports.ON_CALL_HELD = ON_CALL_HELD;
2575
2628
  exports.ON_CALL_INCOMING = ON_CALL_INCOMING;
2576
2629
  exports.ON_CALL_MUTED = ON_CALL_MUTED;
2577
2630
  exports.ON_CALL_OUTGOING = ON_CALL_OUTGOING;
2631
+ exports.ON_CALL_REJECTED = ON_CALL_REJECTED;
2578
2632
  exports.ON_CALL_RESUMED = ON_CALL_RESUMED;
2579
2633
  exports.ON_CALL_UNHELD = ON_CALL_UNHELD;
2580
2634
  exports.ON_CALL_UNMUTED = ON_CALL_UNMUTED;
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ /* */
4
+ class SFUNotAvailableError extends Error {
5
+ constructor(message = 'Sorry your user is not configured to support video conference') {
6
+ super(message);
7
+ this.name = 'SFUNotAvailableError';
8
+ }
9
+ }
10
+
11
+ module.exports = SFUNotAvailableError;
@@ -34,13 +34,16 @@ var updateFrom = (instance , from ) => {
34
34
 
35
35
 
36
36
 
37
+
37
38
 
38
39
 
39
40
 
40
41
 
41
42
 
43
+
42
44
 
43
45
 
46
+
44
47
 
45
48
 
46
49
 
@@ -57,6 +60,7 @@ var updateFrom = (instance , from ) => {
57
60
 
58
61
 
59
62
 
63
+
60
64
 
61
65
 
62
66
  class CallSession {
@@ -76,10 +80,14 @@ class CallSession {
76
80
 
77
81
 
78
82
 
79
-
83
+
84
+
85
+ // = creationTime
80
86
 
81
87
 
82
88
 
89
+
90
+
83
91
 
84
92
 
85
93
 
@@ -115,6 +123,8 @@ class CallSession {
115
123
 
116
124
 
117
125
 
126
+
127
+
118
128
 
119
129
  constructor({
120
130
  answered,
@@ -128,6 +138,8 @@ class CallSession {
128
138
  paused,
129
139
  ringing,
130
140
  startTime,
141
+ creationTime,
142
+ endTime,
131
143
  cameraEnabled,
132
144
  dialedExtension,
133
145
  sipCallId,
@@ -140,12 +152,16 @@ class CallSession {
140
152
  recording,
141
153
  recordingPaused,
142
154
  videoRemotelyDowngraded,
155
+ sipSession,
156
+ answerTime,
143
157
  } ) {
144
158
  this.callId = callId;
145
159
  this.sipCallId = sipCallId;
146
160
  this.displayName = displayName;
147
161
  this.number = number;
162
+ this.creationTime = creationTime;
148
163
  this.startTime = startTime;
164
+ this.endTime = endTime;
149
165
  this.isCaller = isCaller;
150
166
  this.answered = answered;
151
167
  this.answeredBySystem = answeredBySystem;
@@ -164,6 +180,8 @@ class CallSession {
164
180
  this.recording = recording || false;
165
181
  this.recordingPaused = recordingPaused || false;
166
182
  this.videoRemotelyDowngraded = videoRemotelyDowngraded;
183
+ this.sipSession = sipSession;
184
+ this.answerTime = answerTime || this.answerTime;
167
185
 
168
186
  // Useful to compare instead of instanceof with minified code
169
187
  this.type = 'CallSession';
@@ -194,7 +212,7 @@ class CallSession {
194
212
  }
195
213
 
196
214
  answer() {
197
- this.answered = true;
215
+ this.answerTime = new Date();
198
216
  }
199
217
 
200
218
  systemAnswer() {
@@ -350,6 +368,15 @@ class CallSession {
350
368
  return newFrom(callSession, CallSession);
351
369
  }
352
370
 
371
+ // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
372
+ set answered(value ) {
373
+ this.answerTime = value ? this.answerTime || new Date() : null;
374
+ }
375
+
376
+ get answered() {
377
+ return !!this.answerTime;
378
+ }
379
+
353
380
  static parseCall(call ) {
354
381
  return new CallSession({
355
382
  callId: call.id,
@@ -412,4 +439,21 @@ describe('CallSession domain', () => {
412
439
  expect(cs1.is(cs2)).toBeTruthy();
413
440
  expect(cs2.is(cs1)).toBeTruthy();
414
441
  });
442
+
443
+ it('should set answerTime when setting answered', () => {
444
+ const cs1 = new CallSession({});
445
+ cs1.answered = true;
446
+
447
+ const cs2 = new CallSession({});
448
+ cs2.answer();
449
+
450
+ const cs3 = new CallSession({ answered: true });
451
+
452
+ expect(cs1.answered).toBeTruthy();
453
+ expect(cs1.answerTime).not.toBeNull();
454
+ expect(cs2.answered).toBeTruthy();
455
+ expect(cs2.answerTime).not.toBeNull();
456
+ expect(cs3.answered).toBeTruthy();
457
+ expect(cs3.answerTime).not.toBeNull();
458
+ });
415
459
  });