@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
@@ -17,7 +17,7 @@ import Emitter from './utils/Emitter';
17
17
  import ApiClient from './api-client';
18
18
  import IssueReporter from './service/IssueReporter';
19
19
  import Heartbeat from './utils/Heartbeat';
20
- import { getSipSessionId, makeURI, replaceLocalIpModifier, SIP_ID_LENGTH } from './utils/sdp';
20
+ import { getSipCallId, makeURI, replaceLocalIpModifier } from './utils/sdp';
21
21
  import { cleanupStream, createUaOptions, fetchNetworkStats, getAudioConstraints, getLocalStream, getLocalTracks, getLocalVideoStream, getMediaConfiguration, getPeerConnection, getRemoteStream, getRemoteTracks, getRemoteVideoStream, getRemoteVideoStreamFromPc, getVideoConstraints, hasALocalVideoTrack, hasARemoteVideoTrack, hasAVideoTrack, hasLocalVideo, hasRemoteVideo, hasVideoTrack, isAudioOnly, isVideoRemotelyHeld, isWeb, sessionWantsToDoVideo, setLocalMediaStream, toggleAudio, toggleVideo, updateRemoteStream } from './utils/webrtc';
22
22
  const SEND_STATS_DELAY = 5000;
23
23
  const states = ['STATUS_NULL', 'STATUS_NEW', 'STATUS_CONNECTING', 'STATUS_CONNECTED', 'STATUS_COMPLETED'];
@@ -25,6 +25,7 @@ const logger = IssueReporter ? IssueReporter.loggerFor('webrtc-client') : consol
25
25
  const statsLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-stats') : console;
26
26
  // events
27
27
  const REGISTERED = 'registered';
28
+ const REGISTERING = 'registering';
28
29
  const UNREGISTERED = 'unregistered';
29
30
  const REGISTRATION_FAILED = 'registrationFailed';
30
31
  const INVITE = 'invite';
@@ -42,7 +43,7 @@ const ON_ERROR = 'onError';
42
43
  const ON_SCREEN_SHARING_REINVITE = 'onScreenSharingReinvite';
43
44
  const ON_NETWORK_STATS = 'onNetworkStats';
44
45
  const ON_DISCONNECTED = 'onDisconnected';
45
- export const events = [REGISTERED, UNREGISTERED, REGISTRATION_FAILED, INVITE];
46
+ export const events = [REGISTERED, REGISTERING, UNREGISTERED, REGISTRATION_FAILED, INVITE];
46
47
  export const transportEvents = [CONNECTED, DISCONNECTED, TRANSPORT_ERROR, MESSAGE];
47
48
  export class CanceledCallError extends Error {
48
49
  }
@@ -76,6 +77,7 @@ export default class WebRTCClient extends Emitter {
76
77
  // sugar
77
78
  ON_USER_AGENT;
78
79
  REGISTERED;
80
+ REGISTERING;
79
81
  UNREGISTERED;
80
82
  REGISTRATION_FAILED;
81
83
  INVITE;
@@ -103,7 +105,9 @@ export default class WebRTCClient extends Emitter {
103
105
  this.skipRegister = config.skipRegister;
104
106
  this._buildConfig(config, session).then((newConfig) => {
105
107
  this.config = newConfig;
106
- this.userAgent = this.createUserAgent(uaConfigOverrides);
108
+ if (!this.userAgent) {
109
+ this.userAgent = this.createUserAgent(uaConfigOverrides);
110
+ }
107
111
  });
108
112
  this.audioOutputDeviceId = config.audioDeviceOutput;
109
113
  this.audioOutputVolume = config.audioOutputVolume || 1;
@@ -128,6 +132,7 @@ export default class WebRTCClient extends Emitter {
128
132
  this.heartbeat.setOnHeartbeatTimeout(this._onHeartbeatTimeout.bind(this));
129
133
  // sugar
130
134
  this.REGISTERED = REGISTERED;
135
+ this.REGISTERING = REGISTERING;
131
136
  this.UNREGISTERED = UNREGISTERED;
132
137
  this.REGISTRATION_FAILED = REGISTRATION_FAILED;
133
138
  this.INVITE = INVITE;
@@ -168,7 +173,7 @@ export default class WebRTCClient extends Emitter {
168
173
  logger.info('sdk webrtc on invite', {
169
174
  method: 'delegate.onInvite',
170
175
  clientId: this.clientId,
171
- id: invitation.id,
176
+ id: getSipCallId(invitation),
172
177
  remoteURI: invitation.remoteURI,
173
178
  });
174
179
  this._setupSession(invitation);
@@ -230,7 +235,7 @@ export default class WebRTCClient extends Emitter {
230
235
  // @ts-ignore: private
231
236
  this.registerer.waitingToggle(false);
232
237
  }
233
- this.eventEmitter.emit(UNREGISTERED);
238
+ this.eventEmitter.emit(UNREGISTERED, error);
234
239
  }
235
240
  }
236
241
  async register(tries = 0) {
@@ -251,6 +256,7 @@ export default class WebRTCClient extends Emitter {
251
256
  return Promise.resolve();
252
257
  }
253
258
  logger.info('sdk webrtc registering...', logInfo);
259
+ this.eventEmitter.emit(REGISTERING);
254
260
  if (!this.userAgent) {
255
261
  logger.info('sdk webrtc recreating User Agent');
256
262
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
@@ -435,7 +441,7 @@ export default class WebRTCClient extends Emitter {
435
441
  this._setupSession(session);
436
442
  }
437
443
  if (conference) {
438
- this.conferences[getSipSessionId(session)] = true;
444
+ this.conferences[getSipCallId(session)] = true;
439
445
  }
440
446
  const inviteOptions = {
441
447
  requestDelegate: {
@@ -450,7 +456,7 @@ export default class WebRTCClient extends Emitter {
450
456
  },
451
457
  onReject: (response) => {
452
458
  logger.info('on call rejected', {
453
- id: session?.id,
459
+ id: getSipCallId(session),
454
460
  // @ts-ignore: fromTag does not exist
455
461
  fromTag: session?.fromTag,
456
462
  });
@@ -480,7 +486,7 @@ export default class WebRTCClient extends Emitter {
480
486
  answer(session, enableVideo) {
481
487
  logger.info('sdk webrtc answer call', {
482
488
  clientId: this.clientId,
483
- id: session.id,
489
+ id: getSipCallId(session),
484
490
  enableVideo,
485
491
  });
486
492
  if (!session || !session.accept) {
@@ -496,7 +502,7 @@ export default class WebRTCClient extends Emitter {
496
502
  if (session.isCanceled) {
497
503
  const message = 'accepted a canceled session (or was canceled during the accept phase).';
498
504
  logger.error(message, {
499
- id: session.id,
505
+ id: getSipCallId(session),
500
506
  });
501
507
  this.onCallEnded(session);
502
508
  throw new CanceledCallError(message);
@@ -504,7 +510,7 @@ export default class WebRTCClient extends Emitter {
504
510
  logger.info('sdk webrtc answer, accepted.');
505
511
  this._onAccepted(session);
506
512
  }).catch(e => {
507
- logger.error(`answer call error for ${session ? session.id : 'n/a'}`, e);
513
+ logger.error(`answer call error for ${getSipCallId(session)}`, e);
508
514
  throw e;
509
515
  });
510
516
  }
@@ -514,7 +520,7 @@ export default class WebRTCClient extends Emitter {
514
520
  try {
515
521
  this._stopSendingStats(session);
516
522
  this._cleanupMedia(session);
517
- delete this.sipSessions[getSipSessionId(session)];
523
+ delete this.sipSessions[getSipCallId(session)];
518
524
  // Check if Invitation or Inviter (Invitation = incoming call)
519
525
  const isInviter = session instanceof Inviter;
520
526
  // @see github.com/onsip/SIP.js/blob/f11dfd584bc9788ccfc94e03034020672b738975/src/platform/web/simple-user/simple-user.ts#L1004
@@ -536,7 +542,7 @@ export default class WebRTCClient extends Emitter {
536
542
  }
537
543
  // Fetch and emit an event at `interval` with session network stats
538
544
  startNetworkMonitoring(session, interval = 1000) {
539
- const sessionId = getSipSessionId(session);
545
+ const sessionId = getSipCallId(session);
540
546
  logger.info('starting network inspection', {
541
547
  id: sessionId,
542
548
  clientId: this.clientId,
@@ -545,7 +551,7 @@ export default class WebRTCClient extends Emitter {
545
551
  this.networkMonitoringInterval[sessionId] = setInterval(() => this._fetchNetworkStats(sessionId), interval);
546
552
  }
547
553
  stopNetworkMonitoring(session) {
548
- const sessionId = getSipSessionId(session);
554
+ const sessionId = getSipCallId(session);
549
555
  const exists = (sessionId in this.networkMonitoringInterval);
550
556
  logger.info('stopping network inspection', {
551
557
  clientId: this.clientId,
@@ -561,7 +567,7 @@ export default class WebRTCClient extends Emitter {
561
567
  async reject(session) {
562
568
  logger.info('sdk webrtc reject call', {
563
569
  clientId: this.clientId,
564
- id: session.id,
570
+ id: getSipCallId(session),
565
571
  });
566
572
  try {
567
573
  if (session instanceof Invitation) {
@@ -615,13 +621,13 @@ export default class WebRTCClient extends Emitter {
615
621
  }
616
622
  mute(session) {
617
623
  logger.info('sdk webrtc mute', {
618
- id: session.id,
624
+ id: getSipCallId(session),
619
625
  });
620
626
  toggleAudio(session, true);
621
627
  }
622
628
  unmute(session) {
623
629
  logger.info('sdk webrtc unmute', {
624
- id: session.id,
630
+ id: getSipCallId(session),
625
631
  });
626
632
  toggleAudio(session, false);
627
633
  }
@@ -658,18 +664,18 @@ export default class WebRTCClient extends Emitter {
658
664
  }
659
665
  toggleCameraOn(session) {
660
666
  logger.info('sdk webrtc toggle camera on', {
661
- id: session.id,
667
+ id: getSipCallId(session),
662
668
  });
663
669
  toggleVideo(session, false);
664
670
  }
665
671
  toggleCameraOff(session) {
666
672
  logger.info('sdk webrtc toggle camera off', {
667
- id: session.id,
673
+ id: getSipCallId(session),
668
674
  });
669
675
  toggleVideo(session, true);
670
676
  }
671
677
  hold(session, isConference = false, hadVideo = false) {
672
- const sessionId = getSipSessionId(session);
678
+ const sessionId = getSipCallId(session);
673
679
  const hasVideo = hadVideo || this.hasLocalVideo(sessionId);
674
680
  logger.info('sdk webrtc hold', {
675
681
  sessionId,
@@ -717,7 +723,7 @@ export default class WebRTCClient extends Emitter {
717
723
  });
718
724
  }
719
725
  unhold(session, isConference = false) {
720
- const sessionId = getSipSessionId(session);
726
+ const sessionId = getSipCallId(session);
721
727
  const hasVideo = sessionId in this.heldSessions && this.heldSessions[sessionId].hasVideo;
722
728
  logger.info('sdk webrtc unhold', {
723
729
  sessionId,
@@ -732,7 +738,7 @@ export default class WebRTCClient extends Emitter {
732
738
  return Promise.resolve();
733
739
  }
734
740
  this.unmute(session);
735
- delete this.heldSessions[getSipSessionId(session)];
741
+ delete this.heldSessions[getSipCallId(session)];
736
742
  session.sessionDescriptionHandlerOptionsReInvite = {
737
743
  hold: false,
738
744
  conference: isConference,
@@ -757,7 +763,7 @@ export default class WebRTCClient extends Emitter {
757
763
  return this.heldSessions[sessionId];
758
764
  }
759
765
  isCallHeld(session) {
760
- return getSipSessionId(session) in this.heldSessions;
766
+ return getSipCallId(session) in this.heldSessions;
761
767
  }
762
768
  isVideoRemotelyHeld(sessionId) {
763
769
  return isVideoRemotelyHeld(this.heldSessions[sessionId]);
@@ -767,7 +773,7 @@ export default class WebRTCClient extends Emitter {
767
773
  return false;
768
774
  }
769
775
  logger.info('Sending DTMF', {
770
- id: getSipSessionId(session),
776
+ id: getSipCallId(session),
771
777
  tone,
772
778
  });
773
779
  return session.sessionDescriptionHandler.sendDtmf(tone);
@@ -784,7 +790,7 @@ export default class WebRTCClient extends Emitter {
784
790
  transfer(session, target) {
785
791
  this.hold(session);
786
792
  logger.info('Transfering a session', {
787
- id: getSipSessionId(session),
793
+ id: getSipCallId(session),
788
794
  target,
789
795
  });
790
796
  const options = {
@@ -807,21 +813,21 @@ export default class WebRTCClient extends Emitter {
807
813
  atxfer(session) {
808
814
  this.hold(session);
809
815
  logger.info('webrtc transfer started', {
810
- id: getSipSessionId(session),
816
+ id: getSipCallId(session),
811
817
  });
812
818
  const result = {
813
819
  newSession: null,
814
820
  init: async (target) => {
815
821
  logger.info('webrtc transfer initialized', {
816
- id: getSipSessionId(session),
822
+ id: getSipCallId(session),
817
823
  target,
818
824
  });
819
825
  result.newSession = await this.call(target);
820
826
  },
821
827
  complete: () => {
822
828
  logger.info('webrtc transfer completed', {
823
- id: getSipSessionId(session),
824
- referId: getSipSessionId(result.newSession),
829
+ id: getSipCallId(session),
830
+ referId: getSipCallId(result.newSession),
825
831
  });
826
832
  session.refer(result.newSession);
827
833
  },
@@ -838,7 +844,7 @@ export default class WebRTCClient extends Emitter {
838
844
  return;
839
845
  }
840
846
  logger.info('send WebRTC message', {
841
- sipId: sipSession.id,
847
+ sipId: getSipCallId(sipSession),
842
848
  contentType,
843
849
  });
844
850
  try {
@@ -988,7 +994,7 @@ export default class WebRTCClient extends Emitter {
988
994
  }
989
995
  const sdh = session.sessionDescriptionHandler;
990
996
  const pc = sdh.peerConnection;
991
- const sessionId = getSipSessionId(session);
997
+ const sessionId = getSipCallId(session);
992
998
  const localStream = this.getLocalStream(sessionId);
993
999
  logger.info('changing video input device', {
994
1000
  id,
@@ -1049,7 +1055,7 @@ export default class WebRTCClient extends Emitter {
1049
1055
  const desktop = newConstraints && newConstraints.desktop;
1050
1056
  logger.info('Sending reinvite', {
1051
1057
  clientId: this.clientId,
1052
- id: getSipSessionId(sipSession),
1058
+ id: getSipCallId(sipSession),
1053
1059
  newConstraints,
1054
1060
  conference,
1055
1061
  audioOnly,
@@ -1083,7 +1089,7 @@ export default class WebRTCClient extends Emitter {
1083
1089
  sipSession.incomingInviteRequest.message.body = response.message.body;
1084
1090
  }
1085
1091
  logger.info('on re-INVITE accepted', {
1086
- id: getSipSessionId(sipSession),
1092
+ id: getSipCallId(sipSession),
1087
1093
  wasMuted,
1088
1094
  shouldDoScreenSharing,
1089
1095
  });
@@ -1194,7 +1200,7 @@ export default class WebRTCClient extends Emitter {
1194
1200
  }
1195
1201
  onCallEnded(session) {
1196
1202
  this._cleanupMedia(session);
1197
- delete this.sipSessions[getSipSessionId(session)];
1203
+ delete this.sipSessions[getSipCallId(session)];
1198
1204
  this._stopSendingStats(session);
1199
1205
  this.stopNetworkMonitoring(session);
1200
1206
  }
@@ -1207,14 +1213,14 @@ export default class WebRTCClient extends Emitter {
1207
1213
  this.userAgent.attemptReconnection();
1208
1214
  }
1209
1215
  storeSipSession(session) {
1210
- const id = getSipSessionId(session);
1216
+ const id = getSipCallId(session);
1211
1217
  logger.info('storing sip session', { id, clientId: this.clientId });
1212
1218
  this.sipSessions[id] = session;
1213
1219
  }
1214
1220
  getSipSession(id) {
1215
- return id in this.sipSessions ? this.sipSessions[id.substring(0, SIP_ID_LENGTH)] : null;
1221
+ return id in this.sipSessions ? this.sipSessions[id] : null;
1216
1222
  }
1217
- getSipSessionIds() {
1223
+ getSipCallIds() {
1218
1224
  return Object.keys(this.sipSessions);
1219
1225
  }
1220
1226
  async updateLocalStream(sipSessionId, newStream) {
@@ -1253,8 +1259,8 @@ export default class WebRTCClient extends Emitter {
1253
1259
  audio.autoplay = true;
1254
1260
  return audio;
1255
1261
  }
1256
- _onTransportError() {
1257
- logger.error('on transport error');
1262
+ _onTransportError(reason) {
1263
+ logger.warn('on transport error', { reason });
1258
1264
  this.eventEmitter.emit(TRANSPORT_ERROR);
1259
1265
  this.attemptReconnection();
1260
1266
  }
@@ -1307,7 +1313,7 @@ export default class WebRTCClient extends Emitter {
1307
1313
  }
1308
1314
  }
1309
1315
  // We can invoke disconnect() with an error that can be catcher by `onDisconnect`, so we have to trigger it here.
1310
- this._onTransportError();
1316
+ this._onTransportError('heartbeat timeout');
1311
1317
  }
1312
1318
  }
1313
1319
  _hasAudio() {
@@ -1369,7 +1375,7 @@ export default class WebRTCClient extends Emitter {
1369
1375
  }
1370
1376
  // Invitation and Inviter extends Session
1371
1377
  _setupSession(session) {
1372
- const sipSessionId = getSipSessionId(session);
1378
+ const sipSessionId = getSipCallId(session);
1373
1379
  // When receiving an Invitation, the delegate is not defined.
1374
1380
  if (!session.delegate) {
1375
1381
  session.delegate = {};
@@ -1432,17 +1438,14 @@ export default class WebRTCClient extends Emitter {
1432
1438
  }
1433
1439
  async _onProgress(session, early = false) {
1434
1440
  await this._setupMedias(session);
1435
- const sessionId = getSipSessionId(session).substr(0, 20);
1441
+ const sessionId = getSipCallId(session);
1436
1442
  updateRemoteStream(session);
1437
- logger.info('progress received', {
1438
- sessionId,
1439
- early,
1440
- });
1443
+ logger.info('progress received', { sessionId, early });
1441
1444
  this.eventEmitter.emit(early ? ON_EARLY_MEDIA : ON_PROGRESS, session);
1442
1445
  }
1443
1446
  async _onAccepted(session, sessionDialog, withEvent = true, initAllTracks = true) {
1444
1447
  logger.info('on call accepted', {
1445
- id: session.id,
1448
+ id: getSipCallId(session),
1446
1449
  clientId: this.clientId,
1447
1450
  remoteTag: session.remoteTag,
1448
1451
  });
@@ -1486,7 +1489,7 @@ export default class WebRTCClient extends Emitter {
1486
1489
  return;
1487
1490
  }
1488
1491
  // Safari hack, because you cannot call .play() from a non user action
1489
- const sessionId = getSipSessionId(session);
1492
+ const sessionId = getSipCallId(session);
1490
1493
  const isConference = this.isConference(sessionId);
1491
1494
  if (sessionId in this.audioElements) {
1492
1495
  logger.info('html element already exists for session', {
@@ -1531,7 +1534,7 @@ export default class WebRTCClient extends Emitter {
1531
1534
  audioElement.play().catch(() => { });
1532
1535
  }
1533
1536
  _cleanupMedia(session) {
1534
- const sessionId = getSipSessionId(session);
1537
+ const sessionId = getSipCallId(session);
1535
1538
  const localStream = this.getLocalStream(sessionId);
1536
1539
  if (localStream) {
1537
1540
  cleanupStream(localStream);
@@ -1550,7 +1553,7 @@ export default class WebRTCClient extends Emitter {
1550
1553
  };
1551
1554
  if (this._hasAudio() && isWeb()) {
1552
1555
  if (session) {
1553
- cleanLocalElement(getSipSessionId(session));
1556
+ cleanLocalElement(getSipCallId(session));
1554
1557
  }
1555
1558
  else {
1556
1559
  Object.keys(this.audioElements).forEach(id => cleanLocalElement(id));
@@ -1570,7 +1573,7 @@ export default class WebRTCClient extends Emitter {
1570
1573
  if (!pc) {
1571
1574
  return;
1572
1575
  }
1573
- const sessionId = getSipSessionId(session);
1576
+ const sessionId = getSipCallId(session);
1574
1577
  getStats(pc, (result) => {
1575
1578
  const { results, internal, nomore, ...stats } = result;
1576
1579
  this.statsIntervals[sessionId] = nomore;
@@ -1581,7 +1584,7 @@ export default class WebRTCClient extends Emitter {
1581
1584
  }, SEND_STATS_DELAY);
1582
1585
  }
1583
1586
  _stopSendingStats(session) {
1584
- const sessionId = getSipSessionId(session);
1587
+ const sessionId = getSipCallId(session);
1585
1588
  logger.trace('Check for stopping stats', {
1586
1589
  sessionId,
1587
1590
  ids: Object.keys(this.statsIntervals),
@@ -1632,18 +1635,18 @@ export default class WebRTCClient extends Emitter {
1632
1635
  async _accept(session, options = {}) {
1633
1636
  if (session.state === SessionState.Terminated || session.state === SessionState.Terminating) {
1634
1637
  const error = 'Trying to accept a terminated sipSession.';
1635
- logger.warn(error, { state: session.state, sessionId: session.id });
1638
+ logger.warn(error, { state: session.state, sessionId: getSipCallId(session) });
1636
1639
  throw new Error(error);
1637
1640
  }
1638
1641
  if (session.state !== SessionState.Initial) {
1639
1642
  const error = 'Trying to accept a non Initial sipSession.';
1640
- logger.warn(error, { state: session.state, sessionId: session.id });
1643
+ logger.warn(error, { state: session.state, sessionId: getSipCallId(session) });
1641
1644
  throw new Error(error);
1642
1645
  }
1643
1646
  // @ts-ignore: private
1644
1647
  if (!session.incomingInviteRequest.acceptable) {
1645
1648
  const error = 'Trying to reject a non `acceptable` session';
1646
- logger.warn(error, { state: session.state, sessionId: session.id });
1649
+ logger.warn(error, { state: session.state, sessionId: getSipCallId(session) });
1647
1650
  throw new Error(error);
1648
1651
  }
1649
1652
  try {
@@ -1655,12 +1658,12 @@ export default class WebRTCClient extends Emitter {
1655
1658
  }
1656
1659
  async _reject(session, options = {}) {
1657
1660
  if (session.state !== SessionState.Initial && session.state !== SessionState.Establishing) {
1658
- logger.warn('Trying to reject a session in a wrong state', { state: session.state, sessionId: session.id });
1661
+ logger.warn('Trying to reject a session in a wrong state', { state: session.state, sessionId: getSipCallId(session) });
1659
1662
  return;
1660
1663
  }
1661
1664
  // @ts-ignore: private
1662
1665
  if (!session.incomingInviteRequest.rejectable) {
1663
- logger.warn('Trying to reject a non `rejectable` session', { state: session.state, sessionId: session.id });
1666
+ logger.warn('Trying to reject a non `rejectable` session', { state: session.state, sessionId: getSipCallId(session) });
1664
1667
  return;
1665
1668
  }
1666
1669
  try {
@@ -1672,7 +1675,7 @@ export default class WebRTCClient extends Emitter {
1672
1675
  }
1673
1676
  async _cancel(session, options = {}) {
1674
1677
  if (session.state !== SessionState.Initial && session.state !== SessionState.Establishing) {
1675
- logger.warn('Trying to cancel a session in a wrong state', { state: session.state, sessionId: session.id });
1678
+ logger.warn('Trying to cancel a session in a wrong state', { state: session.state, sessionId: getSipCallId(session) });
1676
1679
  return;
1677
1680
  }
1678
1681
  try {
@@ -1684,7 +1687,7 @@ export default class WebRTCClient extends Emitter {
1684
1687
  }
1685
1688
  async _bye(session, options = {}) {
1686
1689
  if (session.state !== SessionState.Established) {
1687
- logger.warn('Trying to end a session in a wrong state', { state: session.state, sessionId: session.id });
1690
+ logger.warn('Trying to end a session in a wrong state', { state: session.state, sessionId: getSipCallId(session) });
1688
1691
  return null;
1689
1692
  }
1690
1693
  try {
@@ -18,6 +18,7 @@ const softphone_1 = __importDefault(require("../../voice/softphone"));
18
18
  const call_1 = __importDefault(require("../../voice/call"));
19
19
  const call_state_machine_1 = require("../../state-machine/call-state-machine");
20
20
  const softphone_state_machine_1 = require("../../state-machine/softphone-state-machine");
21
+ const Call_1 = __importDefault(require("../../domain/Call"));
21
22
  const InvalidStateTransition_1 = __importDefault(require("../../domain/InvalidStateTransition"));
22
23
  const uaOptions = {
23
24
  logBuiltinEnabled: false,
@@ -42,6 +43,7 @@ jest.mock('../../web-rtc-client', () => jest.fn().mockImplementation(() => ({
42
43
  answer: jest.fn(() => Promise.resolve()),
43
44
  hangup: jest.fn(() => Promise.resolve()),
44
45
  register: jest.fn(() => Promise.resolve()),
46
+ onCallEnded: jest.fn(() => Promise.resolve()),
45
47
  setOnHeartbeatTimeout: jest.fn(() => Promise.resolve()),
46
48
  setOnHeartbeatCallback: jest.fn(() => Promise.resolve()),
47
49
  on: jest.fn(),
@@ -49,22 +51,61 @@ jest.mock('../../web-rtc-client', () => jest.fn().mockImplementation(() => ({
49
51
  const ua = new sip_js_1.UserAgent(uaOptions);
50
52
  const sipCall = new sip_js_1.Inviter(ua, sip_js_1.UserAgent.makeURI('sip:1234@my.stack.io'));
51
53
  softphone_1.default.connect();
54
+ // @ts-ignore: private method
52
55
  softphone_1.default._sendAction(softphone_state_machine_1.Actions.REGISTER_DONE);
53
56
  const invalidStateTransition = (state, action) => new InvalidStateTransition_1.default(`Invalid state transition from ${state} with action ${action}`, state, action);
54
57
  describe('Call', () => {
58
+ describe('parsing an API call', () => {
59
+ it('Should parse an API call and transform it to a Call instance', () => __awaiter(void 0, void 0, void 0, function* () {
60
+ const apiCall = new Call_1.default({
61
+ id: '1234',
62
+ sipCallId: 'abcd',
63
+ isCaller: false,
64
+ isVideo: true,
65
+ recording: true,
66
+ callerName: '',
67
+ callerNumber: '',
68
+ calleeName: '',
69
+ calleeNumber: '0123423223',
70
+ dialedExtension: '',
71
+ lineId: null,
72
+ muted: true,
73
+ onHold: false,
74
+ startingTime: new Date(),
75
+ status: 'Up',
76
+ talkingToIds: [],
77
+ });
78
+ const call = call_1.default.parseCall(apiCall);
79
+ expect(call.recording).toBeTruthy();
80
+ expect(call.id).toBe(apiCall.sipCallId);
81
+ expect(call.apiId).toBe(apiCall.id);
82
+ expect(call.number).toBe(apiCall.calleeNumber);
83
+ expect(call.answerTime).toStrictEqual(apiCall.startingTime);
84
+ expect(call.isMuted()).toBeTruthy();
85
+ expect(call.state).toStrictEqual({ [call_state_machine_1.States.ESTABLISHED]: call_state_machine_1.EstablishedStates.MUTED });
86
+ expect(call.isEstablished()).toBeTruthy();
87
+ }));
88
+ });
55
89
  describe('accept', () => {
56
90
  it('Should throw an error when accepting a not ringing call', () => __awaiter(void 0, void 0, void 0, function* () {
57
91
  const call = new call_1.default(sipCall, softphone_1.default);
58
92
  yield expect(call.accept()).rejects.toThrowError(invalidStateTransition(call_state_machine_1.States.IDLE, call_state_machine_1.Actions.ACCEPT));
59
93
  }));
60
- it.only('Should throw an error when the softphone is not registered', () => __awaiter(void 0, void 0, void 0, function* () {
94
+ it('Should throw an error when the softphone is not registered', () => __awaiter(void 0, void 0, void 0, function* () {
61
95
  const call = new call_1.default(sipCall, softphone_1.default);
96
+ // @ts-ignore: private method
62
97
  call._sendAction(call_state_machine_1.Actions.INCOMING_CALL);
98
+ // @ts-ignore: private method
63
99
  softphone_1.default._sendAction(softphone_state_machine_1.Actions.TRANSPORT_CLOSED);
64
100
  yield expect(call.accept()).rejects.toThrowError(invalidStateTransition(call_state_machine_1.States.RINGING, call_state_machine_1.Actions.ACCEPT));
101
+ // Revert softphone state
102
+ softphone_1.default.connect();
103
+ // @ts-ignore: private method
104
+ softphone_1.default._sendAction(softphone_state_machine_1.Actions.REGISTER_DONE);
65
105
  }));
66
106
  it('Should not throw an error when accepting a not ringing call', () => __awaiter(void 0, void 0, void 0, function* () {
67
107
  const call = new call_1.default(sipCall, softphone_1.default);
108
+ // @ts-ignore: private method
68
109
  call._sendAction(call_state_machine_1.Actions.INCOMING_CALL);
69
110
  yield call.accept();
70
111
  expect(softphone_1.default.client.answer).toHaveBeenCalled();
@@ -77,10 +118,24 @@ describe('Call', () => {
77
118
  }));
78
119
  it('Should not throw an error when terminating an established call', () => __awaiter(void 0, void 0, void 0, function* () {
79
120
  const call = new call_1.default(sipCall, softphone_1.default);
121
+ // @ts-ignore: private method
80
122
  call._sendAction(call_state_machine_1.Actions.MAKE_CALL);
123
+ // @ts-ignore: private method
81
124
  call._sendAction(call_state_machine_1.Actions.REMOTLY_ACCEPTED);
82
125
  yield call.hangup();
83
126
  expect(softphone_1.default.client.hangup).toHaveBeenCalled();
84
127
  }));
85
128
  });
129
+ describe('state propagation', () => {
130
+ it('Should update the call state in events', (done) => {
131
+ const call = new call_1.default(sipCall, softphone_1.default);
132
+ // @ts-ignore: private method
133
+ call._sendAction(call_state_machine_1.Actions.MAKE_CALL);
134
+ call.on('remotelyAccepted', () => {
135
+ expect(call.state).toStrictEqual({ [call_state_machine_1.States.ESTABLISHED]: call_state_machine_1.EstablishedStates.ONGOING });
136
+ done();
137
+ });
138
+ call.onAccepted();
139
+ });
140
+ });
86
141
  });
package/lib/api/auth.js CHANGED
@@ -64,6 +64,9 @@ exports.default = ((client, baseUrl) => ({
64
64
  }
65
65
  return client.post(`${baseUrl}/token`, body, headers).then(Session_1.default.parse);
66
66
  }),
67
+ samlLogOut() {
68
+ return client.get(`${baseUrl}/saml/logout`, null, null);
69
+ },
67
70
  initiateIdpAuthentication: (domain, redirectUrl) => __awaiter(void 0, void 0, void 0, function* () {
68
71
  const body = {
69
72
  domain,
@@ -43,7 +43,7 @@ exports.default = {
43
43
  });
44
44
  client.on(client.REGISTERED, () => {
45
45
  const sipSession = client.call('*10');
46
- if (!sipSession || !(0, sdp_1.getSipSessionId)(sipSession)) {
46
+ if (!sipSession || !(0, sdp_1.getSipCallId)(sipSession)) {
47
47
  return handleError('Unable to make call through WebRTC');
48
48
  }
49
49
  setTimeout(() => {
@@ -46,8 +46,7 @@ class CallLog {
46
46
  }
47
47
  static parseNew(plain, session) {
48
48
  const callLog = CallLog.parse(plain);
49
- // @TODO: FIXME add verification declined vs missed call
50
- callLog.newMissedCall = session && session.hasExtension((plain.requested_extension || plain.destination_extension)) && !plain.answered;
49
+ callLog.newMissedCall = session && plain.destination_user_uuid === session.uuid && !plain.answered;
51
50
  return callLog;
52
51
  }
53
52
  static newFrom(profile) {
@@ -105,7 +104,7 @@ class CallLog {
105
104
  return this.callDirection === 'inbound';
106
105
  }
107
106
  isAnOutgoingCall(session) {
108
- console.warn(`@wazo/sdk
107
+ console.warn(`@wazo/sdk
109
108
  CallLog.isAnOutgoingcall(session) method is obsolete.
110
109
  Please use CallLog.isOutgoing(session).
111
110
  `);
@@ -119,7 +119,7 @@ class CTIPhone extends Emitter_1.default {
119
119
  number: callSession.number,
120
120
  });
121
121
  try {
122
- yield CallApi_1.default.cancelCall(callSession);
122
+ yield CallApi_1.default.cancelCall({ apiId: callSession.getId() });
123
123
  if (this.currentCall && callSession.callId === this.currentCall.id) {
124
124
  this.endCurrentCall(callSession);
125
125
  }
@@ -143,7 +143,7 @@ class CTIPhone extends Emitter_1.default {
143
143
  callId: callSession.getId(),
144
144
  number: callSession.number,
145
145
  });
146
- yield CallApi_1.default.cancelCall(callSession);
146
+ yield CallApi_1.default.cancelCall({ id: callSession.getId() });
147
147
  this.eventEmitter.emit('onCallEnded', callSession);
148
148
  });
149
149
  }