@wazo/sdk 0.38.4 → 0.38.7

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 (99) hide show
  1. package/README.md +4 -4
  2. package/dist/wazo-sdk.js +2 -2
  3. package/esm/__tests__/api-client.test.js +6 -0
  4. package/esm/__tests__/web-rtc-client.test.js +88 -3
  5. package/esm/api/calld.js +6 -0
  6. package/esm/api/ctid-ng.js +6 -0
  7. package/esm/api-client.js +6 -0
  8. package/esm/checker/Checker.js +38 -3
  9. package/esm/checker/checks/aor.js +6 -0
  10. package/esm/checker/checks/api.js +6 -0
  11. package/esm/checker/checks/index.js +38 -3
  12. package/esm/checker/checks/webrtc-transport.js +38 -3
  13. package/esm/checker/checks/webrtc.js +38 -3
  14. package/esm/domain/AdHocAPIConference.js +6 -0
  15. package/esm/domain/Call.js +6 -0
  16. package/esm/domain/CallSession.js +1 -1
  17. package/esm/domain/Features.js +6 -0
  18. package/esm/domain/Phone/CTIPhone.js +7 -1
  19. package/esm/domain/Phone/WebRTCPhone.js +3 -3
  20. package/esm/domain/__tests__/Call.test.js +6 -0
  21. package/esm/domain/__tests__/CallSession.test.js +1 -1
  22. package/esm/domain/__tests__/IndirectTransfer.test.js +1 -1
  23. package/esm/domain/__tests__/Line.test.js +5 -5
  24. package/esm/domain/__tests__/Room.test.js +1 -1
  25. package/esm/index.js +42 -8
  26. package/esm/lib/WazoSessionDescriptionHandler.js +30 -1
  27. package/esm/service/CallApi.js +6 -0
  28. package/esm/service/getApiClient.js +6 -0
  29. package/esm/simple/Auth.js +42 -8
  30. package/esm/simple/Configuration.js +42 -8
  31. package/esm/simple/Directory.js +6 -0
  32. package/esm/simple/Phone.js +42 -8
  33. package/esm/simple/Softphone.js +1 -2
  34. package/esm/simple/index.js +42 -8
  35. package/esm/simple/room/LocalParticipant.js +42 -8
  36. package/esm/simple/room/Participant.js +42 -8
  37. package/esm/simple/room/RemoteParticipant.js +42 -8
  38. package/esm/simple/room/Room.js +42 -8
  39. package/esm/simple/room/SipRoom.js +42 -8
  40. package/esm/simple/room/Stream.js +42 -8
  41. package/esm/simple/room/__tests__/RemoteParticipant.test.js +42 -8
  42. package/esm/simple/utils.js +42 -8
  43. package/esm/utils/__tests__/sdp.test.js +50 -0
  44. package/esm/utils/sdp.js +19 -1
  45. package/esm/web-rtc-client.js +38 -3
  46. package/lib/__tests__/api-client.test.js +6 -0
  47. package/lib/__tests__/web-rtc-client.test.js +88 -3
  48. package/lib/api/calld.js +6 -0
  49. package/lib/api/ctid-ng.js +6 -0
  50. package/lib/api-client.js +6 -0
  51. package/lib/checker/Checker.js +38 -3
  52. package/lib/checker/checks/aor.js +6 -0
  53. package/lib/checker/checks/api.js +6 -0
  54. package/lib/checker/checks/index.js +38 -3
  55. package/lib/checker/checks/webrtc-transport.js +38 -3
  56. package/lib/checker/checks/webrtc.js +38 -3
  57. package/lib/domain/AdHocAPIConference.js +6 -0
  58. package/lib/domain/Call.js +6 -0
  59. package/lib/domain/CallSession.js +1 -1
  60. package/lib/domain/Features.js +6 -0
  61. package/lib/domain/Phone/CTIPhone.js +7 -1
  62. package/lib/domain/Phone/WebRTCPhone.js +3 -3
  63. package/lib/domain/__tests__/Call.test.js +6 -0
  64. package/lib/domain/__tests__/CallSession.test.js +1 -1
  65. package/lib/domain/__tests__/IndirectTransfer.test.js +1 -1
  66. package/lib/domain/__tests__/Line.test.js +5 -5
  67. package/lib/domain/__tests__/Room.test.js +1 -1
  68. package/lib/index.js +42 -8
  69. package/lib/lib/WazoSessionDescriptionHandler.js +30 -1
  70. package/lib/service/CallApi.js +6 -0
  71. package/lib/service/getApiClient.js +6 -0
  72. package/lib/simple/Auth.js +42 -8
  73. package/lib/simple/Configuration.js +42 -8
  74. package/lib/simple/Directory.js +6 -0
  75. package/lib/simple/Phone.js +42 -8
  76. package/lib/simple/Softphone.js +1 -2
  77. package/lib/simple/index.js +42 -8
  78. package/lib/simple/room/LocalParticipant.js +42 -8
  79. package/lib/simple/room/Participant.js +42 -8
  80. package/lib/simple/room/RemoteParticipant.js +42 -8
  81. package/lib/simple/room/Room.js +42 -8
  82. package/lib/simple/room/SipRoom.js +42 -8
  83. package/lib/simple/room/Stream.js +42 -8
  84. package/lib/simple/room/__tests__/RemoteParticipant.test.js +42 -8
  85. package/lib/simple/utils.js +42 -8
  86. package/lib/utils/__tests__/sdp.test.js +50 -0
  87. package/lib/utils/sdp.js +19 -0
  88. package/lib/web-rtc-client.js +38 -3
  89. package/package.json +1 -1
  90. package/src/__tests__/web-rtc-client.test.js +50 -0
  91. package/src/domain/Call.js +6 -0
  92. package/src/domain/CallSession.js +1 -1
  93. package/src/domain/Phone/WebRTCPhone.js +2 -2
  94. package/src/domain/__tests__/Line.test.js +5 -5
  95. package/src/lib/WazoSessionDescriptionHandler.js +13 -2
  96. package/src/simple/Softphone.js +1 -2
  97. package/src/utils/__tests__/sdp.test.js +33 -1
  98. package/src/utils/sdp.js +18 -0
  99. package/src/web-rtc-client.js +2 -2
@@ -3071,6 +3071,7 @@ const RECORD_STATE_ACTIVE = 'active';
3071
3071
 
3072
3072
 
3073
3073
 
3074
+
3074
3075
 
3075
3076
 
3076
3077
 
@@ -3081,6 +3082,7 @@ const RECORD_STATE_ACTIVE = 'active';
3081
3082
 
3082
3083
 
3083
3084
 
3085
+
3084
3086
 
3085
3087
 
3086
3088
 
@@ -3109,6 +3111,7 @@ class Call {
3109
3111
 
3110
3112
 
3111
3113
 
3114
+
3112
3115
 
3113
3116
 
3114
3117
 
@@ -3133,6 +3136,7 @@ class Call {
3133
3136
  calleeNumber: plain.peer_caller_id_number,
3134
3137
  dialedExtension: plain.dialed_extension,
3135
3138
  isCaller: plain.is_caller,
3139
+ isVideo: plain.is_video,
3136
3140
  muted: plain.muted,
3137
3141
  onHold: plain.on_hold,
3138
3142
  status: plain.status,
@@ -3156,6 +3160,7 @@ class Call {
3156
3160
  calleeNumber,
3157
3161
  dialedExtension,
3158
3162
  isCaller,
3163
+ isVideo,
3159
3164
  lineId,
3160
3165
  muted,
3161
3166
  onHold,
@@ -3179,6 +3184,7 @@ class Call {
3179
3184
  this.startingTime = startingTime;
3180
3185
  this.talkingToIds = talkingToIds || [];
3181
3186
  this.recording = recording;
3187
+ this.isVideo = !!isVideo;
3182
3188
 
3183
3189
  // Useful to compare instead of instanceof with minified code
3184
3190
  this.type = 'Call';
@@ -3652,7 +3658,7 @@ class CallSession {
3652
3658
  ringing: call.isRinging(),
3653
3659
  answered: call.isUp(),
3654
3660
  answeredBySystem: call.isUp() && call.talkingToIds.length === 0,
3655
- cameraEnabled: false,
3661
+ cameraEnabled: call.isVideo,
3656
3662
  dialedExtension: call.dialedExtension,
3657
3663
  call,
3658
3664
  conference: false, // @FIXME?
@@ -6198,6 +6204,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
6198
6204
  return fixed;
6199
6205
  };
6200
6206
 
6207
+ const addIcesInAllBundles = (sdp ) => {
6208
+ const parsedSdp = sdpParser.parse(sdp);
6209
+
6210
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
6211
+ if (!mediaWithCandidate) {
6212
+ return sdp;
6213
+ }
6214
+
6215
+ const { candidates } = mediaWithCandidate;
6216
+
6217
+ parsedSdp.media = parsedSdp.media.map(media => ({
6218
+ ...media,
6219
+ candidates: media.candidates || candidates,
6220
+ }));
6221
+
6222
+ return sdpParser.write(parsedSdp);
6223
+ };
6224
+
6201
6225
  /* global RTCSessionDescriptionInit, navigator */
6202
6226
 
6203
6227
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -6296,6 +6320,14 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
6296
6320
  wazoLogger.trace('onicecandidate', event.candidate ? event.candidate.candidate : { done: true });
6297
6321
  if (event.candidate) {
6298
6322
  this.gatheredCandidates.push(parseCandidate$1(event.candidate.candidate));
6323
+
6324
+ // When receiving a `srflx` or a `relay` candidate, consider the negotiation done.
6325
+ if (event.candidate.candidate.indexOf('srflx') !== -1 || event.candidate.candidate.indexOf('relay') !== -1) {
6326
+ wazoLogger.info('A valid ice was found, triggering ice gathering complete callback.', {
6327
+ ice: event.candidate.candidate,
6328
+ });
6329
+ this.iceGatheringComplete();
6330
+ }
6299
6331
  }
6300
6332
  };
6301
6333
 
@@ -6319,7 +6351,10 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
6319
6351
 
6320
6352
  // Check if we got ICEs
6321
6353
  if (sdp.indexOf('a=candidate') !== -1) {
6322
- return description;
6354
+ return {
6355
+ type: description.type,
6356
+ sdp: addIcesInAllBundles(sdp),
6357
+ };
6323
6358
  }
6324
6359
 
6325
6360
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -7779,11 +7814,11 @@ class WebRTCClient extends Emitter {
7779
7814
  });
7780
7815
  }
7781
7816
 
7782
- changeAudioInputDevice(id , session ) {
7817
+ changeAudioInputDevice(id , session , force ) {
7783
7818
  const currentId = this.getAudioDeviceId();
7784
7819
  logger$8.info('setting audio input device', { id, currentId, session: !!session });
7785
7820
 
7786
- if (id === currentId) {
7821
+ if (!force && id === currentId) {
7787
7822
  return null;
7788
7823
  }
7789
7824
 
@@ -9579,10 +9614,10 @@ class WebRTCPhone extends Emitter {
9579
9614
  this.audioRingVolume = volume;
9580
9615
  }
9581
9616
 
9582
- changeAudioInputDevice(id ) {
9617
+ changeAudioInputDevice(id , force ) {
9583
9618
  logger$7.info('WebRTC phone - changeAudio input device', { deviceId: id });
9584
9619
 
9585
- return this.client.changeAudioInputDevice(id, this.currentSipSession);
9620
+ return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
9586
9621
  }
9587
9622
 
9588
9623
  changeVideoInputDevice(id ) {
@@ -14091,8 +14126,7 @@ class Softphone {
14091
14126
  window.addEventListener('message', this._onMessage.bind(this), false);
14092
14127
 
14093
14128
  if (!server) {
14094
- // eslint-disable-next-line no-param-reassign
14095
- server = 'stack.dev.wazo.io';
14129
+ throw new Error('`server` is not set');
14096
14130
  }
14097
14131
 
14098
14132
  const config = { server };
@@ -3071,6 +3071,7 @@ const RECORD_STATE_ACTIVE = 'active';
3071
3071
 
3072
3072
 
3073
3073
 
3074
+
3074
3075
 
3075
3076
 
3076
3077
 
@@ -3081,6 +3082,7 @@ const RECORD_STATE_ACTIVE = 'active';
3081
3082
 
3082
3083
 
3083
3084
 
3085
+
3084
3086
 
3085
3087
 
3086
3088
 
@@ -3109,6 +3111,7 @@ class Call {
3109
3111
 
3110
3112
 
3111
3113
 
3114
+
3112
3115
 
3113
3116
 
3114
3117
 
@@ -3133,6 +3136,7 @@ class Call {
3133
3136
  calleeNumber: plain.peer_caller_id_number,
3134
3137
  dialedExtension: plain.dialed_extension,
3135
3138
  isCaller: plain.is_caller,
3139
+ isVideo: plain.is_video,
3136
3140
  muted: plain.muted,
3137
3141
  onHold: plain.on_hold,
3138
3142
  status: plain.status,
@@ -3156,6 +3160,7 @@ class Call {
3156
3160
  calleeNumber,
3157
3161
  dialedExtension,
3158
3162
  isCaller,
3163
+ isVideo,
3159
3164
  lineId,
3160
3165
  muted,
3161
3166
  onHold,
@@ -3179,6 +3184,7 @@ class Call {
3179
3184
  this.startingTime = startingTime;
3180
3185
  this.talkingToIds = talkingToIds || [];
3181
3186
  this.recording = recording;
3187
+ this.isVideo = !!isVideo;
3182
3188
 
3183
3189
  // Useful to compare instead of instanceof with minified code
3184
3190
  this.type = 'Call';
@@ -3652,7 +3658,7 @@ class CallSession {
3652
3658
  ringing: call.isRinging(),
3653
3659
  answered: call.isUp(),
3654
3660
  answeredBySystem: call.isUp() && call.talkingToIds.length === 0,
3655
- cameraEnabled: false,
3661
+ cameraEnabled: call.isVideo,
3656
3662
  dialedExtension: call.dialedExtension,
3657
3663
  call,
3658
3664
  conference: false, // @FIXME?
@@ -6198,6 +6204,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
6198
6204
  return fixed;
6199
6205
  };
6200
6206
 
6207
+ const addIcesInAllBundles = (sdp ) => {
6208
+ const parsedSdp = sdpParser.parse(sdp);
6209
+
6210
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
6211
+ if (!mediaWithCandidate) {
6212
+ return sdp;
6213
+ }
6214
+
6215
+ const { candidates } = mediaWithCandidate;
6216
+
6217
+ parsedSdp.media = parsedSdp.media.map(media => ({
6218
+ ...media,
6219
+ candidates: media.candidates || candidates,
6220
+ }));
6221
+
6222
+ return sdpParser.write(parsedSdp);
6223
+ };
6224
+
6201
6225
  /* global RTCSessionDescriptionInit, navigator */
6202
6226
 
6203
6227
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -6296,6 +6320,14 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
6296
6320
  wazoLogger.trace('onicecandidate', event.candidate ? event.candidate.candidate : { done: true });
6297
6321
  if (event.candidate) {
6298
6322
  this.gatheredCandidates.push(parseCandidate$1(event.candidate.candidate));
6323
+
6324
+ // When receiving a `srflx` or a `relay` candidate, consider the negotiation done.
6325
+ if (event.candidate.candidate.indexOf('srflx') !== -1 || event.candidate.candidate.indexOf('relay') !== -1) {
6326
+ wazoLogger.info('A valid ice was found, triggering ice gathering complete callback.', {
6327
+ ice: event.candidate.candidate,
6328
+ });
6329
+ this.iceGatheringComplete();
6330
+ }
6299
6331
  }
6300
6332
  };
6301
6333
 
@@ -6319,7 +6351,10 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
6319
6351
 
6320
6352
  // Check if we got ICEs
6321
6353
  if (sdp.indexOf('a=candidate') !== -1) {
6322
- return description;
6354
+ return {
6355
+ type: description.type,
6356
+ sdp: addIcesInAllBundles(sdp),
6357
+ };
6323
6358
  }
6324
6359
 
6325
6360
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -7779,11 +7814,11 @@ class WebRTCClient extends Emitter {
7779
7814
  });
7780
7815
  }
7781
7816
 
7782
- changeAudioInputDevice(id , session ) {
7817
+ changeAudioInputDevice(id , session , force ) {
7783
7818
  const currentId = this.getAudioDeviceId();
7784
7819
  logger$8.info('setting audio input device', { id, currentId, session: !!session });
7785
7820
 
7786
- if (id === currentId) {
7821
+ if (!force && id === currentId) {
7787
7822
  return null;
7788
7823
  }
7789
7824
 
@@ -9579,10 +9614,10 @@ class WebRTCPhone extends Emitter {
9579
9614
  this.audioRingVolume = volume;
9580
9615
  }
9581
9616
 
9582
- changeAudioInputDevice(id ) {
9617
+ changeAudioInputDevice(id , force ) {
9583
9618
  logger$7.info('WebRTC phone - changeAudio input device', { deviceId: id });
9584
9619
 
9585
- return this.client.changeAudioInputDevice(id, this.currentSipSession);
9620
+ return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
9586
9621
  }
9587
9622
 
9588
9623
  changeVideoInputDevice(id ) {
@@ -14075,8 +14110,7 @@ class Softphone {
14075
14110
  window.addEventListener('message', this._onMessage.bind(this), false);
14076
14111
 
14077
14112
  if (!server) {
14078
- // eslint-disable-next-line no-param-reassign
14079
- server = 'stack.dev.wazo.io';
14113
+ throw new Error('`server` is not set');
14080
14114
  }
14081
14115
 
14082
14116
  const config = { server };
@@ -98,6 +98,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
98
98
  return fixed;
99
99
  };
100
100
 
101
+ const addIcesInAllBundles = (sdp ) => {
102
+ const parsedSdp = sdpParser.parse(sdp);
103
+
104
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
105
+ if (!mediaWithCandidate) {
106
+ return sdp;
107
+ }
108
+
109
+ const { candidates } = mediaWithCandidate;
110
+
111
+ parsedSdp.media = parsedSdp.media.map(media => ({
112
+ ...media,
113
+ candidates: media.candidates || candidates,
114
+ }));
115
+
116
+ return sdpParser.write(parsedSdp);
117
+ };
118
+
101
119
  /* eslint-disable max-len */
102
120
 
103
121
  const goodSdp = `
@@ -262,4 +280,36 @@ describe('SDP utils', () => {
262
280
  expect(hasAnActiveVideo(inactiveVideo)).toBeFalsy();
263
281
  });
264
282
  });
283
+
284
+ describe('Adding candidate in all bundles ', () => {
285
+ it('should add candidate everywhere', async () => {
286
+ const audioWithoutCandidate = `
287
+ c=IN IP4 203.0.113.1
288
+ m=audio 54400 RTP/SAVPF 0 96
289
+ m=video 54400 RTP/SAVPF 0 96
290
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
291
+ a=candidate:3996450952 1 udp 41819903 14.72.21.2 65092 typ relay raddr 0.0.0.0 rport 0 generation 0 network-id 3 network-cost 10
292
+ `;
293
+ const fixedAudioWithoutCandidate = sdpParser.parse(addIcesInAllBundles(audioWithoutCandidate));
294
+
295
+ expect(fixedAudioWithoutCandidate.media[0].candidates[0].type).toBe('host');
296
+ expect(fixedAudioWithoutCandidate.media[0].candidates[1].type).toBe('relay');
297
+ expect(fixedAudioWithoutCandidate.media[1].candidates[0].type).toBe('host');
298
+ expect(fixedAudioWithoutCandidate.media[1].candidates[1].type).toBe('relay');
299
+
300
+ // It should not add candidate if already present
301
+ const audioWithCandidate = `
302
+ c=IN IP4 203.0.113.1
303
+ m=audio 54400 RTP/SAVPF 0 96
304
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ srflx
305
+
306
+ m=video 54400 RTP/SAVPF 0 96
307
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
308
+ `;
309
+ const fixedAudioWithCandidate = sdpParser.parse(addIcesInAllBundles(audioWithCandidate));
310
+
311
+ expect(fixedAudioWithCandidate.media[0].candidates[0].type).toBe('srflx');
312
+ expect(fixedAudioWithCandidate.media[1].candidates[0].type).toBe('host');
313
+ });
314
+ });
265
315
  });
package/esm/utils/sdp.js CHANGED
@@ -122,4 +122,22 @@ const fixSdp = (sdp , candidates , forcePort = true)
122
122
  return fixed;
123
123
  };
124
124
 
125
- export { activateVideoModifier, areCandidateValid, deactivateVideoModifier, fixBundle, fixSdp, getCandidates, getVideoDirection, hasAnActiveVideo, isSdpValid, parseCandidate, toggleVideoDirection };
125
+ const addIcesInAllBundles = (sdp ) => {
126
+ const parsedSdp = sdpParser.parse(sdp);
127
+
128
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
129
+ if (!mediaWithCandidate) {
130
+ return sdp;
131
+ }
132
+
133
+ const { candidates } = mediaWithCandidate;
134
+
135
+ parsedSdp.media = parsedSdp.media.map(media => ({
136
+ ...media,
137
+ candidates: media.candidates || candidates,
138
+ }));
139
+
140
+ return sdpParser.write(parsedSdp);
141
+ };
142
+
143
+ export { activateVideoModifier, addIcesInAllBundles, areCandidateValid, deactivateVideoModifier, fixBundle, fixSdp, getCandidates, getVideoDirection, hasAnActiveVideo, isSdpValid, parseCandidate, toggleVideoDirection };
@@ -778,6 +778,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
778
778
  return fixed;
779
779
  };
780
780
 
781
+ const addIcesInAllBundles = (sdp ) => {
782
+ const parsedSdp = sdpParser.parse(sdp);
783
+
784
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
785
+ if (!mediaWithCandidate) {
786
+ return sdp;
787
+ }
788
+
789
+ const { candidates } = mediaWithCandidate;
790
+
791
+ parsedSdp.media = parsedSdp.media.map(media => ({
792
+ ...media,
793
+ candidates: media.candidates || candidates,
794
+ }));
795
+
796
+ return sdpParser.write(parsedSdp);
797
+ };
798
+
781
799
  /* global RTCSessionDescriptionInit, navigator */
782
800
 
783
801
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -876,6 +894,14 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
876
894
  wazoLogger.trace('onicecandidate', event.candidate ? event.candidate.candidate : { done: true });
877
895
  if (event.candidate) {
878
896
  this.gatheredCandidates.push(parseCandidate(event.candidate.candidate));
897
+
898
+ // When receiving a `srflx` or a `relay` candidate, consider the negotiation done.
899
+ if (event.candidate.candidate.indexOf('srflx') !== -1 || event.candidate.candidate.indexOf('relay') !== -1) {
900
+ wazoLogger.info('A valid ice was found, triggering ice gathering complete callback.', {
901
+ ice: event.candidate.candidate,
902
+ });
903
+ this.iceGatheringComplete();
904
+ }
879
905
  }
880
906
  };
881
907
 
@@ -899,7 +925,10 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
899
925
 
900
926
  // Check if we got ICEs
901
927
  if (sdp.indexOf('a=candidate') !== -1) {
902
- return description;
928
+ return {
929
+ type: description.type,
930
+ sdp: addIcesInAllBundles(sdp),
931
+ };
903
932
  }
904
933
 
905
934
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -3599,6 +3628,7 @@ const RECORD_STATE_ACTIVE = 'active';
3599
3628
 
3600
3629
 
3601
3630
 
3631
+
3602
3632
 
3603
3633
 
3604
3634
 
@@ -3609,6 +3639,7 @@ const RECORD_STATE_ACTIVE = 'active';
3609
3639
 
3610
3640
 
3611
3641
 
3642
+
3612
3643
 
3613
3644
 
3614
3645
 
@@ -3637,6 +3668,7 @@ class Call {
3637
3668
 
3638
3669
 
3639
3670
 
3671
+
3640
3672
 
3641
3673
 
3642
3674
 
@@ -3661,6 +3693,7 @@ class Call {
3661
3693
  calleeNumber: plain.peer_caller_id_number,
3662
3694
  dialedExtension: plain.dialed_extension,
3663
3695
  isCaller: plain.is_caller,
3696
+ isVideo: plain.is_video,
3664
3697
  muted: plain.muted,
3665
3698
  onHold: plain.on_hold,
3666
3699
  status: plain.status,
@@ -3684,6 +3717,7 @@ class Call {
3684
3717
  calleeNumber,
3685
3718
  dialedExtension,
3686
3719
  isCaller,
3720
+ isVideo,
3687
3721
  lineId,
3688
3722
  muted,
3689
3723
  onHold,
@@ -3707,6 +3741,7 @@ class Call {
3707
3741
  this.startingTime = startingTime;
3708
3742
  this.talkingToIds = talkingToIds || [];
3709
3743
  this.recording = recording;
3744
+ this.isVideo = !!isVideo;
3710
3745
 
3711
3746
  // Useful to compare instead of instanceof with minified code
3712
3747
  this.type = 'Call';
@@ -6409,11 +6444,11 @@ class WebRTCClient extends Emitter {
6409
6444
  });
6410
6445
  }
6411
6446
 
6412
- changeAudioInputDevice(id , session ) {
6447
+ changeAudioInputDevice(id , session , force ) {
6413
6448
  const currentId = this.getAudioDeviceId();
6414
6449
  logger.info('setting audio input device', { id, currentId, session: !!session });
6415
6450
 
6416
- if (id === currentId) {
6451
+ if (!force && id === currentId) {
6417
6452
  return null;
6418
6453
  }
6419
6454
 
@@ -3057,6 +3057,7 @@ const RECORD_STATE_ACTIVE = 'active';
3057
3057
 
3058
3058
 
3059
3059
 
3060
+
3060
3061
 
3061
3062
 
3062
3063
 
@@ -3067,6 +3068,7 @@ const RECORD_STATE_ACTIVE = 'active';
3067
3068
 
3068
3069
 
3069
3070
 
3071
+
3070
3072
 
3071
3073
 
3072
3074
 
@@ -3095,6 +3097,7 @@ class Call {
3095
3097
 
3096
3098
 
3097
3099
 
3100
+
3098
3101
 
3099
3102
 
3100
3103
 
@@ -3119,6 +3122,7 @@ class Call {
3119
3122
  calleeNumber: plain.peer_caller_id_number,
3120
3123
  dialedExtension: plain.dialed_extension,
3121
3124
  isCaller: plain.is_caller,
3125
+ isVideo: plain.is_video,
3122
3126
  muted: plain.muted,
3123
3127
  onHold: plain.on_hold,
3124
3128
  status: plain.status,
@@ -3142,6 +3146,7 @@ class Call {
3142
3146
  calleeNumber,
3143
3147
  dialedExtension,
3144
3148
  isCaller,
3149
+ isVideo,
3145
3150
  lineId,
3146
3151
  muted,
3147
3152
  onHold,
@@ -3165,6 +3170,7 @@ class Call {
3165
3170
  this.startingTime = startingTime;
3166
3171
  this.talkingToIds = talkingToIds || [];
3167
3172
  this.recording = recording;
3173
+ this.isVideo = !!isVideo;
3168
3174
 
3169
3175
  // Useful to compare instead of instanceof with minified code
3170
3176
  this.type = 'Call';
@@ -787,6 +787,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
787
787
  return fixed;
788
788
  };
789
789
 
790
+ const addIcesInAllBundles = (sdp ) => {
791
+ const parsedSdp = sdpParser__default['default'].parse(sdp);
792
+
793
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
794
+ if (!mediaWithCandidate) {
795
+ return sdp;
796
+ }
797
+
798
+ const { candidates } = mediaWithCandidate;
799
+
800
+ parsedSdp.media = parsedSdp.media.map(media => ({
801
+ ...media,
802
+ candidates: media.candidates || candidates,
803
+ }));
804
+
805
+ return sdpParser__default['default'].write(parsedSdp);
806
+ };
807
+
790
808
  /* global RTCSessionDescriptionInit, navigator */
791
809
 
792
810
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -885,6 +903,14 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
885
903
  wazoLogger.trace('onicecandidate', event.candidate ? event.candidate.candidate : { done: true });
886
904
  if (event.candidate) {
887
905
  this.gatheredCandidates.push(parseCandidate(event.candidate.candidate));
906
+
907
+ // When receiving a `srflx` or a `relay` candidate, consider the negotiation done.
908
+ if (event.candidate.candidate.indexOf('srflx') !== -1 || event.candidate.candidate.indexOf('relay') !== -1) {
909
+ wazoLogger.info('A valid ice was found, triggering ice gathering complete callback.', {
910
+ ice: event.candidate.candidate,
911
+ });
912
+ this.iceGatheringComplete();
913
+ }
888
914
  }
889
915
  };
890
916
 
@@ -908,7 +934,10 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
908
934
 
909
935
  // Check if we got ICEs
910
936
  if (sdp.indexOf('a=candidate') !== -1) {
911
- return description;
937
+ return {
938
+ type: description.type,
939
+ sdp: addIcesInAllBundles(sdp),
940
+ };
912
941
  }
913
942
 
914
943
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -3608,6 +3637,7 @@ const RECORD_STATE_ACTIVE = 'active';
3608
3637
 
3609
3638
 
3610
3639
 
3640
+
3611
3641
 
3612
3642
 
3613
3643
 
@@ -3618,6 +3648,7 @@ const RECORD_STATE_ACTIVE = 'active';
3618
3648
 
3619
3649
 
3620
3650
 
3651
+
3621
3652
 
3622
3653
 
3623
3654
 
@@ -3646,6 +3677,7 @@ class Call {
3646
3677
 
3647
3678
 
3648
3679
 
3680
+
3649
3681
 
3650
3682
 
3651
3683
 
@@ -3670,6 +3702,7 @@ class Call {
3670
3702
  calleeNumber: plain.peer_caller_id_number,
3671
3703
  dialedExtension: plain.dialed_extension,
3672
3704
  isCaller: plain.is_caller,
3705
+ isVideo: plain.is_video,
3673
3706
  muted: plain.muted,
3674
3707
  onHold: plain.on_hold,
3675
3708
  status: plain.status,
@@ -3693,6 +3726,7 @@ class Call {
3693
3726
  calleeNumber,
3694
3727
  dialedExtension,
3695
3728
  isCaller,
3729
+ isVideo,
3696
3730
  lineId,
3697
3731
  muted,
3698
3732
  onHold,
@@ -3716,6 +3750,7 @@ class Call {
3716
3750
  this.startingTime = startingTime;
3717
3751
  this.talkingToIds = talkingToIds || [];
3718
3752
  this.recording = recording;
3753
+ this.isVideo = !!isVideo;
3719
3754
 
3720
3755
  // Useful to compare instead of instanceof with minified code
3721
3756
  this.type = 'Call';
@@ -6415,11 +6450,11 @@ class WebRTCClient extends Emitter {
6415
6450
  });
6416
6451
  }
6417
6452
 
6418
- changeAudioInputDevice(id , session ) {
6453
+ changeAudioInputDevice(id , session , force ) {
6419
6454
  const currentId = this.getAudioDeviceId();
6420
6455
  logger.info('setting audio input device', { id, currentId, session: !!session });
6421
6456
 
6422
- if (id === currentId) {
6457
+ if (!force && id === currentId) {
6423
6458
  return null;
6424
6459
  }
6425
6460
 
@@ -7603,3 +7638,53 @@ describe('WebRTC client', () => {
7603
7638
  expect(client.isAudioMuted(oldKindUnmuted)).toBeFalsy();
7604
7639
  });
7605
7640
  });
7641
+
7642
+ describe('changeAudioInputDevice', () => {
7643
+ const defaultId = 'default';
7644
+ const deviceId = 'device1';
7645
+ const constraints = { audio: { deviceId: { exact: defaultId } }, video: null };
7646
+
7647
+ const session = {
7648
+ sessionDescriptionHandler: {
7649
+ peerConnection: {
7650
+ getSenders: () => [{ track: { kind: 'audio', enabled: true } }],
7651
+ },
7652
+ },
7653
+ };
7654
+
7655
+ const stream = {};
7656
+ const getAudioTracksMock = jest.fn(() => []);
7657
+ Object.defineProperty(stream, 'getAudioTracks', {
7658
+ value: getAudioTracksMock,
7659
+ });
7660
+
7661
+ const getUserMediaMock = jest.fn(async () => {
7662
+ return new Promise(resolve => {
7663
+ resolve(stream);
7664
+ });
7665
+ });
7666
+
7667
+ Object.defineProperty(global.navigator, 'mediaDevices', {
7668
+ value: {
7669
+ getUserMedia: getUserMediaMock,
7670
+ },
7671
+ });
7672
+
7673
+ it('should change the audio input track if the provided id is different', async () => {
7674
+ client.setMediaConstraints(constraints);
7675
+ expect(client.getAudioDeviceId()).toBe(defaultId);
7676
+ expect(client.changeAudioInputDevice(deviceId, session)).toBeTruthy();
7677
+ });
7678
+
7679
+ it('should NOT change the audio input track if the provided id is the same', async () => {
7680
+ client.setMediaConstraints(constraints);
7681
+ expect(client.getAudioDeviceId()).toBe(defaultId);
7682
+ expect(client.changeAudioInputDevice(defaultId, session)).toBeFalsy();
7683
+ });
7684
+
7685
+ it('should change the audio input track if the provided id is the same and force param is TRUE', async () => {
7686
+ client.setMediaConstraints(constraints);
7687
+ expect(client.getAudioDeviceId()).toBe(defaultId);
7688
+ expect(client.changeAudioInputDevice(defaultId, session, true)).toBeTruthy();
7689
+ });
7690
+ });