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

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 +10 -4
  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 +131 -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 +10 -4
  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 +132 -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 +14 -6
  144. package/src/utils/sdp.ts +26 -11
  145. package/src/utils/webrtc.ts +26 -4
  146. package/src/voice/call.ts +170 -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,25 @@ 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
+ const inviter_1 = require("sip.js/lib/api/inviter");
42
43
  const invitation_1 = require("sip.js/lib/api/invitation");
43
44
  const session_state_1 = require("sip.js/lib/api/session-state");
44
45
  const call_state_machine_1 = __importStar(require("../state-machine/call-state-machine"));
46
+ const new_from_1 = __importDefault(require("../utils/new-from"));
47
+ const update_from_1 = __importDefault(require("../utils/update-from"));
45
48
  const IssueReporter_1 = __importDefault(require("../service/IssueReporter"));
49
+ const softphone_1 = __importDefault(require("./softphone"));
46
50
  const sdp_1 = require("../utils/sdp");
47
51
  const utils_1 = require("../state-machine/utils");
48
52
  const webrtc_1 = require("../utils/webrtc");
49
53
  const logger = IssueReporter_1.default.loggerFor('call');
50
54
  // Events
51
- exports.EVENT_CALL_ACCEPTED = 'accepted';
55
+ exports.EVENT_CALL_REMOTLY_ACCEPTED = 'remotelyAccepted';
56
+ exports.EVENT_CALL_LOCALLY_ACCEPTED = 'locallyAccepted';
52
57
  exports.EVENT_CALL_CANCELED = 'canceled';
53
58
  exports.EVENT_PROGRESS = 'progress';
54
59
  exports.EVENT_EARLY_MEDIA = 'earlyMedia';
@@ -71,20 +76,65 @@ exports.EVENT_SHARE_SCREEN_ENDED = 'onScreenShareEnded';
71
76
  exports.EVENT_WEB_RTC_STATS = 'webRtcStats';
72
77
  exports.EVENT_CAMERA_RESUMED = 'onCameraResumed';
73
78
  exports.EVENT_CAMERA_DISABLED = 'onCameraDisabled';
74
- exports.EVENT_TERMINATE_SOUND = 'terminateSound';
75
79
  exports.MESSAGE_TYPE_CHAT = 'message/TYPE_CHAT';
76
80
  exports.MESSAGE_TYPE_SIGNAL = 'message/TYPE_SIGNAL';
77
81
  exports.MESSAGE_TRACK_UPDATED = 'onTrackUpdated';
78
82
  class Call extends events_1.EventEmitter {
83
+ static newFrom(call) {
84
+ return (0, new_from_1.default)(call, Call);
85
+ }
86
+ static parseCall(apiCall) {
87
+ const sipCall = {
88
+ id: apiCall.sipCallId,
89
+ stateChange: {
90
+ addListener: () => { },
91
+ },
92
+ remoteIdentity: {
93
+ uri: {
94
+ _normal: {
95
+ user: apiCall.calleeNumber,
96
+ },
97
+ },
98
+ },
99
+ // Mock sdk so `hasLocalVideo` will return true.
100
+ sessionDescriptionHandler: {
101
+ localMediaStream: {
102
+ getTracks: () => (apiCall.isVideo ? [{ kind: 'video', readyState: 'live' }] : []),
103
+ },
104
+ },
105
+ };
106
+ const call = new Call(sipCall, softphone_1.default);
107
+ call.apiId = apiCall.id;
108
+ call.answerTime = new Date(+apiCall.startingTime);
109
+ // Update call state
110
+ const snapshot = call.callActor.getSnapshot();
111
+ if (apiCall.isUp()) {
112
+ snapshot.value = { [call_state_machine_1.States.ESTABLISHED]: call_state_machine_1.EstablishedStates.ONGOING };
113
+ }
114
+ if (apiCall.muted) {
115
+ snapshot.value = { [call_state_machine_1.States.ESTABLISHED]: call_state_machine_1.EstablishedStates.MUTED };
116
+ }
117
+ if (apiCall.isRinging()) {
118
+ snapshot.value = call_state_machine_1.States.RINGING;
119
+ }
120
+ if (apiCall.isRecording()) {
121
+ call.recording = true;
122
+ }
123
+ // @ts-ignore
124
+ call.callActor.update(snapshot);
125
+ return call;
126
+ }
79
127
  constructor(sipCall, phone) {
80
128
  super();
81
129
  this.shouldSendReinvite = false;
130
+ this.recording = false;
82
131
  this.callActor = (0, xstate_1.createActor)(call_state_machine_1.default);
83
132
  this.callActor.start();
84
133
  this.creationTime = new Date();
85
134
  this.phone = phone;
86
135
  this.sipCall = sipCall;
87
- this._bindEvents();
136
+ this.number = (0, sdp_1.getCallNumber)(sipCall);
137
+ this.displayName = (0, sdp_1.getCallDisplayName)(sipCall);
88
138
  }
89
139
  accept() {
90
140
  return __awaiter(this, arguments, void 0, function* (options = {}) {
@@ -96,6 +146,7 @@ class Call extends events_1.EventEmitter {
96
146
  this.answerTime = new Date();
97
147
  return this.phone.client.answer(this.sipCall, options.withCamera).then(() => {
98
148
  logger.info('call - accepted', Object.assign({ id: this.id }, options));
149
+ this.emit(exports.EVENT_CALL_LOCALLY_ACCEPTED, this);
99
150
  return this.id;
100
151
  }).catch(e => {
101
152
  logger.error(e);
@@ -108,18 +159,22 @@ class Call extends events_1.EventEmitter {
108
159
  return __awaiter(this, void 0, void 0, function* () {
109
160
  (0, utils_1.assertCan)(this.callActor, call_state_machine_1.Actions.REJECT);
110
161
  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();
162
+ return this._terminate();
114
163
  });
115
164
  }
116
165
  hangup() {
117
166
  return __awaiter(this, void 0, void 0, function* () {
118
167
  (0, utils_1.assertCan)(this.callActor, call_state_machine_1.Actions.HANGUP);
119
168
  logger.info('call - hangup', { id: this.id });
169
+ return this._terminate();
170
+ });
171
+ }
172
+ _terminate() {
173
+ return __awaiter(this, void 0, void 0, function* () {
120
174
  yield this.phone.client.hangup(this.sipCall);
175
+ this.shouldSendReinvite = false;
121
176
  // Remove this call from softphone's calls
122
- this.phone.removeCall(this);
177
+ this.phone.onCallTerminated(this);
123
178
  return true;
124
179
  });
125
180
  }
@@ -132,7 +187,7 @@ class Call extends events_1.EventEmitter {
132
187
  logger.info('call - force cancel, error', e);
133
188
  }
134
189
  }
135
- startConference(withCalls) {
190
+ startConference( /* withCalls: Call[] */) {
136
191
  // @TODO
137
192
  // const participants = [this, ...withCalls].reduce((acc: Record<string, any>, call: Call) => {
138
193
  // acc[call.talkingToIds[0]] = call;
@@ -150,14 +205,14 @@ class Call extends events_1.EventEmitter {
150
205
  logger.info('call - mute', { id: this.id });
151
206
  this._sendAction(call_state_machine_1.EstablishedActions.MUTE);
152
207
  this.phone.client.mute(this.sipCall);
153
- this.eventEmitter.emit(exports.EVENT_CALL_MUTED);
208
+ this.emit(exports.EVENT_CALL_MUTED);
154
209
  }
155
210
  unMute() {
156
211
  (0, utils_1.assertCan)(this.callActor, call_state_machine_1.EstablishedActions.UN_MUTE);
157
212
  logger.info('call - un-mute', { id: this.id });
158
213
  this._sendAction(call_state_machine_1.EstablishedActions.UN_MUTE);
159
214
  this.phone.client.unmute(this.sipCall);
160
- this.eventEmitter.emit(exports.EVENT_CALL_UN_MUTED);
215
+ this.emit(exports.EVENT_CALL_UN_MUTED);
161
216
  }
162
217
  hold() {
163
218
  return __awaiter(this, void 0, void 0, function* () {
@@ -174,7 +229,7 @@ class Call extends events_1.EventEmitter {
174
229
  yield (0, webrtc_1.downgradeToAudio)(this.sipCall);
175
230
  }
176
231
  const promise = this.phone.client.hold(this.sipCall, this.isConference(), hasVideo);
177
- this.eventEmitter.emit(exports.EVENT_CALL_HELD);
232
+ this.emit(exports.EVENT_CALL_HELD);
178
233
  return promise;
179
234
  });
180
235
  }
@@ -203,7 +258,7 @@ class Call extends events_1.EventEmitter {
203
258
  this._onScreenSharing(stream, hadVideo, wasDesktop);
204
259
  }
205
260
  };
206
- this.eventEmitter.emit(exports.EVENT_CALL_RESUMED);
261
+ this.emit(exports.EVENT_CALL_RESUMED);
207
262
  return promise.then(() => {
208
263
  const stream = this.getLocalVideoStream();
209
264
  if (wasScreensharing) {
@@ -217,19 +272,37 @@ class Call extends events_1.EventEmitter {
217
272
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
218
273
  logger.info('call - turn camera on', { id: this.id });
219
274
  (0, webrtc_1.toggleVideo)(this.sipCall, true);
220
- this.eventEmitter.emit(exports.EVENT_CAMERA_RESUMED);
275
+ this.emit(exports.EVENT_CAMERA_RESUMED);
221
276
  }
222
277
  turnCameraOff() {
223
278
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
224
279
  logger.info('call - turn camera off', { id: this.id });
225
280
  (0, webrtc_1.toggleVideo)(this.sipCall, false);
226
- this.eventEmitter.emit(exports.EVENT_CAMERA_DISABLED);
281
+ this.emit(exports.EVENT_CAMERA_DISABLED);
282
+ }
283
+ isMuted() {
284
+ return this._hasEstablishedState(call_state_machine_1.EstablishedStates.MUTED);
285
+ }
286
+ isCameraMuted() {
287
+ return (0, webrtc_1.isVideoMuted)(this.sipCall);
227
288
  }
228
289
  isHeld() {
229
- return (0, utils_1.getState)(this.callActor) === call_state_machine_1.EstablishedStates.HELD;
290
+ return this._hasEstablishedState(call_state_machine_1.EstablishedStates.HELD);
291
+ }
292
+ isEstablishing() {
293
+ return this.sipCall.state === session_state_1.SessionState.Establishing;
230
294
  }
231
295
  isEstablished() {
232
- return (0, utils_1.getState)(this.callActor) === call_state_machine_1.States.ESTABLISHED;
296
+ return typeof this.state === 'object' && call_state_machine_1.States.ESTABLISHED in this.state;
297
+ }
298
+ isRinging() {
299
+ return this.state === call_state_machine_1.States.RINGING;
300
+ }
301
+ isOutgoing() {
302
+ return this.sipCall instanceof inviter_1.Inviter;
303
+ }
304
+ isIncoming() {
305
+ return !this.isOutgoing();
233
306
  }
234
307
  isConference() {
235
308
  var _a;
@@ -238,7 +311,7 @@ class Call extends events_1.EventEmitter {
238
311
  transfer(target) {
239
312
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
240
313
  logger.info('call - transfer', { id: this.id, target });
241
- this.phone.client.transfer(this.sipCall, target);
314
+ return this.phone.client.transfer(this.sipCall, target);
242
315
  }
243
316
  atxfer() {
244
317
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
@@ -366,7 +439,7 @@ class Call extends events_1.EventEmitter {
366
439
  catch (e) {
367
440
  console.warn(e);
368
441
  }
369
- this.eventEmitter.emit(exports.EVENT_SHARE_SCREEN_ENDED);
442
+ this.emit(exports.EVENT_SHARE_SCREEN_ENDED);
370
443
  this.currentScreenShare = null;
371
444
  return reinvited;
372
445
  });
@@ -376,9 +449,13 @@ class Call extends events_1.EventEmitter {
376
449
  logger.info('call - updrading directly in screensharing mode', { id: this.id, tracks: localStream === null || localStream === void 0 ? void 0 : localStream.getTracks() });
377
450
  this._onScreenSharing(localStream, false, desktop);
378
451
  }
452
+ onMakeCall() {
453
+ this._bindEvents();
454
+ this._sendAction(call_state_machine_1.Actions.MAKE_CALL);
455
+ }
379
456
  onAccepted() {
380
457
  this._sendAction(call_state_machine_1.Actions.REMOTLY_ACCEPTED);
381
- this.emit(exports.EVENT_CALL_ACCEPTED);
458
+ this.emit(exports.EVENT_CALL_REMOTLY_ACCEPTED);
382
459
  }
383
460
  onProgress() {
384
461
  this.emit(exports.EVENT_PROGRESS);
@@ -392,10 +469,14 @@ class Call extends events_1.EventEmitter {
392
469
  onError(error) {
393
470
  this.emit(exports.EVENT_CALL_ERROR, error);
394
471
  }
472
+ onCallIncoming() {
473
+ this._bindEvents();
474
+ this._sendAction(call_state_machine_1.Actions.INCOMING_CALL);
475
+ }
395
476
  onRejected() {
396
477
  this.endTime = new Date();
397
478
  this.emit(exports.EVENT_CALL_REJECTED);
398
- this.phone.removeCall(this);
479
+ this.phone.onCallTerminated(this);
399
480
  }
400
481
  onNetworkStats(stats, previousStats) {
401
482
  this.emit(exports.EVENT_WEB_RTC_STATS, stats, previousStats);
@@ -427,15 +508,28 @@ class Call extends events_1.EventEmitter {
427
508
  onReinvite(request, updatedCalleeName, updatedNumber, hadRemoteVideo) {
428
509
  this.emit(exports.EVENT_REINVITE, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
429
510
  }
511
+ updateFrom(call) {
512
+ (0, update_from_1.default)(this, call);
513
+ }
514
+ is(otherCall) {
515
+ return otherCall && this.id && this.id === otherCall.id;
516
+ }
517
+ shouldAutoAnswer() {
518
+ var _a;
519
+ return !!((_a = this.sipCall.request) === null || _a === void 0 ? void 0 : _a.getHeader('alert-info'));
520
+ }
430
521
  get id() {
431
- return (0, sdp_1.getSipSessionId)(this.sipCall);
522
+ return (0, sdp_1.getSipCallId)(this.sipCall);
523
+ }
524
+ get state() {
525
+ return (0, utils_1.getState)(this.callActor);
432
526
  }
433
- get number() {
434
- const identity = this.sipCall.remoteIdentity || this.sipCall.assertedIdentity;
435
- // @ts-ignore: private
436
- return identity ? identity.uri._normal.user : null;
527
+ _hasEstablishedState(establishedState) {
528
+ const state = this.state;
529
+ return typeof state === 'object' && call_state_machine_1.States.ESTABLISHED in state && state[call_state_machine_1.States.ESTABLISHED] === establishedState;
437
530
  }
438
531
  _bindEvents() {
532
+ var _a, _b;
439
533
  if (this.sipCall instanceof invitation_1.Invitation) {
440
534
  // Monkey patch to know when canceled with the CANCEL message
441
535
  const onCancel = this.sipCall._onCancel.bind(this.sipCall);
@@ -443,21 +537,22 @@ class Call extends events_1.EventEmitter {
443
537
  logger.trace('call - on sip session canceled', { callId: message.callId, id: this.id });
444
538
  onCancel(message);
445
539
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
446
- this.eventEmitter.emit(exports.EVENT_CALL_CANCELED, elsewhere);
540
+ this.emit(exports.EVENT_CALL_CANCELED, elsewhere);
447
541
  };
448
542
  }
449
- this.sipCall.stateChange.addListener((newState) => {
543
+ (_b = (_a = this.sipCall) === null || _a === void 0 ? void 0 : _a.stateChange) === null || _b === void 0 ? void 0 : _b.addListener((newState) => {
450
544
  switch (newState) {
451
545
  case session_state_1.SessionState.Terminating:
452
546
  logger.info('call - terminating', { id: this.id });
453
- this.eventEmitter.emit(exports.EVENT_CALL_TERMINATING);
547
+ this.emit(exports.EVENT_CALL_TERMINATING);
454
548
  break;
455
549
  case session_state_1.SessionState.Terminated:
456
550
  {
457
551
  logger.info('call - terminated', { id: this.id });
458
552
  // Should be called before `_onCallTerminated` or the callCount will not decrement...
459
553
  this.endTime = new Date();
460
- return this.eventEmitter.emit(exports.EVENT_CALL_ENDED);
554
+ this.emit(exports.EVENT_CALL_ENDED);
555
+ return this.phone.onCallTerminated(this);
461
556
  }
462
557
  default:
463
558
  break;
@@ -484,18 +579,17 @@ class Call extends events_1.EventEmitter {
484
579
  kind,
485
580
  });
486
581
  if (kind === 'audio') {
487
- return this.eventEmitter.emit(exports.EVENT_AUDIO_STREAM, stream);
582
+ return this.emit(exports.EVENT_AUDIO_STREAM, stream);
488
583
  }
489
- return this.eventEmitter.emit(exports.EVENT_VIDEO_STREAM, stream, event.track.id, event);
584
+ return this.emit(exports.EVENT_VIDEO_STREAM, stream, event.track.id, event);
490
585
  };
491
586
  peerConnection.onremovestream = (event) => {
492
587
  logger.info('call - on remove stream called on the peer connection', {
493
588
  id: event.stream.id,
494
589
  tracks: event.stream.getTracks(),
495
590
  });
496
- this.eventEmitter.emit(exports.EVENT_REMOVE_STREAM, event.stream);
591
+ this.emit(exports.EVENT_REMOVE_STREAM, event.stream);
497
592
  };
498
- // Client events
499
593
  }
500
594
  _downgradeToAudio(withMessage = true) {
501
595
  (0, utils_1.assertState)(this.callActor, call_state_machine_1.States.ESTABLISHED);
@@ -558,7 +652,7 @@ class Call extends events_1.EventEmitter {
558
652
  if (screenTrack) {
559
653
  screenTrack.onended = () => {
560
654
  logger.info('call - on screenshare ended', { hadVideo, id: this.id, screenTrack });
561
- this.eventEmitter.emit(exports.EVENT_SHARE_SCREEN_ENDING);
655
+ this.emit(exports.EVENT_SHARE_SCREEN_ENDING);
562
656
  };
563
657
  }
564
658
  this.currentScreenShare = {
@@ -568,10 +662,12 @@ class Call extends events_1.EventEmitter {
568
662
  desktop,
569
663
  };
570
664
  (0, webrtc_1.setLocalMediaStream)(this.sipCall, screenStream);
571
- this.eventEmitter.emit(exports.EVENT_SHARE_SCREEN_STARTED, screenStream);
665
+ this.emit(exports.EVENT_SHARE_SCREEN_STARTED, screenStream);
572
666
  }
573
667
  _sendAction(action) {
668
+ const was = this.state;
574
669
  this.callActor.send({ type: action });
670
+ logger.trace('call - send action', { action, was, state: this.state });
575
671
  }
576
672
  }
577
673
  exports.default = Call;