@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.
- package/README.md +4 -4
- package/dist/wazo-sdk.js +2 -2
- package/esm/__tests__/api-client.test.js +6 -0
- package/esm/__tests__/web-rtc-client.test.js +88 -3
- package/esm/api/calld.js +6 -0
- package/esm/api/ctid-ng.js +6 -0
- package/esm/api-client.js +6 -0
- package/esm/checker/Checker.js +38 -3
- package/esm/checker/checks/aor.js +6 -0
- package/esm/checker/checks/api.js +6 -0
- package/esm/checker/checks/index.js +38 -3
- package/esm/checker/checks/webrtc-transport.js +38 -3
- package/esm/checker/checks/webrtc.js +38 -3
- package/esm/domain/AdHocAPIConference.js +6 -0
- package/esm/domain/Call.js +6 -0
- package/esm/domain/CallSession.js +1 -1
- package/esm/domain/Features.js +6 -0
- package/esm/domain/Phone/CTIPhone.js +7 -1
- package/esm/domain/Phone/WebRTCPhone.js +3 -3
- package/esm/domain/__tests__/Call.test.js +6 -0
- package/esm/domain/__tests__/CallSession.test.js +1 -1
- package/esm/domain/__tests__/IndirectTransfer.test.js +1 -1
- package/esm/domain/__tests__/Line.test.js +5 -5
- package/esm/domain/__tests__/Room.test.js +1 -1
- package/esm/index.js +42 -8
- package/esm/lib/WazoSessionDescriptionHandler.js +30 -1
- package/esm/service/CallApi.js +6 -0
- package/esm/service/getApiClient.js +6 -0
- package/esm/simple/Auth.js +42 -8
- package/esm/simple/Configuration.js +42 -8
- package/esm/simple/Directory.js +6 -0
- package/esm/simple/Phone.js +42 -8
- package/esm/simple/Softphone.js +1 -2
- package/esm/simple/index.js +42 -8
- package/esm/simple/room/LocalParticipant.js +42 -8
- package/esm/simple/room/Participant.js +42 -8
- package/esm/simple/room/RemoteParticipant.js +42 -8
- package/esm/simple/room/Room.js +42 -8
- package/esm/simple/room/SipRoom.js +42 -8
- package/esm/simple/room/Stream.js +42 -8
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +42 -8
- package/esm/simple/utils.js +42 -8
- package/esm/utils/__tests__/sdp.test.js +50 -0
- package/esm/utils/sdp.js +19 -1
- package/esm/web-rtc-client.js +38 -3
- package/lib/__tests__/api-client.test.js +6 -0
- package/lib/__tests__/web-rtc-client.test.js +88 -3
- package/lib/api/calld.js +6 -0
- package/lib/api/ctid-ng.js +6 -0
- package/lib/api-client.js +6 -0
- package/lib/checker/Checker.js +38 -3
- package/lib/checker/checks/aor.js +6 -0
- package/lib/checker/checks/api.js +6 -0
- package/lib/checker/checks/index.js +38 -3
- package/lib/checker/checks/webrtc-transport.js +38 -3
- package/lib/checker/checks/webrtc.js +38 -3
- package/lib/domain/AdHocAPIConference.js +6 -0
- package/lib/domain/Call.js +6 -0
- package/lib/domain/CallSession.js +1 -1
- package/lib/domain/Features.js +6 -0
- package/lib/domain/Phone/CTIPhone.js +7 -1
- package/lib/domain/Phone/WebRTCPhone.js +3 -3
- package/lib/domain/__tests__/Call.test.js +6 -0
- package/lib/domain/__tests__/CallSession.test.js +1 -1
- package/lib/domain/__tests__/IndirectTransfer.test.js +1 -1
- package/lib/domain/__tests__/Line.test.js +5 -5
- package/lib/domain/__tests__/Room.test.js +1 -1
- package/lib/index.js +42 -8
- package/lib/lib/WazoSessionDescriptionHandler.js +30 -1
- package/lib/service/CallApi.js +6 -0
- package/lib/service/getApiClient.js +6 -0
- package/lib/simple/Auth.js +42 -8
- package/lib/simple/Configuration.js +42 -8
- package/lib/simple/Directory.js +6 -0
- package/lib/simple/Phone.js +42 -8
- package/lib/simple/Softphone.js +1 -2
- package/lib/simple/index.js +42 -8
- package/lib/simple/room/LocalParticipant.js +42 -8
- package/lib/simple/room/Participant.js +42 -8
- package/lib/simple/room/RemoteParticipant.js +42 -8
- package/lib/simple/room/Room.js +42 -8
- package/lib/simple/room/SipRoom.js +42 -8
- package/lib/simple/room/Stream.js +42 -8
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +42 -8
- package/lib/simple/utils.js +42 -8
- package/lib/utils/__tests__/sdp.test.js +50 -0
- package/lib/utils/sdp.js +19 -0
- package/lib/web-rtc-client.js +38 -3
- package/package.json +1 -1
- package/src/__tests__/web-rtc-client.test.js +50 -0
- package/src/domain/Call.js +6 -0
- package/src/domain/CallSession.js +1 -1
- package/src/domain/Phone/WebRTCPhone.js +2 -2
- package/src/domain/__tests__/Line.test.js +5 -5
- package/src/lib/WazoSessionDescriptionHandler.js +13 -2
- package/src/simple/Softphone.js +1 -2
- package/src/utils/__tests__/sdp.test.js +33 -1
- package/src/utils/sdp.js +18 -0
- 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:
|
|
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
|
|
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
|
-
|
|
14095
|
-
server = 'stack.dev.wazo.io';
|
|
14129
|
+
throw new Error('`server` is not set');
|
|
14096
14130
|
}
|
|
14097
14131
|
|
|
14098
14132
|
const config = { server };
|
package/esm/simple/utils.js
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|
package/esm/web-rtc-client.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
+
});
|