@wazo/sdk 0.38.5 → 0.38.8
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 +1 -1
- package/dist/wazo-sdk.js +2 -2
- package/esm/__tests__/api-client.test.js +148 -2
- package/esm/__tests__/web-rtc-client.test.js +303 -26
- package/esm/api/calld.js +14 -0
- package/esm/api/confd.js +134 -2
- package/esm/api/ctid-ng.js +6 -0
- package/esm/api-client.js +148 -2
- package/esm/checker/Checker.js +212 -26
- package/esm/checker/checks/aor.js +148 -2
- package/esm/checker/checks/api.js +148 -2
- package/esm/checker/checks/index.js +212 -26
- package/esm/checker/checks/wazo-websocket.js +2 -0
- package/esm/checker/checks/webrtc-transport.js +210 -26
- package/esm/checker/checks/webrtc.js +210 -26
- package/esm/domain/AdHocAPIConference.js +148 -2
- package/esm/domain/Call.js +6 -0
- package/esm/domain/CallSession.js +1 -1
- package/esm/domain/Features.js +148 -2
- package/esm/domain/Meeting.js +18 -0
- package/esm/domain/MeetingAuthorization.js +70 -0
- package/esm/domain/Phone/CTIPhone.js +149 -3
- 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__/Meeting.test.js +87 -1
- package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
- package/esm/domain/__tests__/Room.test.js +1 -1
- package/esm/index.js +258 -32
- package/esm/lib/WazoSessionDescriptionHandler.js +22 -1
- package/esm/service/CallApi.js +148 -2
- package/esm/service/getApiClient.js +148 -2
- package/esm/simple/Auth.js +258 -32
- package/esm/simple/Configuration.js +258 -32
- package/esm/simple/Directory.js +148 -2
- package/esm/simple/Phone.js +258 -32
- package/esm/simple/Websocket.js +3 -0
- package/esm/simple/index.js +258 -32
- package/esm/simple/room/LocalParticipant.js +258 -32
- package/esm/simple/room/Participant.js +258 -32
- package/esm/simple/room/RemoteParticipant.js +258 -32
- package/esm/simple/room/Room.js +258 -32
- package/esm/simple/room/SipRoom.js +258 -32
- package/esm/simple/room/Stream.js +258 -32
- package/esm/simple/room/__tests__/Participant.test.js +14747 -0
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +258 -32
- package/esm/simple/utils.js +258 -32
- package/esm/utils/__tests__/object.test.js +57 -0
- package/esm/utils/__tests__/sdp.test.js +50 -0
- package/esm/utils/__tests__/string.test.js +30 -0
- package/esm/utils/object.js +24 -0
- package/esm/utils/sdp.js +19 -1
- package/esm/utils/string.js +10 -0
- package/esm/web-rtc-client.js +210 -26
- package/esm/websocket-client.js +3 -1
- package/lib/__tests__/api-client.test.js +148 -2
- package/lib/__tests__/web-rtc-client.test.js +303 -26
- package/lib/api/calld.js +14 -0
- package/lib/api/confd.js +134 -2
- package/lib/api/ctid-ng.js +6 -0
- package/lib/api-client.js +148 -2
- package/lib/checker/Checker.js +212 -26
- package/lib/checker/checks/aor.js +148 -2
- package/lib/checker/checks/api.js +148 -2
- package/lib/checker/checks/index.js +212 -26
- package/lib/checker/checks/wazo-websocket.js +2 -0
- package/lib/checker/checks/webrtc-transport.js +210 -26
- package/lib/checker/checks/webrtc.js +210 -26
- package/lib/domain/AdHocAPIConference.js +148 -2
- package/lib/domain/Call.js +6 -0
- package/lib/domain/CallSession.js +1 -1
- package/lib/domain/Features.js +148 -2
- package/lib/domain/Meeting.js +18 -0
- package/lib/domain/MeetingAuthorization.js +79 -0
- package/lib/domain/Phone/CTIPhone.js +149 -3
- 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__/Meeting.test.js +87 -1
- package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
- package/lib/domain/__tests__/Room.test.js +1 -1
- package/lib/index.js +258 -32
- package/lib/lib/WazoSessionDescriptionHandler.js +22 -1
- package/lib/service/CallApi.js +148 -2
- package/lib/service/getApiClient.js +148 -2
- package/lib/simple/Auth.js +258 -32
- package/lib/simple/Configuration.js +258 -32
- package/lib/simple/Directory.js +148 -2
- package/lib/simple/Phone.js +258 -32
- package/lib/simple/Websocket.js +3 -0
- package/lib/simple/index.js +258 -32
- package/lib/simple/room/LocalParticipant.js +258 -32
- package/lib/simple/room/Participant.js +258 -32
- package/lib/simple/room/RemoteParticipant.js +258 -32
- package/lib/simple/room/Room.js +258 -32
- package/lib/simple/room/SipRoom.js +258 -32
- package/lib/simple/room/Stream.js +258 -32
- package/lib/simple/room/__tests__/Participant.test.js +14757 -0
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +258 -32
- package/lib/simple/utils.js +258 -32
- package/lib/utils/__tests__/object.test.js +59 -0
- package/lib/utils/__tests__/sdp.test.js +50 -0
- package/lib/utils/__tests__/string.test.js +32 -0
- package/lib/utils/object.js +28 -0
- package/lib/utils/sdp.js +19 -0
- package/lib/utils/string.js +14 -0
- package/lib/web-rtc-client.js +210 -26
- package/lib/websocket-client.js +3 -0
- package/package.json +2 -2
- package/src/__tests__/web-rtc-client.test.js +93 -0
- package/src/api/calld.js +8 -0
- package/src/api/confd.js +43 -2
- package/src/domain/Call.js +6 -0
- package/src/domain/CallSession.js +1 -1
- package/src/domain/Meeting.js +20 -0
- package/src/domain/MeetingAuthorization.js +67 -0
- package/src/domain/Phone/WebRTCPhone.js +2 -2
- package/src/domain/__tests__/Meeting.test.js +70 -1
- package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
- package/src/lib/WazoSessionDescriptionHandler.js +5 -2
- package/src/simple/room/Participant.js +40 -0
- package/src/simple/room/Room.js +2 -2
- package/src/simple/room/SipRoom.js +1 -1
- package/src/simple/room/__tests__/Participant.test.js +81 -0
- package/src/types/WebSocketMessage.js +7 -1
- package/src/utils/__tests__/object.test.js +35 -0
- package/src/utils/__tests__/sdp.test.js +33 -1
- package/src/utils/__tests__/string.test.js +23 -0
- package/src/utils/object.js +15 -0
- package/src/utils/sdp.js +18 -0
- package/src/utils/string.js +8 -0
- package/src/web-rtc-client.js +40 -23
- package/src/websocket-client.js +2 -0
package/lib/simple/utils.js
CHANGED
|
@@ -2657,6 +2657,70 @@ class ExternalApp {
|
|
|
2657
2657
|
|
|
2658
2658
|
//
|
|
2659
2659
|
|
|
2660
|
+
class MeetingAuthorization {
|
|
2661
|
+
|
|
2662
|
+
|
|
2663
|
+
|
|
2664
|
+
|
|
2665
|
+
|
|
2666
|
+
|
|
2667
|
+
constructor({
|
|
2668
|
+
meetingUuid,
|
|
2669
|
+
uuid,
|
|
2670
|
+
userUuid,
|
|
2671
|
+
userName,
|
|
2672
|
+
} = {}) {
|
|
2673
|
+
this.meetingUuid = meetingUuid;
|
|
2674
|
+
this.uuid = uuid;
|
|
2675
|
+
this.userUuid = userUuid;
|
|
2676
|
+
this.userName = userName;
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
setStatus(status ) {
|
|
2680
|
+
this.status = status;
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
getStatus() {
|
|
2684
|
+
return this.status;
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2687
|
+
static parse(plain ) {
|
|
2688
|
+
const {
|
|
2689
|
+
meeting_uuid: meetingUuid,
|
|
2690
|
+
uuid,
|
|
2691
|
+
guest_uuid: userUuid,
|
|
2692
|
+
guest_name: userName,
|
|
2693
|
+
} = plain;
|
|
2694
|
+
|
|
2695
|
+
return new MeetingAuthorization({
|
|
2696
|
+
meetingUuid,
|
|
2697
|
+
uuid,
|
|
2698
|
+
userUuid,
|
|
2699
|
+
userName,
|
|
2700
|
+
});
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
static parseMany(items ) {
|
|
2704
|
+
if (!items) {
|
|
2705
|
+
return [];
|
|
2706
|
+
}
|
|
2707
|
+
return items.map(MeetingAuthorization.parse);
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
//
|
|
2712
|
+
|
|
2713
|
+
|
|
2714
|
+
|
|
2715
|
+
|
|
2716
|
+
|
|
2717
|
+
|
|
2718
|
+
|
|
2719
|
+
|
|
2720
|
+
|
|
2721
|
+
|
|
2722
|
+
|
|
2723
|
+
|
|
2660
2724
|
|
|
2661
2725
|
|
|
2662
2726
|
|
|
@@ -2667,6 +2731,7 @@ class ExternalApp {
|
|
|
2667
2731
|
|
|
2668
2732
|
|
|
2669
2733
|
|
|
2734
|
+
|
|
2670
2735
|
|
|
2671
2736
|
|
|
2672
2737
|
class Meeting {
|
|
@@ -2681,6 +2746,8 @@ class Meeting {
|
|
|
2681
2746
|
|
|
2682
2747
|
|
|
2683
2748
|
|
|
2749
|
+
|
|
2750
|
+
|
|
2684
2751
|
|
|
2685
2752
|
static parse(plain ) {
|
|
2686
2753
|
return new Meeting({
|
|
@@ -2693,6 +2760,7 @@ class Meeting {
|
|
|
2693
2760
|
extension: plain.exten,
|
|
2694
2761
|
persistent: plain.persistent,
|
|
2695
2762
|
creationTime: moment__default['default'](plain.creation_time).toDate(),
|
|
2763
|
+
requireAuthorization: plain.require_authorization,
|
|
2696
2764
|
});
|
|
2697
2765
|
}
|
|
2698
2766
|
|
|
@@ -2717,6 +2785,7 @@ class Meeting {
|
|
|
2717
2785
|
extension,
|
|
2718
2786
|
persistent,
|
|
2719
2787
|
creationTime,
|
|
2788
|
+
requireAuthorization,
|
|
2720
2789
|
} = {}) {
|
|
2721
2790
|
this.guestSipAuthorization = guestSipAuthorization;
|
|
2722
2791
|
this.uri = uri;
|
|
@@ -2727,6 +2796,7 @@ class Meeting {
|
|
|
2727
2796
|
this.extension = extension;
|
|
2728
2797
|
this.persistent = persistent;
|
|
2729
2798
|
this.creationTime = creationTime;
|
|
2799
|
+
this.requireAuthorization = requireAuthorization;
|
|
2730
2800
|
|
|
2731
2801
|
// Useful to compare instead of instanceof with minified code
|
|
2732
2802
|
this.type = 'Meeting';
|
|
@@ -2737,8 +2807,32 @@ class Meeting {
|
|
|
2737
2807
|
const [username, secret] = atob(this.guestSipAuthorization).split(':');
|
|
2738
2808
|
return { username, secret };
|
|
2739
2809
|
}
|
|
2810
|
+
|
|
2740
2811
|
}
|
|
2741
2812
|
|
|
2813
|
+
//
|
|
2814
|
+
|
|
2815
|
+
const camelToUnderscore = (key ) => {
|
|
2816
|
+
if (typeof key !== 'string') {
|
|
2817
|
+
throw new Error('Input is not a string');
|
|
2818
|
+
}
|
|
2819
|
+
return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
2820
|
+
};
|
|
2821
|
+
|
|
2822
|
+
//
|
|
2823
|
+
|
|
2824
|
+
const convertKeysFromCamelToUnderscore = (args ) => {
|
|
2825
|
+
if (!args || typeof args !== 'object' || Array.isArray(args)) {
|
|
2826
|
+
throw new Error('Input is not an object');
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
return Object.keys(args).reduce((acc, key) => {
|
|
2830
|
+
acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
|
|
2831
|
+
? convertKeysFromCamelToUnderscore(args[key]) : args[key];
|
|
2832
|
+
return acc;
|
|
2833
|
+
}, {});
|
|
2834
|
+
};
|
|
2835
|
+
|
|
2742
2836
|
/* */
|
|
2743
2837
|
|
|
2744
2838
|
var confdMethods = (client , baseUrl ) => ({
|
|
@@ -2807,8 +2901,18 @@ var confdMethods = (client , baseUrl ) => ({
|
|
|
2807
2901
|
getMyMeetings: () =>
|
|
2808
2902
|
client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
|
|
2809
2903
|
|
|
2810
|
-
createMyMeeting: (
|
|
2811
|
-
client
|
|
2904
|
+
createMyMeeting: (args ) =>
|
|
2905
|
+
client
|
|
2906
|
+
.post(`${baseUrl}/users/me/meetings`, convertKeysFromCamelToUnderscore(args))
|
|
2907
|
+
.then(Meeting.parse),
|
|
2908
|
+
|
|
2909
|
+
updateMyMeeting: (meetingUuid , data ) =>
|
|
2910
|
+
client.put(
|
|
2911
|
+
`${baseUrl}/users/me/meetings/${meetingUuid}`,
|
|
2912
|
+
convertKeysFromCamelToUnderscore(data),
|
|
2913
|
+
null,
|
|
2914
|
+
ApiRequester.successResponseParser,
|
|
2915
|
+
),
|
|
2812
2916
|
|
|
2813
2917
|
deleteMyMeeting: (meetingUuid ) =>
|
|
2814
2918
|
client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
|
|
@@ -2816,8 +2920,36 @@ var confdMethods = (client , baseUrl ) => ({
|
|
|
2816
2920
|
getMeeting: (meetingUuid ) =>
|
|
2817
2921
|
client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
2818
2922
|
|
|
2923
|
+
meetingAuthorizations: (meetingUuid ) =>
|
|
2924
|
+
client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations`, null).then(MeetingAuthorization.parseMany),
|
|
2925
|
+
|
|
2926
|
+
meetingAuthorizationReject: (meetingUuid , authorizationUuid ) =>
|
|
2927
|
+
client.put(
|
|
2928
|
+
`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/reject`,
|
|
2929
|
+
{},
|
|
2930
|
+
null,
|
|
2931
|
+
ApiRequester.successResponseParser,
|
|
2932
|
+
),
|
|
2933
|
+
|
|
2934
|
+
meetingAuthorizationAccept: (meetingUuid , authorizationUuid ) =>
|
|
2935
|
+
client.put(
|
|
2936
|
+
`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/accept`,
|
|
2937
|
+
{},
|
|
2938
|
+
null,
|
|
2939
|
+
ApiRequester.successResponseParser,
|
|
2940
|
+
),
|
|
2941
|
+
|
|
2819
2942
|
guestGetMeeting: (meetingUuid ) =>
|
|
2820
2943
|
client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
2944
|
+
|
|
2945
|
+
guestAuthorizationRequest: (userUuid , meetingUuid , username ) =>
|
|
2946
|
+
client
|
|
2947
|
+
.post(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations`, { guest_name: username })
|
|
2948
|
+
.then(MeetingAuthorization.parse),
|
|
2949
|
+
|
|
2950
|
+
guestAuthorizationCheck: (userUuid , meetingUuid , authorizationUuid ) =>
|
|
2951
|
+
client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
|
|
2952
|
+
|
|
2821
2953
|
});
|
|
2822
2954
|
|
|
2823
2955
|
//
|
|
@@ -3083,6 +3215,7 @@ const RECORD_STATE_ACTIVE = 'active';
|
|
|
3083
3215
|
|
|
3084
3216
|
|
|
3085
3217
|
|
|
3218
|
+
|
|
3086
3219
|
|
|
3087
3220
|
|
|
3088
3221
|
|
|
@@ -3093,6 +3226,7 @@ const RECORD_STATE_ACTIVE = 'active';
|
|
|
3093
3226
|
|
|
3094
3227
|
|
|
3095
3228
|
|
|
3229
|
+
|
|
3096
3230
|
|
|
3097
3231
|
|
|
3098
3232
|
|
|
@@ -3121,6 +3255,7 @@ class Call {
|
|
|
3121
3255
|
|
|
3122
3256
|
|
|
3123
3257
|
|
|
3258
|
+
|
|
3124
3259
|
|
|
3125
3260
|
|
|
3126
3261
|
|
|
@@ -3145,6 +3280,7 @@ class Call {
|
|
|
3145
3280
|
calleeNumber: plain.peer_caller_id_number,
|
|
3146
3281
|
dialedExtension: plain.dialed_extension,
|
|
3147
3282
|
isCaller: plain.is_caller,
|
|
3283
|
+
isVideo: plain.is_video,
|
|
3148
3284
|
muted: plain.muted,
|
|
3149
3285
|
onHold: plain.on_hold,
|
|
3150
3286
|
status: plain.status,
|
|
@@ -3168,6 +3304,7 @@ class Call {
|
|
|
3168
3304
|
calleeNumber,
|
|
3169
3305
|
dialedExtension,
|
|
3170
3306
|
isCaller,
|
|
3307
|
+
isVideo,
|
|
3171
3308
|
lineId,
|
|
3172
3309
|
muted,
|
|
3173
3310
|
onHold,
|
|
@@ -3191,6 +3328,7 @@ class Call {
|
|
|
3191
3328
|
this.startingTime = startingTime;
|
|
3192
3329
|
this.talkingToIds = talkingToIds || [];
|
|
3193
3330
|
this.recording = recording;
|
|
3331
|
+
this.isVideo = !!isVideo;
|
|
3194
3332
|
|
|
3195
3333
|
// Useful to compare instead of instanceof with minified code
|
|
3196
3334
|
this.type = 'Call';
|
|
@@ -3664,7 +3802,7 @@ class CallSession {
|
|
|
3664
3802
|
ringing: call.isRinging(),
|
|
3665
3803
|
answered: call.isUp(),
|
|
3666
3804
|
answeredBySystem: call.isUp() && call.talkingToIds.length === 0,
|
|
3667
|
-
cameraEnabled:
|
|
3805
|
+
cameraEnabled: call.isVideo,
|
|
3668
3806
|
dialedExtension: call.dialedExtension,
|
|
3669
3807
|
call,
|
|
3670
3808
|
conference: false, // @FIXME?
|
|
@@ -5062,6 +5200,14 @@ var calldMethods = (client , baseUrl ) => ({
|
|
|
5062
5200
|
getMeetingParticipantsAsUser: async (meetingUuid ) =>
|
|
5063
5201
|
client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
|
|
5064
5202
|
|
|
5203
|
+
banMeetingParticipant: (meetingUuid , participantUuid ) =>
|
|
5204
|
+
client.delete(
|
|
5205
|
+
`${baseUrl}/users/me/meetings/${meetingUuid}/participants/${participantUuid}`,
|
|
5206
|
+
null,
|
|
5207
|
+
null,
|
|
5208
|
+
ApiRequester.successResponseParser,
|
|
5209
|
+
),
|
|
5210
|
+
|
|
5065
5211
|
listTrunks: () => client.get(`${baseUrl}/trunks`),
|
|
5066
5212
|
|
|
5067
5213
|
mute: (callId ) =>
|
|
@@ -6210,6 +6356,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
|
|
|
6210
6356
|
return fixed;
|
|
6211
6357
|
};
|
|
6212
6358
|
|
|
6359
|
+
const addIcesInAllBundles = (sdp ) => {
|
|
6360
|
+
const parsedSdp = sdpParser__default['default'].parse(sdp);
|
|
6361
|
+
|
|
6362
|
+
const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
|
|
6363
|
+
if (!mediaWithCandidate) {
|
|
6364
|
+
return sdp;
|
|
6365
|
+
}
|
|
6366
|
+
|
|
6367
|
+
const { candidates } = mediaWithCandidate;
|
|
6368
|
+
|
|
6369
|
+
parsedSdp.media = parsedSdp.media.map(media => ({
|
|
6370
|
+
...media,
|
|
6371
|
+
candidates: media.candidates || candidates,
|
|
6372
|
+
}));
|
|
6373
|
+
|
|
6374
|
+
return sdpParser__default['default'].write(parsedSdp);
|
|
6375
|
+
};
|
|
6376
|
+
|
|
6213
6377
|
/* global RTCSessionDescriptionInit, navigator */
|
|
6214
6378
|
|
|
6215
6379
|
const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
|
|
@@ -6339,7 +6503,10 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
6339
6503
|
|
|
6340
6504
|
// Check if we got ICEs
|
|
6341
6505
|
if (sdp.indexOf('a=candidate') !== -1) {
|
|
6342
|
-
return
|
|
6506
|
+
return {
|
|
6507
|
+
type: description.type,
|
|
6508
|
+
sdp: addIcesInAllBundles(sdp),
|
|
6509
|
+
};
|
|
6343
6510
|
}
|
|
6344
6511
|
|
|
6345
6512
|
wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
|
|
@@ -7799,41 +7966,58 @@ class WebRTCClient extends Emitter {
|
|
|
7799
7966
|
});
|
|
7800
7967
|
}
|
|
7801
7968
|
|
|
7802
|
-
changeAudioInputDevice(id , session ) {
|
|
7969
|
+
async changeAudioInputDevice(id , session , force ) {
|
|
7803
7970
|
const currentId = this.getAudioDeviceId();
|
|
7804
7971
|
logger$8.info('setting audio input device', { id, currentId, session: !!session });
|
|
7805
7972
|
|
|
7806
|
-
if (id === currentId) {
|
|
7973
|
+
if (!force && id === currentId) {
|
|
7807
7974
|
return null;
|
|
7808
7975
|
}
|
|
7809
7976
|
|
|
7977
|
+
// in order to handle an audio track change for default devices
|
|
7978
|
+
// we need the actual id of the device (not 'default')
|
|
7979
|
+
let deviceId = id;
|
|
7980
|
+
if (id === 'default' && navigator.mediaDevices) {
|
|
7981
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
7982
|
+
const defaultDevice = devices.find(device => device.deviceId === 'default');
|
|
7983
|
+
if (defaultDevice) {
|
|
7984
|
+
const deviceLabel = defaultDevice.label.replace('Default - ', '');
|
|
7985
|
+
const targetDevice = devices.find(device => device.label === deviceLabel);
|
|
7986
|
+
if (targetDevice) {
|
|
7987
|
+
deviceId = targetDevice.deviceId;
|
|
7988
|
+
if (!force && deviceId === currentId) {
|
|
7989
|
+
return null;
|
|
7990
|
+
}
|
|
7991
|
+
}
|
|
7992
|
+
}
|
|
7993
|
+
}
|
|
7994
|
+
|
|
7810
7995
|
// let's update the local audio value
|
|
7811
7996
|
if (this.audio) {
|
|
7812
7997
|
this.audio = {
|
|
7813
7998
|
deviceId: {
|
|
7814
|
-
exact:
|
|
7999
|
+
exact: deviceId,
|
|
7815
8000
|
},
|
|
7816
8001
|
};
|
|
7817
8002
|
}
|
|
7818
8003
|
|
|
7819
|
-
if (session) {
|
|
8004
|
+
if (session && navigator.mediaDevices) {
|
|
7820
8005
|
const sdh = session.sessionDescriptionHandler;
|
|
7821
8006
|
const pc = sdh.peerConnection;
|
|
7822
8007
|
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
8008
|
+
const constraints = { audio: { deviceId: { exact: deviceId } } };
|
|
8009
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
8010
|
+
const audioTrack = stream.getAudioTracks()[0];
|
|
8011
|
+
const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
|
|
7827
8012
|
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
}
|
|
7832
|
-
sender.replaceTrack(audioTrack);
|
|
8013
|
+
if (sender) {
|
|
8014
|
+
if (sender.track) {
|
|
8015
|
+
audioTrack.enabled = sender.track.enabled;
|
|
7833
8016
|
}
|
|
8017
|
+
sender.replaceTrack(audioTrack);
|
|
8018
|
+
}
|
|
7834
8019
|
|
|
7835
|
-
|
|
7836
|
-
});
|
|
8020
|
+
return stream;
|
|
7837
8021
|
}
|
|
7838
8022
|
}
|
|
7839
8023
|
|
|
@@ -7853,14 +8037,14 @@ class WebRTCClient extends Emitter {
|
|
|
7853
8037
|
return null;
|
|
7854
8038
|
}
|
|
7855
8039
|
|
|
7856
|
-
// let's
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
}
|
|
7863
|
-
}
|
|
8040
|
+
// let's make sure we don't lose other video constraints settings -- width, height, frameRate...
|
|
8041
|
+
const videoObject = typeof this.video === 'object' ? this.video : {};
|
|
8042
|
+
this.video = {
|
|
8043
|
+
...videoObject,
|
|
8044
|
+
deviceId: {
|
|
8045
|
+
exact: id,
|
|
8046
|
+
},
|
|
8047
|
+
};
|
|
7864
8048
|
}
|
|
7865
8049
|
|
|
7866
8050
|
changeSessionVideoInputDevice(id , session ) {
|
|
@@ -9599,10 +9783,10 @@ class WebRTCPhone extends Emitter {
|
|
|
9599
9783
|
this.audioRingVolume = volume;
|
|
9600
9784
|
}
|
|
9601
9785
|
|
|
9602
|
-
changeAudioInputDevice(id ) {
|
|
9786
|
+
changeAudioInputDevice(id , force ) {
|
|
9603
9787
|
logger$7.info('WebRTC phone - changeAudio input device', { deviceId: id });
|
|
9604
9788
|
|
|
9605
|
-
return this.client.changeAudioInputDevice(id, this.currentSipSession);
|
|
9789
|
+
return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
|
|
9606
9790
|
}
|
|
9607
9791
|
|
|
9608
9792
|
changeVideoInputDevice(id ) {
|
|
@@ -11255,6 +11439,7 @@ const AGENT_UNPAUSED = 'agent_unpaused';
|
|
|
11255
11439
|
const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
|
|
11256
11440
|
const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
|
|
11257
11441
|
const MEETING_USER_PROGRESS = 'meeting_user_progress';
|
|
11442
|
+
const MEETING_USER_GUEST_AUTHORIZATION_CREATED = 'meeting_user_guest_authorization_created';
|
|
11258
11443
|
|
|
11259
11444
|
const BLACKLIST_EVENTS = [
|
|
11260
11445
|
CHAT_MESSAGE_SENT,
|
|
@@ -11606,6 +11791,7 @@ WebSocketClient.eventLists = [
|
|
|
11606
11791
|
CONFERENCE_ADHOC_PARTICIPANT_LEFT,
|
|
11607
11792
|
CONFERENCE_ADHOC_DELETED,
|
|
11608
11793
|
MEETING_USER_PROGRESS,
|
|
11794
|
+
MEETING_USER_GUEST_AUTHORIZATION_CREATED,
|
|
11609
11795
|
];
|
|
11610
11796
|
|
|
11611
11797
|
var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
|
|
@@ -11677,6 +11863,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
|
|
|
11677
11863
|
CONFERENCE_ADHOC_PARTICIPANT_LEFT: CONFERENCE_ADHOC_PARTICIPANT_LEFT,
|
|
11678
11864
|
CONFERENCE_ADHOC_DELETED: CONFERENCE_ADHOC_DELETED,
|
|
11679
11865
|
MEETING_USER_PROGRESS: MEETING_USER_PROGRESS,
|
|
11866
|
+
MEETING_USER_GUEST_AUTHORIZATION_CREATED: MEETING_USER_GUEST_AUTHORIZATION_CREATED,
|
|
11680
11867
|
HEARTBEAT_ENGINE_VERSION: HEARTBEAT_ENGINE_VERSION,
|
|
11681
11868
|
'default': WebSocketClient
|
|
11682
11869
|
});
|
|
@@ -11781,6 +11968,7 @@ class Participant extends Emitter {
|
|
|
11781
11968
|
|
|
11782
11969
|
|
|
11783
11970
|
|
|
11971
|
+
|
|
11784
11972
|
|
|
11785
11973
|
|
|
11786
11974
|
|
|
@@ -11798,6 +11986,7 @@ class Participant extends Emitter {
|
|
|
11798
11986
|
|
|
11799
11987
|
|
|
11800
11988
|
|
|
11989
|
+
|
|
11801
11990
|
|
|
11802
11991
|
/**
|
|
11803
11992
|
* @param room Room The room where the participant is
|
|
@@ -11821,6 +12010,7 @@ class Participant extends Emitter {
|
|
|
11821
12010
|
this.screensharing = false;
|
|
11822
12011
|
this.isOnHold = false;
|
|
11823
12012
|
this.extra = extra;
|
|
12013
|
+
this.banned = false;
|
|
11824
12014
|
|
|
11825
12015
|
this.ON_UPDATED = 'participant/ON_UPDATED';
|
|
11826
12016
|
this.ON_START_TALKING = 'participant/ON_START_TALKING';
|
|
@@ -11837,6 +12027,7 @@ class Participant extends Emitter {
|
|
|
11837
12027
|
this.ON_EXTRA_CHANGE = 'participant/ON_EXTRA_CHANGE';
|
|
11838
12028
|
this.ON_HOLD = 'participant/ON_HOLD';
|
|
11839
12029
|
this.ON_RESUME = 'participant/ON_RESUME';
|
|
12030
|
+
this.ON_BAN = 'participant/ON_BAN';
|
|
11840
12031
|
}
|
|
11841
12032
|
|
|
11842
12033
|
triggerEvent(name , ...args ) {
|
|
@@ -11877,6 +12068,10 @@ class Participant extends Emitter {
|
|
|
11877
12068
|
status.extra = this.extra;
|
|
11878
12069
|
break;
|
|
11879
12070
|
}
|
|
12071
|
+
case this.ON_BAN: {
|
|
12072
|
+
status.banned = true;
|
|
12073
|
+
break;
|
|
12074
|
+
}
|
|
11880
12075
|
}
|
|
11881
12076
|
|
|
11882
12077
|
if (broadcast) {
|
|
@@ -11979,6 +12174,11 @@ class Participant extends Emitter {
|
|
|
11979
12174
|
this.triggerUpdate(this.ON_RESUME, broadcast);
|
|
11980
12175
|
}
|
|
11981
12176
|
|
|
12177
|
+
onBan(broadcast = true) {
|
|
12178
|
+
this.banned = true;
|
|
12179
|
+
this.triggerUpdate(this.ON_BAN, broadcast);
|
|
12180
|
+
}
|
|
12181
|
+
|
|
11982
12182
|
getStatus() {
|
|
11983
12183
|
return {
|
|
11984
12184
|
callId: this.callId,
|
|
@@ -12025,6 +12225,10 @@ class Participant extends Emitter {
|
|
|
12025
12225
|
}
|
|
12026
12226
|
}
|
|
12027
12227
|
|
|
12228
|
+
if (status.banned) {
|
|
12229
|
+
this.onBan(false);
|
|
12230
|
+
}
|
|
12231
|
+
|
|
12028
12232
|
// Poor man's object comparison
|
|
12029
12233
|
if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
|
|
12030
12234
|
this.extra = { ...this.extra, ...status.extra };
|
|
@@ -12052,6 +12256,28 @@ class Participant extends Emitter {
|
|
|
12052
12256
|
this.streams = streams;
|
|
12053
12257
|
this.videoStreams = streams;
|
|
12054
12258
|
}
|
|
12259
|
+
|
|
12260
|
+
async ban(apiRequestDelay = null) {
|
|
12261
|
+
const { meetingUuid } = this.room;
|
|
12262
|
+
if (!meetingUuid) {
|
|
12263
|
+
throw new Error('Attempting to ban a participant without a `meetingUuid`');
|
|
12264
|
+
}
|
|
12265
|
+
|
|
12266
|
+
// this notifies all that someone is being banned
|
|
12267
|
+
this.onBan(true);
|
|
12268
|
+
|
|
12269
|
+
// this allows to delay the actual ban, in order for the banned participant as well as others to react to the situation
|
|
12270
|
+
if (apiRequestDelay) {
|
|
12271
|
+
await this.delay(apiRequestDelay);
|
|
12272
|
+
}
|
|
12273
|
+
|
|
12274
|
+
// proceed with the actual kick
|
|
12275
|
+
return getApiClient().calld.banMeetingParticipant(meetingUuid, this.callId);
|
|
12276
|
+
}
|
|
12277
|
+
|
|
12278
|
+
async delay(ms ) {
|
|
12279
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
12280
|
+
}
|
|
12055
12281
|
}
|
|
12056
12282
|
|
|
12057
12283
|
//
|
|
@@ -12204,7 +12430,7 @@ class Room$1 extends Emitter {
|
|
|
12204
12430
|
logger$2.info('connecting to room', { extension, audioOnly, room: !!room });
|
|
12205
12431
|
|
|
12206
12432
|
if (!room) {
|
|
12207
|
-
await Wazo.Phone.connect();
|
|
12433
|
+
await Wazo.Phone.connect({ media: constraints });
|
|
12208
12434
|
|
|
12209
12435
|
const withCamera = constraints && !!constraints.video;
|
|
12210
12436
|
|
|
@@ -12649,7 +12875,7 @@ class Room$1 extends Emitter {
|
|
|
12649
12875
|
const participant = this._getParticipantFromCallId(status.callId);
|
|
12650
12876
|
|
|
12651
12877
|
if (participant) {
|
|
12652
|
-
// we're
|
|
12878
|
+
// we're receiving, so no need to broadcast
|
|
12653
12879
|
participant.updateStatus(status, false);
|
|
12654
12880
|
}
|
|
12655
12881
|
break;
|
|
@@ -12916,7 +13142,7 @@ class SipRoom extends Room$1 {
|
|
|
12916
13142
|
logger$1.info('connecting to sip room', { extension, audioOnly, room: !!room });
|
|
12917
13143
|
|
|
12918
13144
|
if (!room) {
|
|
12919
|
-
await Wazo.Phone.connect();
|
|
13145
|
+
await Wazo.Phone.connect({ media: constraints });
|
|
12920
13146
|
|
|
12921
13147
|
const withCamera = constraints && !!constraints.video;
|
|
12922
13148
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
const camelToUnderscore = (key ) => {
|
|
6
|
+
if (typeof key !== 'string') {
|
|
7
|
+
throw new Error('Input is not a string');
|
|
8
|
+
}
|
|
9
|
+
return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//
|
|
13
|
+
|
|
14
|
+
const convertKeysFromCamelToUnderscore = (args ) => {
|
|
15
|
+
if (!args || typeof args !== 'object' || Array.isArray(args)) {
|
|
16
|
+
throw new Error('Input is not an object');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return Object.keys(args).reduce((acc, key) => {
|
|
20
|
+
acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
|
|
21
|
+
? convertKeysFromCamelToUnderscore(args[key]) : args[key];
|
|
22
|
+
return acc;
|
|
23
|
+
}, {});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
//
|
|
27
|
+
|
|
28
|
+
describe('object utils', () => {
|
|
29
|
+
describe('convertKeysFromCamelToUnderscore', () => {
|
|
30
|
+
it('should throw an error when input is not an object', () => {
|
|
31
|
+
const msg = 'Input is not an object';
|
|
32
|
+
expect(() => convertKeysFromCamelToUnderscore(true)).toThrow(msg);
|
|
33
|
+
expect(() => convertKeysFromCamelToUnderscore(null)).toThrow(msg);
|
|
34
|
+
expect(() => convertKeysFromCamelToUnderscore(undefined)).toThrow(msg);
|
|
35
|
+
expect(() => convertKeysFromCamelToUnderscore([])).toThrow(msg);
|
|
36
|
+
expect(() => convertKeysFromCamelToUnderscore('some-string')).toThrow(msg);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should convert camel-cased keys to underscore', () => {
|
|
40
|
+
let value = Math.random();
|
|
41
|
+
expect(convertKeysFromCamelToUnderscore({ LoremIpsum: value })).toEqual({ lorem_ipsum: value });
|
|
42
|
+
value = Math.random();
|
|
43
|
+
expect(convertKeysFromCamelToUnderscore({ loremIpsum: value })).toEqual({ lorem_ipsum: value });
|
|
44
|
+
value = Math.random();
|
|
45
|
+
expect(convertKeysFromCamelToUnderscore({ 'lorem-ipsum': value })).toEqual({ 'lorem-ipsum': value });
|
|
46
|
+
value = Math.random();
|
|
47
|
+
expect(convertKeysFromCamelToUnderscore({ L123: value })).toEqual({ l123: value });
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle multi-leveled object', () => {
|
|
51
|
+
const value = Math.random();
|
|
52
|
+
expect(convertKeysFromCamelToUnderscore({ LoremIpsum: { DoloreSit: { Amet: value }, regular: 'reg' } }))
|
|
53
|
+
.toEqual({ lorem_ipsum: { dolore_sit: { amet: value }, regular: 'reg' } });
|
|
54
|
+
|
|
55
|
+
expect(convertKeysFromCamelToUnderscore({ LoremIpsum: { DoloreSit: { Amet: [value] }, regular: ['something'] } }))
|
|
56
|
+
.toEqual({ lorem_ipsum: { dolore_sit: { amet: [value] }, regular: ['something'] } });
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -104,6 +104,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
|
|
|
104
104
|
return fixed;
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
+
const addIcesInAllBundles = (sdp ) => {
|
|
108
|
+
const parsedSdp = sdpParser__default['default'].parse(sdp);
|
|
109
|
+
|
|
110
|
+
const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
|
|
111
|
+
if (!mediaWithCandidate) {
|
|
112
|
+
return sdp;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const { candidates } = mediaWithCandidate;
|
|
116
|
+
|
|
117
|
+
parsedSdp.media = parsedSdp.media.map(media => ({
|
|
118
|
+
...media,
|
|
119
|
+
candidates: media.candidates || candidates,
|
|
120
|
+
}));
|
|
121
|
+
|
|
122
|
+
return sdpParser__default['default'].write(parsedSdp);
|
|
123
|
+
};
|
|
124
|
+
|
|
107
125
|
/* eslint-disable max-len */
|
|
108
126
|
|
|
109
127
|
const goodSdp = `
|
|
@@ -268,4 +286,36 @@ describe('SDP utils', () => {
|
|
|
268
286
|
expect(hasAnActiveVideo(inactiveVideo)).toBeFalsy();
|
|
269
287
|
});
|
|
270
288
|
});
|
|
289
|
+
|
|
290
|
+
describe('Adding candidate in all bundles ', () => {
|
|
291
|
+
it('should add candidate everywhere', async () => {
|
|
292
|
+
const audioWithoutCandidate = `
|
|
293
|
+
c=IN IP4 203.0.113.1
|
|
294
|
+
m=audio 54400 RTP/SAVPF 0 96
|
|
295
|
+
m=video 54400 RTP/SAVPF 0 96
|
|
296
|
+
a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
|
|
297
|
+
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
|
|
298
|
+
`;
|
|
299
|
+
const fixedAudioWithoutCandidate = sdpParser__default['default'].parse(addIcesInAllBundles(audioWithoutCandidate));
|
|
300
|
+
|
|
301
|
+
expect(fixedAudioWithoutCandidate.media[0].candidates[0].type).toBe('host');
|
|
302
|
+
expect(fixedAudioWithoutCandidate.media[0].candidates[1].type).toBe('relay');
|
|
303
|
+
expect(fixedAudioWithoutCandidate.media[1].candidates[0].type).toBe('host');
|
|
304
|
+
expect(fixedAudioWithoutCandidate.media[1].candidates[1].type).toBe('relay');
|
|
305
|
+
|
|
306
|
+
// It should not add candidate if already present
|
|
307
|
+
const audioWithCandidate = `
|
|
308
|
+
c=IN IP4 203.0.113.1
|
|
309
|
+
m=audio 54400 RTP/SAVPF 0 96
|
|
310
|
+
a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ srflx
|
|
311
|
+
|
|
312
|
+
m=video 54400 RTP/SAVPF 0 96
|
|
313
|
+
a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
|
|
314
|
+
`;
|
|
315
|
+
const fixedAudioWithCandidate = sdpParser__default['default'].parse(addIcesInAllBundles(audioWithCandidate));
|
|
316
|
+
|
|
317
|
+
expect(fixedAudioWithCandidate.media[0].candidates[0].type).toBe('srflx');
|
|
318
|
+
expect(fixedAudioWithCandidate.media[1].candidates[0].type).toBe('host');
|
|
319
|
+
});
|
|
320
|
+
});
|
|
271
321
|
});
|