@wazo/sdk 0.39.0-beta.8 → 0.39.0

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 (146) hide show
  1. package/README.md +7 -7
  2. package/dist/wazo-sdk.js +12 -12
  3. package/esm/__tests__/api-client.test.js +7 -1
  4. package/esm/__tests__/web-rtc-client.test.js +10 -0
  5. package/esm/api/chatd.js +17 -3
  6. package/esm/api/dird.js +2 -2
  7. package/esm/api-client.js +4 -0
  8. package/esm/checker/checks/ice-ipv4.js +2 -1
  9. package/esm/domain/Contact.js +15 -8
  10. package/esm/domain/Phone/WebRTCPhone.js +9 -11
  11. package/esm/domain/Session.js +24 -0
  12. package/esm/domain/__tests__/Contact.test.js +200 -48
  13. package/esm/lib/WazoSessionDescriptionHandler.js +14 -11
  14. package/esm/service/IssueReporter.js +12 -2
  15. package/esm/service/__tests__/IssueReporter.test.js +12 -0
  16. package/esm/service/getApiClient.js +9 -0
  17. package/esm/simple/Auth.js +40 -5
  18. package/esm/simple/Phone.js +3 -1
  19. package/esm/simple/Websocket.js +1 -0
  20. package/esm/simple/room/Stream.js +3 -3
  21. package/esm/types/api/chatd.d.ts +1 -1
  22. package/esm/types/api/chatd.d.ts.map +1 -1
  23. package/esm/types/api/dird.d.ts.map +1 -1
  24. package/esm/types/api-client.d.ts +3 -2
  25. package/esm/types/api-client.d.ts.map +1 -1
  26. package/esm/types/checker/checks/ice-ipv4.d.ts.map +1 -1
  27. package/esm/types/domain/Contact.d.ts +1 -1
  28. package/esm/types/domain/Contact.d.ts.map +1 -1
  29. package/esm/types/domain/Phone/WebRTCPhone.d.ts +1 -1
  30. package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  31. package/esm/types/domain/Session.d.ts +2 -0
  32. package/esm/types/domain/Session.d.ts.map +1 -1
  33. package/esm/types/domain/types.d.ts +40 -14
  34. package/esm/types/domain/types.d.ts.map +1 -1
  35. package/esm/types/index.d.ts +2 -0
  36. package/esm/types/index.d.ts.map +1 -1
  37. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts +1 -1
  38. package/esm/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  39. package/esm/types/service/IssueReporter.d.ts +1 -0
  40. package/esm/types/service/IssueReporter.d.ts.map +1 -1
  41. package/esm/types/service/getApiClient.d.ts +2 -0
  42. package/esm/types/service/getApiClient.d.ts.map +1 -1
  43. package/esm/types/simple/Auth.d.ts.map +1 -1
  44. package/esm/types/simple/Phone.d.ts +4 -3
  45. package/esm/types/simple/Phone.d.ts.map +1 -1
  46. package/esm/types/simple/Websocket.d.ts.map +1 -1
  47. package/esm/types/simple/index.d.ts +1 -0
  48. package/esm/types/simple/index.d.ts.map +1 -1
  49. package/esm/types/utils/Emitter.d.ts +1 -1
  50. package/esm/types/utils/Heartbeat.d.ts +3 -2
  51. package/esm/types/utils/Heartbeat.d.ts.map +1 -1
  52. package/esm/types/utils/api-requester.d.ts +5 -1
  53. package/esm/types/utils/api-requester.d.ts.map +1 -1
  54. package/esm/types/web-rtc-client.d.ts +5 -29
  55. package/esm/types/web-rtc-client.d.ts.map +1 -1
  56. package/esm/types/websocket-client.d.ts +5 -1
  57. package/esm/types/websocket-client.d.ts.map +1 -1
  58. package/esm/utils/__tests__/api-requester.test.js +7 -2
  59. package/esm/utils/api-requester.js +23 -5
  60. package/esm/web-rtc-client.js +69 -40
  61. package/esm/websocket-client.js +9 -2
  62. package/lib/__tests__/api-client.test.js +7 -1
  63. package/lib/__tests__/web-rtc-client.test.js +16 -0
  64. package/lib/api/chatd.js +23 -7
  65. package/lib/api/dird.js +2 -2
  66. package/lib/api-client.js +4 -0
  67. package/lib/checker/checks/ice-ipv4.js +2 -1
  68. package/lib/domain/Contact.js +15 -8
  69. package/lib/domain/Phone/WebRTCPhone.js +9 -11
  70. package/lib/domain/Session.js +23 -0
  71. package/lib/domain/__tests__/Contact.test.js +175 -50
  72. package/lib/lib/WazoSessionDescriptionHandler.js +15 -12
  73. package/lib/service/IssueReporter.js +12 -2
  74. package/lib/service/__tests__/IssueReporter.test.js +12 -0
  75. package/lib/service/getApiClient.js +12 -1
  76. package/lib/simple/Auth.js +34 -4
  77. package/lib/simple/Phone.js +3 -1
  78. package/lib/simple/Websocket.js +1 -0
  79. package/lib/simple/room/Stream.js +3 -3
  80. package/lib/types/api/chatd.d.ts +1 -1
  81. package/lib/types/api/chatd.d.ts.map +1 -1
  82. package/lib/types/api/dird.d.ts.map +1 -1
  83. package/lib/types/api-client.d.ts +3 -2
  84. package/lib/types/api-client.d.ts.map +1 -1
  85. package/lib/types/checker/checks/ice-ipv4.d.ts.map +1 -1
  86. package/lib/types/domain/Contact.d.ts +1 -1
  87. package/lib/types/domain/Contact.d.ts.map +1 -1
  88. package/lib/types/domain/Phone/WebRTCPhone.d.ts +1 -1
  89. package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  90. package/lib/types/domain/Session.d.ts +2 -0
  91. package/lib/types/domain/Session.d.ts.map +1 -1
  92. package/lib/types/domain/types.d.ts +40 -14
  93. package/lib/types/domain/types.d.ts.map +1 -1
  94. package/lib/types/index.d.ts +2 -0
  95. package/lib/types/index.d.ts.map +1 -1
  96. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts +1 -1
  97. package/lib/types/lib/WazoSessionDescriptionHandler.d.ts.map +1 -1
  98. package/lib/types/service/IssueReporter.d.ts +1 -0
  99. package/lib/types/service/IssueReporter.d.ts.map +1 -1
  100. package/lib/types/service/getApiClient.d.ts +2 -0
  101. package/lib/types/service/getApiClient.d.ts.map +1 -1
  102. package/lib/types/simple/Auth.d.ts.map +1 -1
  103. package/lib/types/simple/Phone.d.ts +4 -3
  104. package/lib/types/simple/Phone.d.ts.map +1 -1
  105. package/lib/types/simple/Websocket.d.ts.map +1 -1
  106. package/lib/types/simple/index.d.ts +1 -0
  107. package/lib/types/simple/index.d.ts.map +1 -1
  108. package/lib/types/utils/Emitter.d.ts +1 -1
  109. package/lib/types/utils/Heartbeat.d.ts +3 -2
  110. package/lib/types/utils/Heartbeat.d.ts.map +1 -1
  111. package/lib/types/utils/api-requester.d.ts +5 -1
  112. package/lib/types/utils/api-requester.d.ts.map +1 -1
  113. package/lib/types/web-rtc-client.d.ts +5 -29
  114. package/lib/types/web-rtc-client.d.ts.map +1 -1
  115. package/lib/types/websocket-client.d.ts +5 -1
  116. package/lib/types/websocket-client.d.ts.map +1 -1
  117. package/lib/utils/__tests__/api-requester.test.js +7 -2
  118. package/lib/utils/api-requester.js +19 -5
  119. package/lib/web-rtc-client.js +67 -39
  120. package/lib/websocket-client.js +8 -2
  121. package/package.json +37 -35
  122. package/src/__tests__/api-client.test.ts +9 -1
  123. package/src/__tests__/web-rtc-client.test.ts +12 -0
  124. package/src/api/chatd.ts +22 -4
  125. package/src/api/dird.ts +3 -2
  126. package/src/api-client.ts +8 -2
  127. package/src/checker/checks/ice-ipv4.ts +2 -1
  128. package/src/domain/Contact.ts +16 -8
  129. package/src/domain/Phone/WebRTCPhone.ts +11 -12
  130. package/src/domain/Session.ts +28 -0
  131. package/src/domain/__tests__/Contact.test.ts +213 -54
  132. package/src/domain/types.ts +42 -14
  133. package/src/lib/WazoSessionDescriptionHandler.ts +15 -11
  134. package/src/service/IssueReporter.ts +13 -2
  135. package/src/service/__tests__/IssueReporter.test.ts +14 -0
  136. package/src/service/getApiClient.ts +12 -0
  137. package/src/simple/Auth.ts +58 -6
  138. package/src/simple/Phone.ts +15 -6
  139. package/src/simple/Websocket.ts +1 -0
  140. package/src/simple/room/Stream.ts +3 -3
  141. package/src/types/global.d.ts +1 -0
  142. package/src/utils/Heartbeat.ts +2 -2
  143. package/src/utils/__tests__/api-requester.test.ts +8 -2
  144. package/src/utils/api-requester.ts +31 -4
  145. package/src/web-rtc-client.ts +84 -70
  146. package/src/websocket-client.ts +14 -1
@@ -8,7 +8,6 @@ import type { InvitationRejectOptions } from 'sip.js/lib/api/invitation-reject-o
8
8
  import type { InviterCancelOptions } from 'sip.js/lib/api/inviter-cancel-options';
9
9
  import type { SessionByeOptions } from 'sip.js/lib/api/session-bye-options';
10
10
  import type { InvitationAcceptOptions } from 'sip.js/lib/api/invitation-accept-options';
11
-
12
11
  import type { SessionDialog } from 'sip.js/lib/core/dialogs/session-dialog';
13
12
  import type { IncomingRequestMessage } from 'sip.js/lib/core/messages/incoming-request-message';
14
13
  import type { SessionDescriptionHandlerFactoryOptions } from 'sip.js/lib/platform/web/session-description-handler/session-description-handler-factory-options';
@@ -29,7 +28,7 @@ import { defaultPeerConnectionConfiguration } from 'sip.js/lib/platform/web/sess
29
28
  import getStats from 'getstats';
30
29
 
31
30
  import { OutgoingByeRequest, OutgoingInviteRequest, OutgoingRequest } from 'sip.js/lib/core';
32
- import { Inviter, Invitation, Registerer } from 'sip.js/lib/api';
31
+ import { Inviter, Invitation, Registerer, Session } from 'sip.js/lib/api';
33
32
  import WazoSessionDescriptionHandler, { wazoMediaStreamFactory } from './lib/WazoSessionDescriptionHandler';
34
33
  import Emitter from './utils/Emitter';
35
34
  import ApiClient from './api-client';
@@ -37,6 +36,7 @@ import IssueReporter from './service/IssueReporter';
37
36
  import Heartbeat from './utils/Heartbeat';
38
37
  import { getVideoDirection, hasAnActiveVideo } from './utils/sdp';
39
38
  import { lastIndexOf } from './utils/array';
39
+ import type { MediaConfig, UserAgentConfigOverrides, WebRtcConfig, UserAgentOptions } from './domain/types';
40
40
 
41
41
  // We need to replace 0.0.0.0 to 127.0.0.1 in the sdp to avoid MOH during a createOffer.
42
42
  export const replaceLocalIpModifier = (description: Record<string, any>) => Promise.resolve({ // description is immutable... so we have to clone it or the `type` attribute won't be returned.
@@ -70,38 +70,17 @@ const ON_DISCONNECTED = 'onDisconnected';
70
70
  export const events = [REGISTERED, UNREGISTERED, REGISTRATION_FAILED, INVITE];
71
71
  export const transportEvents = [CONNECTED, DISCONNECTED, TRANSPORT_ERROR, MESSAGE];
72
72
  export class CanceledCallError extends Error {}
73
+
73
74
  const MAX_REGISTER_TRIES = 5;
74
- type MediaConfig = {
75
- audio: Record<string, any> | boolean;
76
- video?: Record<string, any> | boolean;
77
- localVideo?: Record<string, any> | boolean;
78
- };
79
- type WebRtcConfig = {
80
- displayName?: string;
81
- host: string;
82
- port?: number;
83
- websocketSip?: string;
84
- authorizationUser?: string;
85
- password?: string;
86
- uri?: string;
87
- media?: MediaConfig;
88
- iceCheckingTimeout?: number;
89
- log?: Record<string, any>;
90
- audioOutputDeviceId?: string;
91
- audioOutputVolume?: number;
92
- userAgentString?: string;
93
- heartbeatDelay?: number;
94
- heartbeatTimeout?: number;
95
- maxHeartbeats?: number;
96
- skipRegister?: boolean;
97
- }; // @see https://github.com/onsip/SIP.js/blob/master/src/Web/Simple.js
75
+ // setting a 24hr timeout and letting the backend define the actual value
76
+ const NO_ANSWER_TIMEOUT = 60 * 60 * 24; // in seconds
98
77
 
99
78
  export default class WebRTCClient extends Emitter {
100
79
  clientId: number;
101
80
 
102
81
  config: WebRtcConfig;
103
82
 
104
- uaConfigOverrides: Record<string, any> | null | undefined;
83
+ uaConfigOverrides?: UserAgentConfigOverrides;
105
84
 
106
85
  userAgent: UserAgent | null;
107
86
 
@@ -201,7 +180,7 @@ export default class WebRTCClient extends Emitter {
201
180
  return [];
202
181
  }
203
182
 
204
- constructor(config: WebRtcConfig, session: Invitation | Inviter | null | undefined, uaConfigOverrides: Record<string, any> | null | undefined = undefined) {
183
+ constructor(config: WebRtcConfig, session: Invitation | Inviter | null | undefined, uaConfigOverrides?: UserAgentConfigOverrides) {
205
184
  super();
206
185
 
207
186
  // For debug purpose
@@ -271,11 +250,11 @@ export default class WebRTCClient extends Emitter {
271
250
  this.audio = media.audio;
272
251
  }
273
252
 
274
- createUserAgent(configOverrides: Record<string, any> | null | undefined): UserAgent {
275
- const webRTCConfiguration = this._createWebRTCConfiguration(configOverrides);
253
+ createUserAgent(uaConfigOverrides?: UserAgentConfigOverrides): UserAgent {
254
+ const uaOptions = this._createUaOptions(uaConfigOverrides);
276
255
 
277
- logger.info('sdk webrtc, creating UA', { webRTCConfiguration, clientId: this.clientId });
278
- webRTCConfiguration.delegate = {
256
+ logger.info('sdk webrtc, creating UA', { uaOptions, clientId: this.clientId });
257
+ uaOptions.delegate = {
279
258
  onConnect: this.onConnect.bind(this),
280
259
  onDisconnect: this.onDisconnect.bind(this),
281
260
  onInvite: (invitation: Invitation) => {
@@ -293,7 +272,8 @@ export default class WebRTCClient extends Emitter {
293
272
  this.eventEmitter.emit(INVITE, invitation, this.sessionWantsToDoVideo(invitation), shouldAutoAnswer);
294
273
  },
295
274
  };
296
- const ua: any = new UserAgent(webRTCConfiguration);
275
+ const ua: any = new UserAgent(uaOptions);
276
+ ua.start();
297
277
 
298
278
  if (ua.transport && ua.transport.connectPromise) {
299
279
  ua.transport.connectPromise.catch((e: any) => {
@@ -511,19 +491,32 @@ export default class WebRTCClient extends Emitter {
511
491
  registerer: !!this.registerer,
512
492
  });
513
493
 
514
- if (!this.registerer) {
515
- return Promise.resolve();
516
- }
517
-
518
494
  try {
519
- return this.registerer.unregister().then(() => {
520
- logger.info('sdk webrtc unregistered', { clientId: this.clientId });
495
+ return new Promise((resolve, reject) => {
496
+ if (!this.registerer) {
497
+ return resolve();
498
+ }
499
+
500
+ const onRegisterStateChange = (state: string) => {
501
+ if (state === RegistererState.Unregistered) {
502
+ logger.info('sdk webrtc unregistered', { clientId: this.clientId });
503
+ if (this.registerer) {
504
+ this.registerer.stateChange.addListener(onRegisterStateChange);
505
+ }
506
+ this._cleanupRegister();
507
+
508
+ resolve();
509
+ }
510
+ };
521
511
 
522
- this._cleanupRegister();
523
- }).catch(e => {
524
- logger.error('sdk webrtc unregistering, promise error', e);
512
+ this.registerer.stateChange.addListener(onRegisterStateChange);
525
513
 
526
- this._cleanupRegister();
514
+ this.registerer.unregister().then().catch(e => {
515
+ logger.error('sdk webrtc unregistering, promise error', e);
516
+
517
+ this._cleanupRegister();
518
+ reject();
519
+ });
527
520
  });
528
521
  } catch (e: any) {
529
522
  logger.error('sdk webrtc unregistering, error', e);
@@ -593,9 +586,7 @@ export default class WebRTCClient extends Emitter {
593
586
  const inviteOptions: InviterInviteOptions = {
594
587
  requestDelegate: {
595
588
  onAccept: (response: IncomingResponse) => {
596
- // @ts-ignore
597
589
  if (session.sessionDescriptionHandler?.peerConnection) {
598
- // @ts-ignore
599
590
  session.sessionDescriptionHandler.peerConnection.sfu = conference;
600
591
  }
601
592
  // @ts-ignore
@@ -918,9 +909,9 @@ export default class WebRTCClient extends Emitter {
918
909
  isConference,
919
910
  };
920
911
 
921
- if (isConference) {
922
- this.mute(session);
923
- }
912
+ // We should also mute the call, because when holding a call during a voicemail, the audio is still sent with the
913
+ // `sendonly` direction
914
+ this.mute(session);
924
915
 
925
916
  session.sessionDescriptionHandlerOptionsReInvite = {
926
917
  // @ts-ignore
@@ -968,9 +959,7 @@ export default class WebRTCClient extends Emitter {
968
959
  return Promise.resolve();
969
960
  }
970
961
 
971
- if (isConference) {
972
- this.unmute(session);
973
- }
962
+ this.unmute(session);
974
963
 
975
964
  delete this.heldSessions[this.getSipSessionId(session)];
976
965
  session.sessionDescriptionHandlerOptionsReInvite = {
@@ -1395,9 +1384,9 @@ export default class WebRTCClient extends Emitter {
1395
1384
 
1396
1385
  // Release old video stream
1397
1386
  if (localStream) {
1398
- localStream.getVideoTracks().forEach(track => {
1399
- track.stop();
1400
- });
1387
+ localStream.getVideoTracks()
1388
+ .filter((track: MediaStreamTrack) => track.enabled)
1389
+ .forEach((track: MediaStreamTrack) => track.stop());
1401
1390
  }
1402
1391
 
1403
1392
  const constraints = {
@@ -1799,7 +1788,7 @@ export default class WebRTCClient extends Emitter {
1799
1788
  return;
1800
1789
  }
1801
1790
 
1802
- remoteStream.getTracks().forEach(track => {
1791
+ remoteStream.getVideoTracks().forEach(track => {
1803
1792
  remoteStream.removeTrack(track);
1804
1793
  });
1805
1794
 
@@ -1859,6 +1848,8 @@ export default class WebRTCClient extends Emitter {
1859
1848
  const audio: HTMLAudioElement = document.createElement('audio');
1860
1849
  audio.setAttribute('id', `audio-${sessionId}`);
1861
1850
 
1851
+ logger.info('creating audio element', { sessionId, audioOutputDeviceId: this.audioOutputDeviceId });
1852
+
1862
1853
  if ((audio as any).setSinkId && this.audioOutputDeviceId) {
1863
1854
  (audio as any).setSinkId(this.audioOutputDeviceId);
1864
1855
  }
@@ -2013,7 +2004,7 @@ export default class WebRTCClient extends Emitter {
2013
2004
  }));
2014
2005
  }
2015
2006
 
2016
- _createWebRTCConfiguration(configOverrides: Record<string, any> | null = {}): Record<string, any> {
2007
+ _createUaOptions(uaOptionsOverrides: UserAgentConfigOverrides = {}): UserAgentOptions {
2017
2008
  let {
2018
2009
  host,
2019
2010
  } = this.config;
@@ -2024,12 +2015,13 @@ export default class WebRTCClient extends Emitter {
2024
2015
  [host] = webSocketSip;
2025
2016
  port = Number(webSocketSip[1]);
2026
2017
  }
2018
+ const { userUuid } = this.config;
2027
2019
 
2028
- const config: Record<string, any> = {
2020
+ const uaOptions: UserAgentOptions = {
2021
+ noAnswerTimeout: NO_ANSWER_TIMEOUT,
2029
2022
  authorizationUsername: this.config.authorizationUser,
2030
2023
  authorizationPassword: this.config.password,
2031
2024
  displayName: this.config.displayName,
2032
- autoStart: true,
2033
2025
  hackIpInContact: true,
2034
2026
  contactParams: {
2035
2027
  transport: 'wss',
@@ -2041,7 +2033,8 @@ export default class WebRTCClient extends Emitter {
2041
2033
  userAgentString: this.config.userAgentString || 'wazo-sdk',
2042
2034
  reconnectionAttempts: 10000,
2043
2035
  reconnectionDelay: 5,
2044
- sessionDescriptionHandlerFactory: (session: Inviter | Invitation, options: SessionDescriptionHandlerFactoryOptions = {}) => {
2036
+
2037
+ sessionDescriptionHandlerFactory: (session: Session, options: SessionDescriptionHandlerFactoryOptions = {}) => {
2045
2038
  const uaLogger = session.userAgent.getLogger('sip.WazoSessionDescriptionHandler');
2046
2039
 
2047
2040
  const isWeb = this._isWeb();
@@ -2054,11 +2047,11 @@ export default class WebRTCClient extends Emitter {
2054
2047
  ...(options.peerConnectionConfiguration || {}),
2055
2048
  },
2056
2049
  };
2057
- return new WazoSessionDescriptionHandler(uaLogger, wazoMediaStreamFactory, sdhOptions, isWeb, session);
2050
+ return new WazoSessionDescriptionHandler(uaLogger, wazoMediaStreamFactory, sdhOptions, isWeb, session as Inviter | Invitation);
2058
2051
  },
2059
2052
  transportOptions: {
2060
- traceSip: configOverrides?.traceSip || false,
2061
- wsServers: `wss://${host}:${port}/api/asterisk/ws`,
2053
+ traceSip: uaOptionsOverrides?.traceSip || false,
2054
+ wsServers: `wss://${host}:${port}/api/asterisk/ws${userUuid ? `?userUuid=${userUuid}` : ''}`,
2062
2055
  },
2063
2056
  sessionDescriptionHandlerFactoryOptions: {
2064
2057
  modifiers: [replaceLocalIpModifier],
@@ -2074,19 +2067,23 @@ export default class WebRTCClient extends Emitter {
2074
2067
  rtcpMuxPolicy: 'require',
2075
2068
  iceServers: WebRTCClient.getIceServers(this.config.host),
2076
2069
  ...this._getRtcOptions(),
2077
- ...(configOverrides?.peerConnectionOptions || {}),
2070
+ ...(uaOptionsOverrides?.peerConnectionOptions || {}),
2078
2071
  },
2079
2072
  },
2080
2073
  // Configuration used in SDH to create the PeerConnection
2081
2074
  peerConnectionConfiguration: {
2082
2075
  rtcpMuxPolicy: 'require',
2083
2076
  iceServers: WebRTCClient.getIceServers(this.config.host),
2084
- ...(configOverrides?.peerConnectionOptions || {}),
2077
+ ...(uaOptionsOverrides?.peerConnectionOptions || {}),
2085
2078
  },
2086
2079
  },
2087
2080
  };
2088
- return { ...config,
2089
- ...configOverrides,
2081
+
2082
+ delete uaOptionsOverrides?.traceSip;
2083
+
2084
+ return {
2085
+ ...uaOptions,
2086
+ ...uaOptionsOverrides,
2090
2087
  };
2091
2088
  }
2092
2089
 
@@ -2283,6 +2280,20 @@ export default class WebRTCClient extends Emitter {
2283
2280
  // @ts-ignore
2284
2281
  const earlyStream = sipSession && sipSession.sessionDescriptionHandler ? sipSession.sessionDescriptionHandler.remoteMediaStream : null;
2285
2282
  const stream = newStream || removeStream || earlyStream;
2283
+ const shouldPause = audioElement.currentTime > 0 && !audioElement.paused && !audioElement.ended && audioElement.readyState > 2;
2284
+
2285
+ logger.info('setting up media', {
2286
+ sessionId,
2287
+ streams: {
2288
+ new: !!newStream,
2289
+ remove: !!removeStream,
2290
+ early: !!earlyStream,
2291
+ },
2292
+ isWeb: this._isWeb(),
2293
+ hasAudio: this._hasAudio(),
2294
+ isConference,
2295
+ shouldPause,
2296
+ });
2286
2297
 
2287
2298
  if (!this._isWeb() || !stream) {
2288
2299
  return;
@@ -2293,7 +2304,7 @@ export default class WebRTCClient extends Emitter {
2293
2304
  return;
2294
2305
  }
2295
2306
 
2296
- if (audioElement.currentTime > 0 && !audioElement.paused && !audioElement.ended && audioElement.readyState > 2) {
2307
+ if (shouldPause) {
2297
2308
  audioElement.pause();
2298
2309
  }
2299
2310
 
@@ -2337,7 +2348,7 @@ export default class WebRTCClient extends Emitter {
2337
2348
  }
2338
2349
 
2339
2350
  _cleanupStream(stream: MediaStream): void {
2340
- stream.getTracks().forEach(track => track.stop());
2351
+ stream.getTracks().filter(track => track.enabled).forEach(track => track.stop());
2341
2352
  }
2342
2353
 
2343
2354
  _toggleAudio(session: Inviter | Invitation, muteAudio: boolean): void {
@@ -2594,8 +2605,11 @@ export default class WebRTCClient extends Emitter {
2594
2605
  networkStats.totalTransportReceived = transportReceived;
2595
2606
  networkStats.transportReceived = transportReceived - lastTransportReceived;
2596
2607
  networkStats.bandwidth = networkStats.audioBytesSent + networkStats.audioBytesReceived + networkStats.videoBytesSent + networkStats.videoBytesReceived + networkStats.transportReceived + networkStats.transportSent;
2597
- this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
2598
- this.sessionNetworkStats[sessionId].push(networkStats);
2608
+
2609
+ if (this.sessionNetworkStats[sessionId]) {
2610
+ this.eventEmitter.emit(ON_NETWORK_STATS, session, networkStats, this.sessionNetworkStats[sessionId]);
2611
+ this.sessionNetworkStats[sessionId].push(networkStats);
2612
+ }
2599
2613
  }
2600
2614
 
2601
2615
  async _accept(session: Invitation, options: InvitationAcceptOptions = {}) {
@@ -1,5 +1,7 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
2
  import ReconnectingWebSocket from 'reconnecting-websocket';
3
+
4
+ import Session from './domain/Session';
3
5
  import Emitter from './utils/Emitter';
4
6
  import type { WebSocketMessage } from './types/WebSocketMessage';
5
7
  import IssueReporter from './service/IssueReporter';
@@ -18,6 +20,7 @@ type Arguments = {
18
20
  token: string;
19
21
  events?: Array<string>;
20
22
  version?: number;
23
+ session?: Session,
21
24
  heartbeat?: {
22
25
  delay: number;
23
26
  timeout: number;
@@ -99,6 +102,8 @@ const messageLogger = IssueReporter.loggerFor('wazo-ws-message');
99
102
  class WebSocketClient extends Emitter {
100
103
  initialized: boolean;
101
104
 
105
+ session?: Session;
106
+
102
107
  host: string | null | undefined;
103
108
 
104
109
  version: number | undefined;
@@ -130,6 +135,7 @@ class WebSocketClient extends Emitter {
130
135
  * @param events
131
136
  * @param version
132
137
  * @param heartbeat
138
+ * @param session
133
139
  * @param options @see https://github.com/pladaria/reconnecting-websocket#available-options
134
140
  */
135
141
  constructor({
@@ -138,12 +144,14 @@ class WebSocketClient extends Emitter {
138
144
  version,
139
145
  events,
140
146
  heartbeat,
147
+ session,
141
148
  }: Arguments, options: Record<string, any> = {
142
149
  host,
143
150
  token,
144
151
  version: 1,
145
152
  events: [],
146
153
  heartbeat: {},
154
+ session: null,
147
155
  }) {
148
156
  super();
149
157
  this.initialized = false;
@@ -153,6 +161,7 @@ class WebSocketClient extends Emitter {
153
161
  this.events = events;
154
162
  this.options = options;
155
163
  this.version = version;
164
+ this.session = session;
156
165
  this._boundOnHeartbeat = this._onHeartbeat.bind(this);
157
166
  const {
158
167
  delay,
@@ -424,7 +433,11 @@ class WebSocketClient extends Emitter {
424
433
  this.close();
425
434
  }
426
435
 
427
- const url = `wss://${this.host || ''}/api/websocketd/?token=${this.token || ''}&version=${this.version}`;
436
+ let url = `wss://${this.host || ''}/api/websocketd/?token=${this.token || ''}&version=${this.version}`;
437
+ if (this.session) {
438
+ url += `&userUuid=${this.session.uuid}`;
439
+ }
440
+
428
441
  logger.info('Wazo WS url computed to reconnect', {
429
442
  url,
430
443
  });