@wazo/sdk 0.37.2 → 0.37.6
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/dist/wazo-sdk.js +5 -5
- package/esm/__tests__/api-client.test.js +84 -22
- package/esm/__tests__/web-rtc-client.test.js +156 -55
- package/esm/api/call-logd.js +10 -22
- package/esm/api/calld.js +3 -0
- package/esm/api/confd.js +71 -0
- package/esm/api-client.js +84 -22
- package/esm/checker/Checker.js +160 -55
- package/esm/checker/checks/aor.js +84 -22
- package/esm/checker/checks/api.js +84 -22
- package/esm/checker/checks/index.js +160 -55
- package/esm/checker/checks/wazo-websocket.js +4 -0
- package/esm/checker/checks/webrtc-transport.js +156 -55
- package/esm/checker/checks/webrtc.js +156 -55
- package/esm/domain/AdHocAPIConference.js +84 -22
- package/esm/domain/CallLog.js +10 -22
- package/esm/domain/Features.js +84 -22
- package/esm/domain/Meeting.js +71 -0
- package/esm/domain/Phone/CTIPhone.js +84 -22
- package/esm/domain/Phone/WebRTCPhone.js +22 -8
- package/esm/domain/__tests__/CallLog.test.js +10 -22
- package/esm/index.js +726 -371
- package/esm/lib/WazoSessionDescriptionHandler.js +17 -9
- package/esm/service/CallApi.js +84 -22
- package/esm/service/getApiClient.js +84 -22
- package/esm/simple/Auth.js +717 -363
- package/esm/simple/Configuration.js +717 -363
- package/esm/simple/Directory.js +84 -22
- package/esm/simple/Phone.js +709 -355
- package/esm/simple/Websocket.js +6 -0
- package/esm/simple/index.js +719 -365
- package/esm/simple/room/LocalParticipant.js +689 -335
- package/esm/simple/room/Participant.js +689 -335
- package/esm/simple/room/RemoteParticipant.js +689 -335
- package/esm/simple/room/Room.js +689 -335
- package/esm/simple/room/SipRoom.js +13001 -0
- package/esm/simple/room/Stream.js +719 -365
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +4130 -3774
- package/esm/simple/utils.js +719 -365
- package/esm/web-rtc-client.js +156 -55
- package/esm/websocket-client.js +5 -1
- package/lib/__tests__/api-client.test.js +84 -22
- package/lib/__tests__/web-rtc-client.test.js +156 -55
- package/lib/api/call-logd.js +10 -22
- package/lib/api/calld.js +3 -0
- package/lib/api/confd.js +71 -0
- package/lib/api-client.js +84 -22
- package/lib/checker/Checker.js +160 -55
- package/lib/checker/checks/aor.js +84 -22
- package/lib/checker/checks/api.js +84 -22
- package/lib/checker/checks/index.js +160 -55
- package/lib/checker/checks/wazo-websocket.js +4 -0
- package/lib/checker/checks/webrtc-transport.js +156 -55
- package/lib/checker/checks/webrtc.js +156 -55
- package/lib/domain/AdHocAPIConference.js +84 -22
- package/lib/domain/CallLog.js +10 -22
- package/lib/domain/Features.js +84 -22
- package/lib/domain/Meeting.js +73 -0
- package/lib/domain/Phone/CTIPhone.js +84 -22
- package/lib/domain/Phone/WebRTCPhone.js +22 -8
- package/lib/domain/__tests__/CallLog.test.js +10 -22
- package/lib/index.js +726 -371
- package/lib/lib/WazoSessionDescriptionHandler.js +17 -9
- package/lib/service/CallApi.js +84 -22
- package/lib/service/getApiClient.js +84 -22
- package/lib/simple/Auth.js +717 -363
- package/lib/simple/Configuration.js +717 -363
- package/lib/simple/Directory.js +84 -22
- package/lib/simple/Phone.js +709 -355
- package/lib/simple/Websocket.js +6 -0
- package/lib/simple/index.js +719 -365
- package/lib/simple/room/LocalParticipant.js +689 -335
- package/lib/simple/room/Participant.js +689 -335
- package/lib/simple/room/RemoteParticipant.js +689 -335
- package/lib/simple/room/Room.js +689 -335
- package/lib/simple/room/SipRoom.js +13011 -0
- package/lib/simple/room/Stream.js +719 -365
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +4131 -3775
- package/lib/simple/utils.js +719 -365
- package/lib/web-rtc-client.js +156 -55
- package/lib/websocket-client.js +6 -0
- package/package.json +1 -1
- package/src/api/calld.js +3 -0
- package/src/api/confd.js +13 -0
- package/src/domain/CallLog.js +10 -22
- package/src/domain/Meeting.js +59 -0
- package/src/domain/Phone/WebRTCPhone.js +22 -8
- package/src/index.js +2 -0
- package/src/lib/WazoSessionDescriptionHandler.js +17 -9
- package/src/simple/Phone.js +13 -4
- package/src/simple/index.js +4 -0
- package/src/simple/room/Participant.js +7 -0
- package/src/simple/room/Room.js +158 -79
- package/src/simple/room/SipRoom.js +147 -0
- package/src/simple/room/Stream.js +1 -3
- package/src/simple/room/__tests__/RemoteParticipant.test.js +3 -2
- package/src/types/WebSocketMessage.js +21 -0
- package/src/web-rtc-client.js +55 -24
- package/src/websocket-client.js +4 -0
|
@@ -453,7 +453,9 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
453
453
|
.then(() => {
|
|
454
454
|
if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
|
|
455
455
|
// Add a video an empty bundle to be able to replaceTrack when joining a conference without video
|
|
456
|
-
this.peerConnection.addTransceiver
|
|
456
|
+
if (this.peerConnection.addTransceiver) {
|
|
457
|
+
this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
|
|
458
|
+
}
|
|
457
459
|
}
|
|
458
460
|
})
|
|
459
461
|
.then(() => this.createLocalOfferOrAnswer(options))
|
|
@@ -480,12 +482,6 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
480
482
|
};
|
|
481
483
|
})
|
|
482
484
|
.then((sessionDescription) => this.applyModifiers(sessionDescription, modifiers))
|
|
483
|
-
.then((sessionDescription) => {
|
|
484
|
-
// Set new constraints to avoid the constraints check issue in `sdh.getLocalMediaStream` later.
|
|
485
|
-
this.localMediaStreamConstraints = options.constraints;
|
|
486
|
-
|
|
487
|
-
return sessionDescription;
|
|
488
|
-
})
|
|
489
485
|
.then((sessionDescription) => ({ body: sessionDescription.sdp, contentType: 'application/sdp' }))
|
|
490
486
|
.catch((error) => {
|
|
491
487
|
wazoLogger.error('error when creating media', error);
|
|
@@ -680,6 +676,9 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
680
676
|
|
|
681
677
|
// set the transceiver direction to the answer direction
|
|
682
678
|
this._peerConnection.getTransceivers().forEach((transceiver) => {
|
|
679
|
+
if (transceiver.stopped) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
683
682
|
if (transceiver.direction /* guarding, but should always be true */) {
|
|
684
683
|
const { receiver } = transceiver;
|
|
685
684
|
if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
|
|
@@ -724,10 +723,15 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
724
723
|
if (kind !== 'audio' && kind !== 'video') {
|
|
725
724
|
throw new Error(`Unknown new track kind ${kind}.`);
|
|
726
725
|
}
|
|
727
|
-
const sender = pc.getSenders().find((otherSender) =>
|
|
726
|
+
const sender = pc.getSenders && pc.getSenders().find((otherSender) =>
|
|
727
|
+
otherSender.track && otherSender.track.kind === kind);
|
|
728
728
|
|
|
729
729
|
// Do not reuse sender video tracks in SFU
|
|
730
730
|
if (sender && (!sfu || newTrack.kind === 'audio')) {
|
|
731
|
+
if (sender.track) {
|
|
732
|
+
// eslint-disable-next-line no-param-reassign
|
|
733
|
+
newTrack.enabled = sender.track.enabled;
|
|
734
|
+
}
|
|
731
735
|
trackUpdates.push(
|
|
732
736
|
new Promise((resolve) => {
|
|
733
737
|
this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
|
|
@@ -761,7 +765,11 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
|
|
|
761
765
|
// Review: could make streamless tracks a configurable option?
|
|
762
766
|
// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addTrack#Usage_notes
|
|
763
767
|
try {
|
|
764
|
-
pc.addTrack
|
|
768
|
+
if (pc.addTrack) {
|
|
769
|
+
pc.addTrack(newTrack, localStream);
|
|
770
|
+
} else {
|
|
771
|
+
pc.addStream(localStream);
|
|
772
|
+
}
|
|
765
773
|
} catch (error) {
|
|
766
774
|
this.logger.error(`SessionDescriptionHandler.setLocalMediaStream - failed to add sender ${kind} track`);
|
|
767
775
|
throw error;
|
package/lib/service/CallApi.js
CHANGED
|
@@ -1816,7 +1816,11 @@ class CallLog {
|
|
|
1816
1816
|
answered: plain.answered,
|
|
1817
1817
|
callDirection: plain.call_direction,
|
|
1818
1818
|
destination: {
|
|
1819
|
-
|
|
1819
|
+
// @TEMP: Temporarily assuming empty numbers are meetings
|
|
1820
|
+
// which is admittedly a very dangerous assumption. Did i mention it was temporary?
|
|
1821
|
+
extension: plain.requested_extension
|
|
1822
|
+
|| plain.destination_extension
|
|
1823
|
+
|| `meeting-${plain.requested_name || plain.destination_name || ''}`,
|
|
1820
1824
|
name: plain.requested_name || plain.destination_name || '',
|
|
1821
1825
|
},
|
|
1822
1826
|
source: {
|
|
@@ -1832,27 +1836,11 @@ class CallLog {
|
|
|
1832
1836
|
}
|
|
1833
1837
|
|
|
1834
1838
|
static parseNew(plain , session ) {
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
extension: plain.requested_extension || plain.destination_extension,
|
|
1841
|
-
name: plain.requested_name || plain.destination_name || '',
|
|
1842
|
-
},
|
|
1843
|
-
source: {
|
|
1844
|
-
extension: plain.source_extension,
|
|
1845
|
-
name: plain.source_name,
|
|
1846
|
-
},
|
|
1847
|
-
id: plain.id,
|
|
1848
|
-
duration: (plain.duration || 0) * 1000, // duration is in seconds
|
|
1849
|
-
start: moment__default['default'](plain.start).toDate(),
|
|
1850
|
-
end: plain.end ? moment__default['default'](plain.end).toDate() : null,
|
|
1851
|
-
recordings: Recording.parseMany(plain.recordings),
|
|
1852
|
-
// @TODO: FIXME add verification declined vs missed call
|
|
1853
|
-
newMissedCall: session
|
|
1854
|
-
&& session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
|
|
1855
|
-
});
|
|
1839
|
+
const callLog = CallLog.parse(plain);
|
|
1840
|
+
// @TODO: FIXME add verification declined vs missed call
|
|
1841
|
+
callLog.newMissedCall = session
|
|
1842
|
+
&& session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered;
|
|
1843
|
+
return callLog;
|
|
1856
1844
|
}
|
|
1857
1845
|
|
|
1858
1846
|
static newFrom(profile ) {
|
|
@@ -3027,6 +3015,65 @@ class ExternalApp {
|
|
|
3027
3015
|
}
|
|
3028
3016
|
}
|
|
3029
3017
|
|
|
3018
|
+
//
|
|
3019
|
+
|
|
3020
|
+
|
|
3021
|
+
|
|
3022
|
+
|
|
3023
|
+
|
|
3024
|
+
|
|
3025
|
+
|
|
3026
|
+
|
|
3027
|
+
|
|
3028
|
+
|
|
3029
|
+
|
|
3030
|
+
class Meeting {
|
|
3031
|
+
|
|
3032
|
+
|
|
3033
|
+
|
|
3034
|
+
|
|
3035
|
+
|
|
3036
|
+
|
|
3037
|
+
|
|
3038
|
+
|
|
3039
|
+
|
|
3040
|
+
|
|
3041
|
+
static parse(plain ) {
|
|
3042
|
+
return new Meeting({
|
|
3043
|
+
guestSipAuthorization: plain.guest_sip_authorization,
|
|
3044
|
+
hostname: plain.hostname,
|
|
3045
|
+
name: plain.name,
|
|
3046
|
+
ownerUuids: plain.owner_uuids,
|
|
3047
|
+
port: plain.port,
|
|
3048
|
+
uuid: plain.uuid,
|
|
3049
|
+
number: plain.number,
|
|
3050
|
+
});
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
static newFrom(meeting ) {
|
|
3054
|
+
return newFrom(meeting, Meeting);
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, hostname, number } = {}) {
|
|
3058
|
+
this.guestSipAuthorization = guestSipAuthorization;
|
|
3059
|
+
this.hostname = hostname;
|
|
3060
|
+
this.name = name;
|
|
3061
|
+
this.ownerUuids = ownerUuids;
|
|
3062
|
+
this.port = port;
|
|
3063
|
+
this.uuid = uuid;
|
|
3064
|
+
this.number = number;
|
|
3065
|
+
|
|
3066
|
+
// Useful to compare instead of instanceof with minified code
|
|
3067
|
+
this.type = 'Meeting';
|
|
3068
|
+
}
|
|
3069
|
+
|
|
3070
|
+
getGuestSipCredentials() {
|
|
3071
|
+
// eslint-disable-next-line no-undef
|
|
3072
|
+
const [username, secret] = atob(this.guestSipAuthorization).split(':');
|
|
3073
|
+
return { username, secret };
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3030
3077
|
/* */
|
|
3031
3078
|
|
|
3032
3079
|
var confdMethods = (client , baseUrl ) => ({
|
|
@@ -3091,6 +3138,18 @@ var confdMethods = (client , baseUrl ) => ({
|
|
|
3091
3138
|
return null;
|
|
3092
3139
|
}
|
|
3093
3140
|
},
|
|
3141
|
+
|
|
3142
|
+
createMyMeeting: (name ) =>
|
|
3143
|
+
client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
|
|
3144
|
+
|
|
3145
|
+
deleteMyMeeting: (meetingUuid ) =>
|
|
3146
|
+
client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
|
|
3147
|
+
|
|
3148
|
+
getMeeting: (meetingUuid ) =>
|
|
3149
|
+
client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
3150
|
+
|
|
3151
|
+
guestGetMeeting: (meetingUuid ) =>
|
|
3152
|
+
client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
3094
3153
|
});
|
|
3095
3154
|
|
|
3096
3155
|
//
|
|
@@ -3925,6 +3984,9 @@ var calldMethods = (client , baseUrl ) => ({
|
|
|
3925
3984
|
getConferenceParticipantsAsUser: async (conferenceId ) =>
|
|
3926
3985
|
client.get(`${baseUrl}/users/me/conferences/${conferenceId}/participants`),
|
|
3927
3986
|
|
|
3987
|
+
getMeetingParticipantsAsUser: async (meetingUuid ) =>
|
|
3988
|
+
client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
|
|
3989
|
+
|
|
3928
3990
|
listTrunks: () => client.get(`${baseUrl}/trunks`),
|
|
3929
3991
|
|
|
3930
3992
|
mute: (callId ) =>
|
|
@@ -2501,6 +2501,65 @@ class ExternalApp {
|
|
|
2501
2501
|
}
|
|
2502
2502
|
}
|
|
2503
2503
|
|
|
2504
|
+
//
|
|
2505
|
+
|
|
2506
|
+
|
|
2507
|
+
|
|
2508
|
+
|
|
2509
|
+
|
|
2510
|
+
|
|
2511
|
+
|
|
2512
|
+
|
|
2513
|
+
|
|
2514
|
+
|
|
2515
|
+
|
|
2516
|
+
class Meeting {
|
|
2517
|
+
|
|
2518
|
+
|
|
2519
|
+
|
|
2520
|
+
|
|
2521
|
+
|
|
2522
|
+
|
|
2523
|
+
|
|
2524
|
+
|
|
2525
|
+
|
|
2526
|
+
|
|
2527
|
+
static parse(plain ) {
|
|
2528
|
+
return new Meeting({
|
|
2529
|
+
guestSipAuthorization: plain.guest_sip_authorization,
|
|
2530
|
+
hostname: plain.hostname,
|
|
2531
|
+
name: plain.name,
|
|
2532
|
+
ownerUuids: plain.owner_uuids,
|
|
2533
|
+
port: plain.port,
|
|
2534
|
+
uuid: plain.uuid,
|
|
2535
|
+
number: plain.number,
|
|
2536
|
+
});
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
static newFrom(meeting ) {
|
|
2540
|
+
return newFrom(meeting, Meeting);
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, hostname, number } = {}) {
|
|
2544
|
+
this.guestSipAuthorization = guestSipAuthorization;
|
|
2545
|
+
this.hostname = hostname;
|
|
2546
|
+
this.name = name;
|
|
2547
|
+
this.ownerUuids = ownerUuids;
|
|
2548
|
+
this.port = port;
|
|
2549
|
+
this.uuid = uuid;
|
|
2550
|
+
this.number = number;
|
|
2551
|
+
|
|
2552
|
+
// Useful to compare instead of instanceof with minified code
|
|
2553
|
+
this.type = 'Meeting';
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
getGuestSipCredentials() {
|
|
2557
|
+
// eslint-disable-next-line no-undef
|
|
2558
|
+
const [username, secret] = atob(this.guestSipAuthorization).split(':');
|
|
2559
|
+
return { username, secret };
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2504
2563
|
/* */
|
|
2505
2564
|
|
|
2506
2565
|
var confdMethods = (client , baseUrl ) => ({
|
|
@@ -2565,6 +2624,18 @@ var confdMethods = (client , baseUrl ) => ({
|
|
|
2565
2624
|
return null;
|
|
2566
2625
|
}
|
|
2567
2626
|
},
|
|
2627
|
+
|
|
2628
|
+
createMyMeeting: (name ) =>
|
|
2629
|
+
client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
|
|
2630
|
+
|
|
2631
|
+
deleteMyMeeting: (meetingUuid ) =>
|
|
2632
|
+
client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
|
|
2633
|
+
|
|
2634
|
+
getMeeting: (meetingUuid ) =>
|
|
2635
|
+
client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
2636
|
+
|
|
2637
|
+
guestGetMeeting: (meetingUuid ) =>
|
|
2638
|
+
client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
2568
2639
|
});
|
|
2569
2640
|
|
|
2570
2641
|
//
|
|
@@ -3149,7 +3220,11 @@ class CallLog {
|
|
|
3149
3220
|
answered: plain.answered,
|
|
3150
3221
|
callDirection: plain.call_direction,
|
|
3151
3222
|
destination: {
|
|
3152
|
-
|
|
3223
|
+
// @TEMP: Temporarily assuming empty numbers are meetings
|
|
3224
|
+
// which is admittedly a very dangerous assumption. Did i mention it was temporary?
|
|
3225
|
+
extension: plain.requested_extension
|
|
3226
|
+
|| plain.destination_extension
|
|
3227
|
+
|| `meeting-${plain.requested_name || plain.destination_name || ''}`,
|
|
3153
3228
|
name: plain.requested_name || plain.destination_name || '',
|
|
3154
3229
|
},
|
|
3155
3230
|
source: {
|
|
@@ -3165,27 +3240,11 @@ class CallLog {
|
|
|
3165
3240
|
}
|
|
3166
3241
|
|
|
3167
3242
|
static parseNew(plain , session ) {
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
extension: plain.requested_extension || plain.destination_extension,
|
|
3174
|
-
name: plain.requested_name || plain.destination_name || '',
|
|
3175
|
-
},
|
|
3176
|
-
source: {
|
|
3177
|
-
extension: plain.source_extension,
|
|
3178
|
-
name: plain.source_name,
|
|
3179
|
-
},
|
|
3180
|
-
id: plain.id,
|
|
3181
|
-
duration: (plain.duration || 0) * 1000, // duration is in seconds
|
|
3182
|
-
start: moment__default['default'](plain.start).toDate(),
|
|
3183
|
-
end: plain.end ? moment__default['default'](plain.end).toDate() : null,
|
|
3184
|
-
recordings: Recording.parseMany(plain.recordings),
|
|
3185
|
-
// @TODO: FIXME add verification declined vs missed call
|
|
3186
|
-
newMissedCall: session
|
|
3187
|
-
&& session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
|
|
3188
|
-
});
|
|
3243
|
+
const callLog = CallLog.parse(plain);
|
|
3244
|
+
// @TODO: FIXME add verification declined vs missed call
|
|
3245
|
+
callLog.newMissedCall = session
|
|
3246
|
+
&& session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered;
|
|
3247
|
+
return callLog;
|
|
3189
3248
|
}
|
|
3190
3249
|
|
|
3191
3250
|
static newFrom(profile ) {
|
|
@@ -3927,6 +3986,9 @@ var calldMethods = (client , baseUrl ) => ({
|
|
|
3927
3986
|
getConferenceParticipantsAsUser: async (conferenceId ) =>
|
|
3928
3987
|
client.get(`${baseUrl}/users/me/conferences/${conferenceId}/participants`),
|
|
3929
3988
|
|
|
3989
|
+
getMeetingParticipantsAsUser: async (meetingUuid ) =>
|
|
3990
|
+
client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
|
|
3991
|
+
|
|
3930
3992
|
listTrunks: () => client.get(`${baseUrl}/trunks`),
|
|
3931
3993
|
|
|
3932
3994
|
mute: (callId ) =>
|