@wazo/sdk 1.0.0-alpha.1 → 1.0.0-alpha.10

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 (148) hide show
  1. package/README.md +16 -7
  2. package/dist/wazo-sdk.js +6 -6
  3. package/esm/__tests__/__voice__/call.test.js +57 -2
  4. package/esm/api/auth.js +3 -0
  5. package/esm/checker/checks/webrtc.js +2 -2
  6. package/esm/domain/CallLog.js +2 -3
  7. package/esm/domain/Phone/CTIPhone.js +2 -2
  8. package/esm/domain/Phone/WebRTCPhone.js +64 -63
  9. package/esm/index.js +3 -1
  10. package/esm/service/CallApi.js +4 -4
  11. package/esm/simple/Auth.js +13 -3
  12. package/esm/simple/Phone.js +6 -5
  13. package/esm/simple/index.js +2 -1
  14. package/esm/simple/room/Room.js +2 -2
  15. package/esm/simple/room/SipRoom.js +2 -2
  16. package/esm/state-machine/call-state-machine.js +2 -2
  17. package/esm/state-machine/softphone-state-machine.js +1 -2
  18. package/esm/state-machine/utils.js +8 -3
  19. package/esm/types/api/auth.d.ts +3 -0
  20. package/esm/types/api/auth.d.ts.map +1 -1
  21. package/esm/types/checker/checks/index.d.ts +1 -1
  22. package/esm/types/checker/checks/webrtc-transport.d.ts +2 -2
  23. package/esm/types/checker/checks/webrtc-transport.d.ts.map +1 -1
  24. package/esm/types/domain/CallLog.d.ts.map +1 -1
  25. package/esm/types/domain/CallSession.d.ts +3 -3
  26. package/esm/types/domain/CallSession.d.ts.map +1 -1
  27. package/esm/types/domain/Phone/CTIPhone.d.ts.map +1 -1
  28. package/esm/types/domain/Phone/WebRTCPhone.d.ts +22 -22
  29. package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  30. package/esm/types/domain/types.d.ts +0 -4
  31. package/esm/types/domain/types.d.ts.map +1 -1
  32. package/esm/types/index.d.ts +3 -1
  33. package/esm/types/index.d.ts.map +1 -1
  34. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
  35. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  36. package/esm/types/service/CallApi.d.ts +5 -5
  37. package/esm/types/service/CallApi.d.ts.map +1 -1
  38. package/esm/types/simple/Auth.d.ts +6 -1
  39. package/esm/types/simple/Auth.d.ts.map +1 -1
  40. package/esm/types/simple/Phone.d.ts +8 -8
  41. package/esm/types/simple/Phone.d.ts.map +1 -1
  42. package/esm/types/simple/index.d.ts +3 -1
  43. package/esm/types/simple/index.d.ts.map +1 -1
  44. package/esm/types/state-machine/softphone-state-machine.d.ts +1 -2
  45. package/esm/types/state-machine/softphone-state-machine.d.ts.map +1 -1
  46. package/esm/types/state-machine/utils.d.ts +2 -2
  47. package/esm/types/state-machine/utils.d.ts.map +1 -1
  48. package/esm/types/utils/sdp.d.ts +3 -2
  49. package/esm/types/utils/sdp.d.ts.map +1 -1
  50. package/esm/types/utils/webrtc.d.ts +1 -0
  51. package/esm/types/utils/webrtc.d.ts.map +1 -1
  52. package/esm/types/voice/call.d.ts +30 -12
  53. package/esm/types/voice/call.d.ts.map +1 -1
  54. package/esm/types/voice/softphone.d.ts +25 -13
  55. package/esm/types/voice/softphone.d.ts.map +1 -1
  56. package/esm/types/web-rtc-client.d.ts +39 -38
  57. package/esm/types/web-rtc-client.d.ts.map +1 -1
  58. package/esm/utils/sdp.js +22 -9
  59. package/esm/utils/webrtc.js +23 -3
  60. package/esm/voice/call.js +130 -38
  61. package/esm/voice/softphone.js +145 -35
  62. package/esm/web-rtc-client.js +61 -58
  63. package/lib/__tests__/__voice__/call.test.js +56 -1
  64. package/lib/api/auth.js +3 -0
  65. package/lib/checker/checks/webrtc.js +1 -1
  66. package/lib/domain/CallLog.js +2 -3
  67. package/lib/domain/Phone/CTIPhone.js +2 -2
  68. package/lib/domain/Phone/WebRTCPhone.js +63 -62
  69. package/lib/index.js +7 -3
  70. package/lib/service/CallApi.js +2 -2
  71. package/lib/simple/Auth.js +15 -3
  72. package/lib/simple/Phone.js +3 -2
  73. package/lib/simple/index.js +2 -1
  74. package/lib/simple/room/Room.js +1 -1
  75. package/lib/simple/room/SipRoom.js +1 -1
  76. package/lib/state-machine/call-state-machine.js +2 -2
  77. package/lib/state-machine/softphone-state-machine.js +1 -2
  78. package/lib/state-machine/utils.js +8 -3
  79. package/lib/types/api/auth.d.ts +3 -0
  80. package/lib/types/api/auth.d.ts.map +1 -1
  81. package/lib/types/checker/checks/index.d.ts +1 -1
  82. package/lib/types/checker/checks/webrtc-transport.d.ts +2 -2
  83. package/lib/types/checker/checks/webrtc-transport.d.ts.map +1 -1
  84. package/lib/types/domain/CallLog.d.ts.map +1 -1
  85. package/lib/types/domain/CallSession.d.ts +3 -3
  86. package/lib/types/domain/CallSession.d.ts.map +1 -1
  87. package/lib/types/domain/Phone/CTIPhone.d.ts.map +1 -1
  88. package/lib/types/domain/Phone/WebRTCPhone.d.ts +22 -22
  89. package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  90. package/lib/types/domain/types.d.ts +0 -4
  91. package/lib/types/domain/types.d.ts.map +1 -1
  92. package/lib/types/index.d.ts +3 -1
  93. package/lib/types/index.d.ts.map +1 -1
  94. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts +3 -3
  95. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  96. package/lib/types/service/CallApi.d.ts +5 -5
  97. package/lib/types/service/CallApi.d.ts.map +1 -1
  98. package/lib/types/simple/Auth.d.ts +6 -1
  99. package/lib/types/simple/Auth.d.ts.map +1 -1
  100. package/lib/types/simple/Phone.d.ts +8 -8
  101. package/lib/types/simple/Phone.d.ts.map +1 -1
  102. package/lib/types/simple/index.d.ts +3 -1
  103. package/lib/types/simple/index.d.ts.map +1 -1
  104. package/lib/types/state-machine/softphone-state-machine.d.ts +1 -2
  105. package/lib/types/state-machine/softphone-state-machine.d.ts.map +1 -1
  106. package/lib/types/state-machine/utils.d.ts +2 -2
  107. package/lib/types/state-machine/utils.d.ts.map +1 -1
  108. package/lib/types/utils/sdp.d.ts +3 -2
  109. package/lib/types/utils/sdp.d.ts.map +1 -1
  110. package/lib/types/utils/webrtc.d.ts +1 -0
  111. package/lib/types/utils/webrtc.d.ts.map +1 -1
  112. package/lib/types/voice/call.d.ts +30 -12
  113. package/lib/types/voice/call.d.ts.map +1 -1
  114. package/lib/types/voice/softphone.d.ts +25 -13
  115. package/lib/types/voice/softphone.d.ts.map +1 -1
  116. package/lib/types/web-rtc-client.d.ts +39 -38
  117. package/lib/types/web-rtc-client.d.ts.map +1 -1
  118. package/lib/utils/sdp.js +25 -10
  119. package/lib/utils/webrtc.js +24 -3
  120. package/lib/voice/call.js +131 -36
  121. package/lib/voice/softphone.js +150 -35
  122. package/lib/web-rtc-client.js +59 -57
  123. package/package.json +1 -1
  124. package/src/__tests__/__voice__/call.test.ts +63 -2
  125. package/src/api/auth.ts +5 -0
  126. package/src/checker/checks/webrtc-transport.ts +2 -2
  127. package/src/checker/checks/webrtc.ts +2 -2
  128. package/src/domain/CallLog.ts +2 -3
  129. package/src/domain/CallSession.ts +3 -3
  130. package/src/domain/Phone/CTIPhone.ts +3 -2
  131. package/src/domain/Phone/WebRTCPhone.ts +95 -93
  132. package/src/domain/types.ts +0 -5
  133. package/src/index.ts +4 -1
  134. package/src/lib/WazoSessionDescriptionHandler.ts +3 -3
  135. package/src/service/CallApi.ts +7 -7
  136. package/src/simple/Auth.ts +15 -3
  137. package/src/simple/Phone.ts +12 -11
  138. package/src/simple/index.ts +2 -1
  139. package/src/simple/room/Room.ts +3 -3
  140. package/src/simple/room/SipRoom.ts +3 -3
  141. package/src/state-machine/call-state-machine.ts +2 -2
  142. package/src/state-machine/softphone-state-machine.ts +1 -2
  143. package/src/state-machine/utils.ts +12 -5
  144. package/src/utils/sdp.ts +26 -11
  145. package/src/utils/webrtc.ts +26 -4
  146. package/src/voice/call.ts +169 -50
  147. package/src/voice/softphone.ts +180 -41
  148. package/src/web-rtc-client.ts +106 -99
package/lib/utils/sdp.js CHANGED
@@ -3,11 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.makeURI = exports.replaceLocalIpModifier = exports.getSipSessionId = exports.addIcesInAllBundles = exports.fixSdp = exports.hasAnActiveVideo = exports.activateVideoModifier = exports.deactivateVideoModifier = exports.getVideoDirection = exports.toggleVideoDirection = exports.fixBundle = exports.isSdpValid = exports.areCandidateValid = exports.parseCandidate = exports.getCandidates = exports.SIP_ID_LENGTH = void 0;
6
+ exports.getCallDisplayName = exports.getCallNumber = exports.makeURI = exports.replaceLocalIpModifier = exports.getSipCallId = exports.addIcesInAllBundles = exports.fixSdp = exports.hasAnActiveVideo = exports.activateVideoModifier = exports.deactivateVideoModifier = exports.getVideoDirection = exports.toggleVideoDirection = exports.fixBundle = exports.isSdpValid = exports.areCandidateValid = exports.parseCandidate = exports.getCandidates = void 0;
7
+ /* eslint-disable no-underscore-dangle */
7
8
  const sdp_transform_1 = __importDefault(require("sdp-transform"));
8
9
  const user_agent_1 = require("sip.js/lib/api/user-agent");
9
10
  const api_1 = require("sip.js/lib/api");
10
- exports.SIP_ID_LENGTH = 36;
11
11
  const getCandidates = (rawSdp) => {
12
12
  if (!rawSdp) {
13
13
  return [];
@@ -116,26 +116,41 @@ const addIcesInAllBundles = (sdp) => {
116
116
  return sdp_transform_1.default.write(parsedSdp);
117
117
  };
118
118
  exports.addIcesInAllBundles = addIcesInAllBundles;
119
- const getSipSessionId = (sipSession) => {
119
+ const getSipCallId = (sipSession) => {
120
120
  if (!sipSession) {
121
121
  return '';
122
122
  }
123
- const message = sipSession.message;
124
- if (message === null || message === void 0 ? void 0 : message.callId) {
125
- return message.callId.substring(0, exports.SIP_ID_LENGTH);
126
- }
127
123
  // For Inviter
128
124
  // @ts-ignore: private
129
125
  if (sipSession instanceof api_1.Inviter && sipSession.outgoingRequestMessage) {
130
126
  // @ts-ignore: private
131
- return sipSession.outgoingRequestMessage.callId.substring(0, exports.SIP_ID_LENGTH);
127
+ return sipSession.outgoingRequestMessage.callId;
132
128
  }
133
129
  // For Invitation
134
- return (sipSession.id || '').substring(0, exports.SIP_ID_LENGTH);
130
+ // @ts-ignore: private
131
+ if (sipSession instanceof api_1.Invitation && sipSession.incomingInviteRequest.message) {
132
+ // @ts-ignore: private
133
+ return sipSession.incomingInviteRequest.message.callId;
134
+ }
135
+ return sipSession.id;
135
136
  };
136
- exports.getSipSessionId = getSipSessionId;
137
+ exports.getSipCallId = getSipCallId;
137
138
  // We need to replace 0.0.0.0 to 127.0.0.1 in the sdp to avoid MOH during a createOffer.
138
139
  const replaceLocalIpModifier = (description) => Promise.resolve(Object.assign(Object.assign({}, JSON.parse(JSON.stringify(description))), { sdp: description.sdp.replace('c=IN IP4 0.0.0.0', 'c=IN IP4 127.0.0.1') }));
139
140
  exports.replaceLocalIpModifier = replaceLocalIpModifier;
140
141
  const makeURI = (target, host) => user_agent_1.UserAgent.makeURI(`sip:${target}@${host}`);
141
142
  exports.makeURI = makeURI;
143
+ const getCallNumber = (sipCall) => {
144
+ // eslint-disable-next-line
145
+ const identity = sipCall ? sipCall.remoteIdentity || sipCall.assertedIdentity : null;
146
+ // @ts-ignore: private
147
+ return identity ? identity.uri._normal.user : null;
148
+ };
149
+ exports.getCallNumber = getCallNumber;
150
+ const getCallDisplayName = (sipCall) => {
151
+ // eslint-disable-next-line
152
+ const identity = sipCall ? sipCall.remoteIdentity || sipCall.assertedIdentity : null;
153
+ const number = (0, exports.getCallNumber)(sipCall);
154
+ return identity ? identity.displayName || number : number;
155
+ };
156
+ exports.getCallDisplayName = getCallDisplayName;
@@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.fetchNetworkStats = exports.upgradeToVideo = exports.downgradeToAudio = exports.createUaOptions = exports.getStreamFromConstraints = exports.getMediaConfiguration = exports.getVideoConstraints = exports.getAudioConstraints = exports.isAudioOnly = exports.updateRemoteStream = exports.setLocalMediaStream = exports.cleanupStream = exports.toggleVideo = exports.toggleAudio = exports.getWebRtcStats = exports.sessionWantsToDoVideo = exports.hasAVideoTrack = exports.hasVideoTrack = exports.getRemoteVideoStreamFromPc = exports.getRemoteVideoStream = exports.hasARemoteVideoTrack = exports.hasRemoteVideo = exports.isVideoRemotelyHeld = exports.getRemoteTracks = exports.getLocalVideoStream = exports.hasALocalVideoTrack = exports.hasLocalVideo = exports.isVideoTrack = exports.getRemoteStream = exports.getLocalTracks = exports.getLocalStream = exports.getPeerConnection = exports.parseCandidate = exports.getIceServers = exports.isAPrivateIp = exports.isFirefox = exports.isWeb = void 0;
38
+ exports.fetchNetworkStats = exports.upgradeToVideo = exports.downgradeToAudio = exports.createUaOptions = exports.getStreamFromConstraints = exports.getMediaConfiguration = exports.getVideoConstraints = exports.getAudioConstraints = exports.isAudioOnly = exports.updateRemoteStream = exports.setLocalMediaStream = exports.cleanupStream = exports.isVideoMuted = exports.toggleVideo = exports.toggleAudio = exports.getWebRtcStats = exports.sessionWantsToDoVideo = exports.hasAVideoTrack = exports.hasVideoTrack = exports.getRemoteVideoStreamFromPc = exports.getRemoteVideoStream = exports.hasARemoteVideoTrack = exports.hasRemoteVideo = exports.isVideoRemotelyHeld = exports.getRemoteTracks = exports.getLocalVideoStream = exports.hasALocalVideoTrack = exports.hasLocalVideo = exports.isVideoTrack = exports.getRemoteStream = exports.getLocalTracks = exports.getLocalStream = exports.getPeerConnection = exports.parseCandidate = exports.getIceServers = exports.isAPrivateIp = exports.isFirefox = exports.isWeb = void 0;
39
39
  const peer_connection_configuration_default_1 = require("sip.js/lib/platform/web/session-description-handler/peer-connection-configuration-default");
40
40
  const web_1 = require("sip.js/lib/platform/web");
41
41
  const WazoSessionDescriptionHandler_1 = __importStar(require("../lib/WazoSessionDescriptionHandler"));
@@ -238,13 +238,34 @@ const toggleVideo = (sipCall, muteCamera) => {
238
238
  }
239
239
  };
240
240
  exports.toggleVideo = toggleVideo;
241
+ const isVideoMuted = (sipCall) => {
242
+ const sdh = sipCall.sessionDescriptionHandler;
243
+ const pc = sdh === null || sdh === void 0 ? void 0 : sdh.peerConnection;
244
+ if (pc === null || pc === void 0 ? void 0 : pc.getSenders) {
245
+ for (const sender of pc.getSenders()) {
246
+ if (sender && sender.track && sender.track.kind === 'video') {
247
+ return !sender.track.enabled;
248
+ }
249
+ }
250
+ }
251
+ else {
252
+ for (const stream of pc.getLocalStreams()) {
253
+ // eslint-disable-next-line no-unreachable-loop
254
+ for (const track of stream.getVideoTracks()) {
255
+ return !track.enabled;
256
+ }
257
+ }
258
+ }
259
+ return true;
260
+ };
261
+ exports.isVideoMuted = isVideoMuted;
241
262
  const cleanupStream = (stream) => {
242
263
  stream.getTracks().filter(track => track.enabled).forEach(track => track.stop());
243
264
  };
244
265
  exports.cleanupStream = cleanupStream;
245
266
  const setLocalMediaStream = (sipCall, newStream) => {
246
267
  logger.info('setting local media stream', {
247
- id: sipCall.id,
268
+ id: (0, sdp_1.getSipCallId)(sipCall),
248
269
  tracks: newStream ? newStream.getTracks() : null,
249
270
  });
250
271
  if (sipCall.sessionDescriptionHandler) {
@@ -258,7 +279,7 @@ const updateRemoteStream = (sipCall, allTracks = true) => {
258
279
  const remoteStream = (0, exports.getRemoteStream)(sipCall);
259
280
  const pc = (0, exports.getPeerConnection)(sipCall);
260
281
  logger.info('Updating remote stream', {
261
- id: sipCall.id,
282
+ id: (0, sdp_1.getSipCallId)(sipCall),
262
283
  tracks: remoteStream ? remoteStream.getTracks() : null,
263
284
  receiverTracks: pc && pc.getReceivers ? pc.getReceivers().map((receiver) => receiver.track) : null,
264
285
  });
package/lib/voice/call.js CHANGED
@@ -35,20 +35,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.MESSAGE_TRACK_UPDATED = exports.MESSAGE_TYPE_SIGNAL = exports.MESSAGE_TYPE_CHAT = exports.EVENT_TERMINATE_SOUND = exports.EVENT_CAMERA_DISABLED = exports.EVENT_CAMERA_RESUMED = exports.EVENT_WEB_RTC_STATS = exports.EVENT_SHARE_SCREEN_ENDED = exports.EVENT_SHARE_SCREEN_STARTED = exports.EVENT_SHARE_SCREEN_ENDING = exports.EVENT_REMOVE_STREAM = exports.EVENT_VIDEO_STREAM = exports.EVENT_AUDIO_STREAM = exports.EVENT_TRACK = exports.EVENT_REINVITE = exports.EVENT_CALL_RESUMED = exports.EVENT_CALL_HELD = exports.EVENT_CALL_UN_MUTED = exports.EVENT_CALL_MUTED = exports.EVENT_CALL_ENDED = exports.EVENT_CALL_TERMINATING = exports.EVENT_CALL_REJECTED = exports.EVENT_CALL_ERROR = exports.EVENT_EARLY_MEDIA = exports.EVENT_PROGRESS = exports.EVENT_CALL_CANCELED = exports.EVENT_CALL_ACCEPTED = void 0;
38
+ exports.MESSAGE_TRACK_UPDATED = exports.MESSAGE_TYPE_SIGNAL = exports.MESSAGE_TYPE_CHAT = exports.EVENT_CAMERA_DISABLED = exports.EVENT_CAMERA_RESUMED = exports.EVENT_WEB_RTC_STATS = exports.EVENT_SHARE_SCREEN_ENDED = exports.EVENT_SHARE_SCREEN_STARTED = exports.EVENT_SHARE_SCREEN_ENDING = exports.EVENT_REMOVE_STREAM = exports.EVENT_VIDEO_STREAM = exports.EVENT_AUDIO_STREAM = exports.EVENT_TRACK = exports.EVENT_REINVITE = exports.EVENT_CALL_RESUMED = exports.EVENT_CALL_HELD = exports.EVENT_CALL_UN_MUTED = exports.EVENT_CALL_MUTED = exports.EVENT_CALL_ENDED = exports.EVENT_CALL_TERMINATING = exports.EVENT_CALL_REJECTED = exports.EVENT_CALL_ERROR = exports.EVENT_EARLY_MEDIA = exports.EVENT_PROGRESS = exports.EVENT_CALL_CANCELED = exports.EVENT_CALL_LOCALLY_ACCEPTED = exports.EVENT_CALL_REMOTLY_ACCEPTED = void 0;
39
39
  /* eslint-disable no-underscore-dangle */
40
40
  const events_1 = require("events");
41
41
  const xstate_1 = require("xstate");
42
42
  const invitation_1 = require("sip.js/lib/api/invitation");
43
43
  const session_state_1 = require("sip.js/lib/api/session-state");
44
44
  const call_state_machine_1 = __importStar(require("../state-machine/call-state-machine"));
45
+ const new_from_1 = __importDefault(require("../utils/new-from"));
46
+ const update_from_1 = __importDefault(require("../utils/update-from"));
45
47
  const IssueReporter_1 = __importDefault(require("../service/IssueReporter"));
48
+ const softphone_1 = __importDefault(require("./softphone"));
46
49
  const sdp_1 = require("../utils/sdp");
47
50
  const utils_1 = require("../state-machine/utils");
48
51
  const webrtc_1 = require("../utils/webrtc");
49
52
  const logger = IssueReporter_1.default.loggerFor('call');
50
53
  // Events
51
- exports.EVENT_CALL_ACCEPTED = 'accepted';
54
+ exports.EVENT_CALL_REMOTLY_ACCEPTED = 'remotelyAccepted';
55
+ exports.EVENT_CALL_LOCALLY_ACCEPTED = 'locallyAccepted';
52
56
  exports.EVENT_CALL_CANCELED = 'canceled';
53
57
  exports.EVENT_PROGRESS = 'progress';
54
58
  exports.EVENT_EARLY_MEDIA = 'earlyMedia';
@@ -71,20 +75,65 @@ exports.EVENT_SHARE_SCREEN_ENDED = 'onScreenShareEnded';
71
75
  exports.EVENT_WEB_RTC_STATS = 'webRtcStats';
72
76
  exports.EVENT_CAMERA_RESUMED = 'onCameraResumed';
73
77
  exports.EVENT_CAMERA_DISABLED = 'onCameraDisabled';
74
- exports.EVENT_TERMINATE_SOUND = 'terminateSound';
75
78
  exports.MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
76
79
  exports.MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
77
80
  exports.MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
78
81
  class Call extends events_1.EventEmitter {
82
+ static newFrom(call) {
83
+ return (0, new_from_1.default)(call, Call);
84
+ }
85
+ static parseCall(apiCall) {
86
+ const sipCall = {
87
+ id: apiCall.sipCallId,
88
+ stateChange: {
89
+ addListener: () => { },
90
+ },
91
+ remoteIdentity: {
92
+ uri: {
93
+ _normal: {
94
+ user: apiCall.calleeNumber,
95
+ },
96
+ },
97
+ },
98
+ // Mock sdk so `hasLocalVideo` will return true.
99
+ sessionDescriptionHandler: {
100
+ localMediaStream: {
101
+ getTracks: () => (apiCall.isVideo ? [{ kind: 'video', readyState: 'live' }] : []),
102
+ },
103
+ },
104
+ };
105
+ const call = new Call(sipCall, softphone_1.default);
106
+ call.apiId = apiCall.id;
107
+ call.answerTime = new Date(+apiCall.startingTime);
108
+ // Update call state
109
+ const snapshot = call.callActor.getSnapshot();
110
+ if (apiCall.isUp()) {
111
+ snapshot.value = { [call_state_machine_1.States.ESTABLISHED]: call_state_machine_1.EstablishedStates.ONGOING };
112
+ }
113
+ if (apiCall.muted) {
114
+ snapshot.value = { [call_state_machine_1.States.ESTABLISHED]: call_state_machine_1.EstablishedStates.MUTED };
115
+ }
116
+ if (apiCall.isRinging()) {
117
+ snapshot.value = call_state_machine_1.States.RINGING;
118
+ }
119
+ if (apiCall.isRecording()) {
120
+ call.recording = true;
121
+ }
122
+ // @ts-ignore
123
+ call.callActor.update(snapshot);
124
+ return call;
125
+ }
79
126
  constructor(sipCall, phone) {
80
127
  super();
81
128
  this.shouldSendReinvite = false;
129
+ this.recording = false;
82
130
  this.callActor = (0, xstate_1.createActor)(call_state_machine_1.default);
83
131
  this.callActor.start();
84
132
  this.creationTime = new Date();
85
133
  this.phone = phone;
86
134
  this.sipCall = sipCall;
87
- this._bindEvents();
135
+ this.number = (0, sdp_1.getCallNumber)(sipCall);
136
+ this.displayName = (0, sdp_1.getCallDisplayName)(sipCall);
88
137
  }
89
138
  accept() {
90
139
  return __awaiter(this, arguments, void 0, function* (options = {}) {
@@ -96,6 +145,7 @@ class Call extends events_1.EventEmitter {
96
145
  this.answerTime = new Date();
97
146
  return this.phone.client.answer(this.sipCall, options.withCamera).then(() => {
98
147
  logger.info('call - accepted', Object.assign({ id: this.id }, options));
148
+ this.emit(exports.EVENT_CALL_LOCALLY_ACCEPTED, this);
99
149
  return this.id;
100
150
  }).catch(e => {
101
151
  logger.error(e);
@@ -108,18 +158,22 @@ class Call extends events_1.EventEmitter {
108
158
  return __awaiter(this, void 0, void 0, function* () {
109
159
  (0, utils_1.assertCan)(this.callActor, call_state_machine_1.Actions.REJECT);
110
160
  logger.info('call - reject', { id: this.id });
111
- this.eventEmitter.emit(exports.EVENT_TERMINATE_SOUND, 'call rejected locally');
112
- this.shouldSendReinvite = false;
113
- return this.hangup();
161
+ return this._terminate();
114
162
  });
115
163
  }
116
164
  hangup() {
117
165
  return __awaiter(this, void 0, void 0, function* () {
118
166
  (0, utils_1.assertCan)(this.callActor, call_state_machine_1.Actions.HANGUP);
119
167
  logger.info('call - hangup', { id: this.id });
168
+ return this._terminate();
169
+ });
170
+ }
171
+ _terminate() {
172
+ return __awaiter(this, void 0, void 0, function* () {
120
173
  yield this.phone.client.hangup(this.sipCall);
174
+ this.shouldSendReinvite = false;
121
175
  // Remove this call from softphone's calls
122
- this.phone.removeCall(this);
176
+ this.phone.onCallTerminated(this);
123
177
  return true;
124
178
  });
125
179
  }
@@ -132,7 +186,7 @@ class Call extends events_1.EventEmitter {
132
186
  logger.info('call - force cancel, error', e);
133
187
  }
134
188
  }
135
- startConference(withCalls) {
189
+ startConference( /* withCalls: Call[] */) {
136
190
  // @TODO
137
191
  // const participants = [this, ...withCalls].reduce((acc: Record<string, any>, call: Call) => {
138
192
  // acc[call.talkingToIds[0]] = call;
@@ -150,14 +204,14 @@ class Call extends events_1.EventEmitter {
150
204
  logger.info('call - mute', { id: this.id });
151
205
  this._sendAction(call_state_machine_1.EstablishedActions.MUTE);
152
206
  this.phone.client.mute(this.sipCall);
153
- this.eventEmitter.emit(exports.EVENT_CALL_MUTED);
207
+ this.emit(exports.EVENT_CALL_MUTED);
154
208
  }
155
209
  unMute() {
156
210
  (0, utils_1.assertCan)(this.callActor, call_state_machine_1.EstablishedActions.UN_MUTE);
157
211
  logger.info('call - un-mute', { id: this.id });
158
212
  this._sendAction(call_state_machine_1.EstablishedActions.UN_MUTE);
159
213
  this.phone.client.unmute(this.sipCall);
160
- this.eventEmitter.emit(exports.EVENT_CALL_UN_MUTED);
214
+ this.emit(exports.EVENT_CALL_UN_MUTED);
161
215
  }
162
216
  hold() {
163
217
  return __awaiter(this, void 0, void 0, function* () {
@@ -174,7 +228,7 @@ class Call extends events_1.EventEmitter {
174
228
  yield (0, webrtc_1.downgradeToAudio)(this.sipCall);
175
229
  }
176
230
  const promise = this.phone.client.hold(this.sipCall, this.isConference(), hasVideo);
177
- this.eventEmitter.emit(exports.EVENT_CALL_HELD);
231
+ this.emit(exports.EVENT_CALL_HELD);
178
232
  return promise;
179
233
  });
180
234
  }
@@ -203,7 +257,7 @@ class Call extends events_1.EventEmitter {
203
257
  this._onScreenSharing(stream, hadVideo, wasDesktop);
204
258
  }
205
259
  };
206
- this.eventEmitter.emit(exports.EVENT_CALL_RESUMED);
260
+ this.emit(exports.EVENT_CALL_RESUMED);
207
261
  return promise.then(() => {
208
262
  const stream = this.getLocalVideoStream();
209
263
  if (wasScreensharing) {
@@ -217,19 +271,37 @@ class Call extends events_1.EventEmitter {
217
271
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
218
272
  logger.info('call - turn camera on', { id: this.id });
219
273
  (0, webrtc_1.toggleVideo)(this.sipCall, true);
220
- this.eventEmitter.emit(exports.EVENT_CAMERA_RESUMED);
274
+ this.emit(exports.EVENT_CAMERA_RESUMED);
221
275
  }
222
276
  turnCameraOff() {
223
277
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
224
278
  logger.info('call - turn camera off', { id: this.id });
225
279
  (0, webrtc_1.toggleVideo)(this.sipCall, false);
226
- this.eventEmitter.emit(exports.EVENT_CAMERA_DISABLED);
280
+ this.emit(exports.EVENT_CAMERA_DISABLED);
281
+ }
282
+ isMuted() {
283
+ return this._hasEstablishedState(call_state_machine_1.EstablishedStates.MUTED);
284
+ }
285
+ isCameraMuted() {
286
+ return (0, webrtc_1.isVideoMuted)(this.sipCall);
227
287
  }
228
288
  isHeld() {
229
- return (0, utils_1.getState)(this.callActor) === call_state_machine_1.EstablishedStates.HELD;
289
+ return this._hasEstablishedState(call_state_machine_1.EstablishedStates.HELD);
290
+ }
291
+ isEstablishing() {
292
+ return this.sipCall.state === session_state_1.SessionState.Establishing;
230
293
  }
231
294
  isEstablished() {
232
- return (0, utils_1.getState)(this.callActor) === call_state_machine_1.States.ESTABLISHED;
295
+ return typeof this.state === 'object' && call_state_machine_1.States.ESTABLISHED in this.state;
296
+ }
297
+ isRinging() {
298
+ return this.state === call_state_machine_1.States.RINGING;
299
+ }
300
+ isOutgoing() {
301
+ return this.sipCall instanceof invitation_1.Invitation;
302
+ }
303
+ isIncoming() {
304
+ return !this.isOutgoing();
233
305
  }
234
306
  isConference() {
235
307
  var _a;
@@ -238,7 +310,7 @@ class Call extends events_1.EventEmitter {
238
310
  transfer(target) {
239
311
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
240
312
  logger.info('call - transfer', { id: this.id, target });
241
- this.phone.client.transfer(this.sipCall, target);
313
+ return this.phone.client.transfer(this.sipCall, target);
242
314
  }
243
315
  atxfer() {
244
316
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
@@ -366,7 +438,7 @@ class Call extends events_1.EventEmitter {
366
438
  catch (e) {
367
439
  console.warn(e);
368
440
  }
369
- this.eventEmitter.emit(exports.EVENT_SHARE_SCREEN_ENDED);
441
+ this.emit(exports.EVENT_SHARE_SCREEN_ENDED);
370
442
  this.currentScreenShare = null;
371
443
  return reinvited;
372
444
  });
@@ -376,9 +448,13 @@ class Call extends events_1.EventEmitter {
376
448
  logger.info('call - updrading directly in screensharing mode', { id: this.id, tracks: localStream === null || localStream === void 0 ? void 0 : localStream.getTracks() });
377
449
  this._onScreenSharing(localStream, false, desktop);
378
450
  }
451
+ onMakeCall() {
452
+ this._bindEvents();
453
+ this._sendAction(call_state_machine_1.Actions.MAKE_CALL);
454
+ }
379
455
  onAccepted() {
380
456
  this._sendAction(call_state_machine_1.Actions.REMOTLY_ACCEPTED);
381
- this.emit(exports.EVENT_CALL_ACCEPTED);
457
+ this.emit(exports.EVENT_CALL_REMOTLY_ACCEPTED);
382
458
  }
383
459
  onProgress() {
384
460
  this.emit(exports.EVENT_PROGRESS);
@@ -392,10 +468,14 @@ class Call extends events_1.EventEmitter {
392
468
  onError(error) {
393
469
  this.emit(exports.EVENT_CALL_ERROR, error);
394
470
  }
471
+ onCallIncoming() {
472
+ this._bindEvents();
473
+ this._sendAction(call_state_machine_1.Actions.INCOMING_CALL);
474
+ }
395
475
  onRejected() {
396
476
  this.endTime = new Date();
397
477
  this.emit(exports.EVENT_CALL_REJECTED);
398
- this.phone.removeCall(this);
478
+ this.phone.onCallTerminated(this);
399
479
  }
400
480
  onNetworkStats(stats, previousStats) {
401
481
  this.emit(exports.EVENT_WEB_RTC_STATS, stats, previousStats);
@@ -427,15 +507,28 @@ class Call extends events_1.EventEmitter {
427
507
  onReinvite(request, updatedCalleeName, updatedNumber, hadRemoteVideo) {
428
508
  this.emit(exports.EVENT_REINVITE, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
429
509
  }
510
+ updateFrom(call) {
511
+ (0, update_from_1.default)(this, call);
512
+ }
513
+ is(otherCall) {
514
+ return otherCall && this.id && this.id === otherCall.id;
515
+ }
516
+ shouldAutoAnswer() {
517
+ var _a;
518
+ return !!((_a = this.sipCall.request) === null || _a === void 0 ? void 0 : _a.getHeader('alert-info'));
519
+ }
430
520
  get id() {
431
- return (0, sdp_1.getSipSessionId)(this.sipCall);
521
+ return (0, sdp_1.getSipCallId)(this.sipCall);
522
+ }
523
+ get state() {
524
+ return (0, utils_1.getState)(this.callActor);
432
525
  }
433
- get number() {
434
- const identity = this.sipCall.remoteIdentity || this.sipCall.assertedIdentity;
435
- // @ts-ignore: private
436
- return identity ? identity.uri._normal.user : null;
526
+ _hasEstablishedState(establishedState) {
527
+ const state = this.state;
528
+ return typeof state === 'object' && call_state_machine_1.States.ESTABLISHED in state && state[call_state_machine_1.States.ESTABLISHED] === establishedState;
437
529
  }
438
530
  _bindEvents() {
531
+ var _a, _b;
439
532
  if (this.sipCall instanceof invitation_1.Invitation) {
440
533
  // Monkey patch to know when canceled with the CANCEL message
441
534
  const onCancel = this.sipCall._onCancel.bind(this.sipCall);
@@ -443,21 +536,22 @@ class Call extends events_1.EventEmitter {
443
536
  logger.trace('call - on sip session canceled', { callId: message.callId, id: this.id });
444
537
  onCancel(message);
445
538
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
446
- this.eventEmitter.emit(exports.EVENT_CALL_CANCELED, elsewhere);
539
+ this.emit(exports.EVENT_CALL_CANCELED, elsewhere);
447
540
  };
448
541
  }
449
- this.sipCall.stateChange.addListener((newState) => {
542
+ (_b = (_a = this.sipCall) === null || _a === void 0 ? void 0 : _a.stateChange) === null || _b === void 0 ? void 0 : _b.addListener((newState) => {
450
543
  switch (newState) {
451
544
  case session_state_1.SessionState.Terminating:
452
545
  logger.info('call - terminating', { id: this.id });
453
- this.eventEmitter.emit(exports.EVENT_CALL_TERMINATING);
546
+ this.emit(exports.EVENT_CALL_TERMINATING);
454
547
  break;
455
548
  case session_state_1.SessionState.Terminated:
456
549
  {
457
550
  logger.info('call - terminated', { id: this.id });
458
551
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
459
552
  this.endTime = new Date();
460
- return this.eventEmitter.emit(exports.EVENT_CALL_ENDED);
553
+ this.emit(exports.EVENT_CALL_ENDED);
554
+ return this.phone.onCallTerminated(this);
461
555
  }
462
556
  default:
463
557
  break;
@@ -484,18 +578,17 @@ class Call extends events_1.EventEmitter {
484
578
  kind,
485
579
  });
486
580
  if (kind === 'audio') {
487
- return this.eventEmitter.emit(exports.EVENT_AUDIO_STREAM, stream);
581
+ return this.emit(exports.EVENT_AUDIO_STREAM, stream);
488
582
  }
489
- return this.eventEmitter.emit(exports.EVENT_VIDEO_STREAM, stream, event.track.id, event);
583
+ return this.emit(exports.EVENT_VIDEO_STREAM, stream, event.track.id, event);
490
584
  };
491
585
  peerConnection.onremovestream = (event) => {
492
586
  logger.info('call - on remove stream called on the peer connection', {
493
587
  id: event.stream.id,
494
588
  tracks: event.stream.getTracks(),
495
589
  });
496
- this.eventEmitter.emit(exports.EVENT_REMOVE_STREAM, event.stream);
590
+ this.emit(exports.EVENT_REMOVE_STREAM, event.stream);
497
591
  };
498
- // Client events
499
592
  }
500
593
  _downgradeToAudio(withMessage = true) {
501
594
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
@@ -558,7 +651,7 @@ class Call extends events_1.EventEmitter {
558
651
  if (screenTrack) {
559
652
  screenTrack.onended = () => {
560
653
  logger.info('call - on screenshare ended', { hadVideo, id: this.id, screenTrack });
561
- this.eventEmitter.emit(exports.EVENT_SHARE_SCREEN_ENDING);
654
+ this.emit(exports.EVENT_SHARE_SCREEN_ENDING);
562
655
  };
563
656
  }
564
657
  this.currentScreenShare = {
@@ -568,10 +661,12 @@ class Call extends events_1.EventEmitter {
568
661
  desktop,
569
662
  };
570
663
  (0, webrtc_1.setLocalMediaStream)(this.sipCall, screenStream);
571
- this.eventEmitter.emit(exports.EVENT_SHARE_SCREEN_STARTED, screenStream);
664
+ this.emit(exports.EVENT_SHARE_SCREEN_STARTED, screenStream);
572
665
  }
573
666
  _sendAction(action) {
667
+ const was = this.state;
574
668
  this.callActor.send({ type: action });
669
+ logger.trace('call - send action', { action, was, state: this.state });
575
670
  }
576
671
  }
577
672
  exports.default = Call;