[mirotalksfu] - add only host meeting recroding
هذا الالتزام موجود في:
@@ -23,6 +23,7 @@ class LocalStorage {
|
||||
lobby: false, // default false
|
||||
pitch_bar: true, // volume indicator
|
||||
sounds: true, // room notify sounds
|
||||
host_ony_recording: false, // presenter
|
||||
video_obj_fit: 2, // cover
|
||||
video_controls: 0, // off
|
||||
theme: 0, // dark
|
||||
@@ -83,6 +84,8 @@ class LocalStorage {
|
||||
case this.MEDIA_TYPE.audioVideo:
|
||||
this.INIT_CONFIG.audioVideo = status;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.setObjectLocalStorage('INIT_CONFIG', this.INIT_CONFIG);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ let isPitchBarEnabled = true;
|
||||
let isSoundEnabled = true;
|
||||
let isLobbyEnabled = false;
|
||||
let isLobbyOpen = false;
|
||||
let hostOnlyRecording = false;
|
||||
let isEnumerateAudioDevices = false;
|
||||
let isEnumerateVideoDevices = false;
|
||||
let isAudioAllowed = false;
|
||||
@@ -178,9 +179,10 @@ function initClient() {
|
||||
);
|
||||
setTippy('switchPitchBar', 'Toggle audio pitch bar', 'right');
|
||||
setTippy('switchSounds', 'Toggle the sounds notifications', 'right');
|
||||
setTippy('switchShare', "Show 'Share Room' popup on join.", 'right');
|
||||
setTippy('switchShare', "Show 'Share Room' popup on join", 'right');
|
||||
setTippy('roomId', 'Room name', 'right');
|
||||
setTippy('sessionTime', 'Session time', 'right');
|
||||
setTippy('roomRecording', 'Only the host (presenter) has the capability to record the meeting', 'bottom');
|
||||
setTippy('whiteboardGhostButton', 'Toggle transparent background', 'bottom');
|
||||
setTippy('wbBackgroundColorEl', 'Background color', 'bottom');
|
||||
setTippy('wbDrawingColorEl', 'Drawing color', 'bottom');
|
||||
@@ -924,6 +926,7 @@ function roomIsReady() {
|
||||
show(fileShareButton);
|
||||
BUTTONS.settings.lockRoomButton && show(lockRoomButton);
|
||||
BUTTONS.settings.lobbyButton && show(lobbyButton);
|
||||
BUTTONS.settings.host_only_recording && show(roomRecording);
|
||||
BUTTONS.main.aboutButton && show(aboutButton);
|
||||
if (!DetectRTC.isMobileDevice) show(pinUnpinGridDiv);
|
||||
handleButtons();
|
||||
@@ -1522,6 +1525,14 @@ function handleSelects() {
|
||||
lS.setSettings(lsSettings);
|
||||
e.target.blur();
|
||||
};
|
||||
// recording
|
||||
switchHostOnlyRecording.onchange = (e) => {
|
||||
hostOnlyRecording = e.currentTarget.checked;
|
||||
rc.roomAction(hostOnlyRecording ? 'hostOnlyRecordingOn' : 'hostOnlyRecordingOff');
|
||||
lsSettings.host_only_recording = hostOnlyRecording;
|
||||
lS.setSettings(lsSettings);
|
||||
e.target.blur();
|
||||
};
|
||||
// styling
|
||||
BtnAspectRatio.onchange = () => {
|
||||
setAspectRatio(BtnAspectRatio.value);
|
||||
@@ -1657,7 +1668,7 @@ function loadSettingsFromLocalStorage() {
|
||||
|
||||
function handleRoomClientEvents() {
|
||||
rc.on(RoomClient.EVENTS.startRec, () => {
|
||||
console.log('Room Client start recoding');
|
||||
console.log('Room event: Client start recoding');
|
||||
hide(startRecButton);
|
||||
show(stopRecButton);
|
||||
show(pauseRecButton);
|
||||
@@ -1665,17 +1676,17 @@ function handleRoomClientEvents() {
|
||||
startRecordingTimer();
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.pauseRec, () => {
|
||||
console.log('Room Client pause recoding');
|
||||
console.log('Room event: Client pause recoding');
|
||||
hide(pauseRecButton);
|
||||
show(resumeRecButton);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.resumeRec, () => {
|
||||
console.log('Room Client resume recoding');
|
||||
console.log('Room event: Client resume recoding');
|
||||
hide(resumeRecButton);
|
||||
show(pauseRecButton);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.stopRec, () => {
|
||||
console.log('Room Client stop recoding');
|
||||
console.log('Room event: Client stop recoding');
|
||||
hide(stopRecButton);
|
||||
hide(pauseRecButton);
|
||||
hide(resumeRecButton);
|
||||
@@ -1684,43 +1695,43 @@ function handleRoomClientEvents() {
|
||||
stopRecordingTimer();
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.raiseHand, () => {
|
||||
console.log('Room Client raise hand');
|
||||
console.log('Room event: Client raise hand');
|
||||
hide(raiseHandButton);
|
||||
show(lowerHandButton);
|
||||
setColor(lowerHandIcon, 'lime');
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.lowerHand, () => {
|
||||
console.log('Room Client lower hand');
|
||||
console.log('Room event: Client lower hand');
|
||||
hide(lowerHandButton);
|
||||
show(raiseHandButton);
|
||||
setColor(lowerHandIcon, 'white');
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.startAudio, () => {
|
||||
console.log('Room Client start audio');
|
||||
console.log('Room event: Client start audio');
|
||||
hide(startAudioButton);
|
||||
show(stopAudioButton);
|
||||
setColor(startAudioButton, 'red');
|
||||
setAudioButtonsDisabled(false);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.pauseAudio, () => {
|
||||
console.log('Room Client pause audio');
|
||||
console.log('Room event: Client pause audio');
|
||||
hide(stopAudioButton);
|
||||
show(startAudioButton);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.resumeAudio, () => {
|
||||
console.log('Room Client resume audio');
|
||||
console.log('Room event: Client resume audio');
|
||||
hide(startAudioButton);
|
||||
show(stopAudioButton);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.stopAudio, () => {
|
||||
console.log('Room Client stop audio');
|
||||
console.log('Room event: Client stop audio');
|
||||
hide(stopAudioButton);
|
||||
show(startAudioButton);
|
||||
setAudioButtonsDisabled(false);
|
||||
stopMicrophoneProcessing();
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.startVideo, () => {
|
||||
console.log('Room Client start video');
|
||||
console.log('Room event: Client start video');
|
||||
hide(startVideoButton);
|
||||
show(stopVideoButton);
|
||||
setColor(startVideoButton, 'red');
|
||||
@@ -1728,17 +1739,17 @@ function handleRoomClientEvents() {
|
||||
if (isParticipantsListOpen) getRoomParticipants(true);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.pauseVideo, () => {
|
||||
console.log('Room Client pause video');
|
||||
console.log('Room event: Client pause video');
|
||||
hide(stopVideoButton);
|
||||
show(startVideoButton);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.resumeVideo, () => {
|
||||
console.log('Room Client resume video');
|
||||
console.log('Room event: Client resume video');
|
||||
hide(startVideoButton);
|
||||
show(stopVideoButton);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.stopVideo, () => {
|
||||
console.log('Room Client stop video');
|
||||
console.log('Room event: Client stop video');
|
||||
hide(stopVideoButton);
|
||||
show(startVideoButton);
|
||||
setVideoButtonsDisabled(false);
|
||||
@@ -1746,38 +1757,38 @@ function handleRoomClientEvents() {
|
||||
if (isParticipantsListOpen) getRoomParticipants(true);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.startScreen, () => {
|
||||
console.log('Room Client start screen');
|
||||
console.log('Room event: Client start screen');
|
||||
hide(startScreenButton);
|
||||
show(stopScreenButton);
|
||||
if (isParticipantsListOpen) getRoomParticipants(true);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.pauseScreen, () => {
|
||||
console.log('Room Client pause screen');
|
||||
console.log('Room event: Client pause screen');
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.resumeScreen, () => {
|
||||
console.log('Room Client resume screen');
|
||||
console.log('Room event: Client resume screen');
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.stopScreen, () => {
|
||||
console.log('Room Client stop screen');
|
||||
console.log('Room event: Client stop screen');
|
||||
hide(stopScreenButton);
|
||||
show(startScreenButton);
|
||||
if (isParticipantsListOpen) getRoomParticipants(true);
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.roomLock, () => {
|
||||
console.log('Room Client lock room');
|
||||
console.log('Room event: Client lock room');
|
||||
hide(lockRoomButton);
|
||||
show(unlockRoomButton);
|
||||
setColor(unlockRoomButton, 'red');
|
||||
isRoomLocked = true;
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.roomUnlock, () => {
|
||||
console.log('Room Client unlock room');
|
||||
console.log('Room event: Client unlock room');
|
||||
hide(unlockRoomButton);
|
||||
show(lockRoomButton);
|
||||
isRoomLocked = false;
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.lobbyOn, () => {
|
||||
console.log('Room Client room lobby enabled');
|
||||
console.log('Room event: Client room lobby enabled');
|
||||
if (isRulesActive && !isPresenter) {
|
||||
hide(lobbyButton);
|
||||
}
|
||||
@@ -1785,13 +1796,36 @@ function handleRoomClientEvents() {
|
||||
isLobbyEnabled = true;
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.lobbyOff, () => {
|
||||
console.log('Room Client room lobby disabled');
|
||||
console.log('Room event: Client room lobby disabled');
|
||||
isLobbyEnabled = false;
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.hostOnlyRecordingOn, () => {
|
||||
if (isRulesActive && !isPresenter) {
|
||||
console.log('Room event: host only recording enabled');
|
||||
// Stop recording ...
|
||||
if (rc.isRecording() || recordingStatus.innerText != '0s') {
|
||||
console.log('Room event: host only recording enabled, going to stop recording');
|
||||
rc.stopRecording();
|
||||
}
|
||||
hide(startRecButton);
|
||||
hide(roomRecording);
|
||||
show(recordingMessage);
|
||||
hostOnlyRecording = true;
|
||||
}
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.hostOnlyRecordingOff, () => {
|
||||
if (isRulesActive && !isPresenter) {
|
||||
console.log('Room event: host only recording disabled');
|
||||
show(startRecButton);
|
||||
hide(roomRecording);
|
||||
hide(recordingMessage);
|
||||
hostOnlyRecording = false;
|
||||
}
|
||||
});
|
||||
rc.on(RoomClient.EVENTS.exitRoom, () => {
|
||||
console.log('Room Client leave room');
|
||||
console.log('Room event: Client leave room');
|
||||
if (rc.isRecording() || recordingStatus.innerText != '0s') {
|
||||
console.log('Room Client save recording before to exit');
|
||||
console.log('Room event: Client save recording before to exit');
|
||||
rc.stopRecording();
|
||||
}
|
||||
if (survey.enabled) {
|
||||
@@ -2387,6 +2421,8 @@ function whiteboardAction(data, emit = true) {
|
||||
case 'close':
|
||||
if (wbIsOpen) toggleWhiteboard();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
//...
|
||||
}
|
||||
}
|
||||
@@ -2671,6 +2707,8 @@ function setTheme() {
|
||||
document.body.style.background = 'radial-gradient(#69140E, #3C1518)';
|
||||
selectTheme.selectedIndex = 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
//...
|
||||
}
|
||||
wbIsBgTransparent = false;
|
||||
|
||||
@@ -51,6 +51,7 @@ const icons = {
|
||||
sounds: '<i class="fas fa-music"></i>',
|
||||
fileSend: '<i class="fa-solid fa-file-export"></i>',
|
||||
fileReceive: '<i class="fa-solid fa-file-import"></i>',
|
||||
recording: '<i class="fas fa-record-vinyl"></i>',
|
||||
};
|
||||
|
||||
const image = {
|
||||
@@ -107,6 +108,8 @@ const _EVENTS = {
|
||||
lobbyOn: 'lobbyOn',
|
||||
lobbyOff: 'lobbyOff',
|
||||
roomUnlock: 'roomUnlock',
|
||||
hostOnlyRecordingOn: 'hostOnlyRecordingOn',
|
||||
hostOnlyRecordingOff: 'hostOnlyRecordingOff',
|
||||
};
|
||||
|
||||
let recordedBlobs;
|
||||
@@ -280,6 +283,7 @@ class RoomClient {
|
||||
.request('join', data)
|
||||
.then(
|
||||
async function (room) {
|
||||
console.log('##### JOIN ROOM #####', room);
|
||||
if (room === 'isLocked') {
|
||||
this.event(_EVENTS.roomLock);
|
||||
console.log('00-WARNING ----> Room is Locked, Try to unlock by the password');
|
||||
@@ -329,6 +333,10 @@ class RoomClient {
|
||||
this.getId('isUserPresenter').innerText = isPresenter;
|
||||
window.localStorage.isReconnected = false;
|
||||
handleRules(isPresenter);
|
||||
room.config.hostOnlyRecording
|
||||
? (console.log('07.1 ----> WARNING Room Host only recording enabled'),
|
||||
this.event(_EVENTS.hostOnlyRecordingOn))
|
||||
: this.event(_EVENTS.hostOnlyRecordingOff);
|
||||
}
|
||||
adaptAspectRatio(participantsCount);
|
||||
for (let peer of Array.from(peers.keys()).filter((id) => id !== this.peer_id)) {
|
||||
@@ -1128,6 +1136,8 @@ class RoomClient {
|
||||
},
|
||||
}; // video cam constraints ultra high bandwidth
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.videoQualitySelectedIndex = videoQuality.selectedIndex;
|
||||
return videoConstraints;
|
||||
@@ -1441,6 +1451,8 @@ class RoomClient {
|
||||
}
|
||||
console.log('[addProducer] audio-element-count', this.localAudioEl.childElementCount);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
@@ -1846,6 +1858,8 @@ class RoomClient {
|
||||
}
|
||||
console.log('[Add audioConsumers]', this.audioConsumers);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
@@ -2089,6 +2103,8 @@ class RoomClient {
|
||||
case mediaType.screen:
|
||||
track = stream.getVideoTracks()[0];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const consumerStream = new MediaStream();
|
||||
consumerStream.addTrack(track);
|
||||
@@ -2424,6 +2440,8 @@ class RoomClient {
|
||||
document.documentElement.style.setProperty('--btns-width', '320px');
|
||||
document.documentElement.style.setProperty('--btns-flex-direction', 'row');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2609,6 +2627,8 @@ class RoomClient {
|
||||
this.videoMediaContainer.style.width = '100% !important';
|
||||
this.videoMediaContainer.style.height = '25%';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
resizeVideoMedia();
|
||||
}
|
||||
@@ -3832,6 +3852,8 @@ class RoomClient {
|
||||
this.userLog('info', `${peer_name} <i class="fab fa-youtube"></i> closed the video`, 'top-end');
|
||||
this.closeVideo();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3993,6 +4015,16 @@ class RoomClient {
|
||||
this.socket.emit('roomAction', data);
|
||||
if (popup) this.roomStatus(action);
|
||||
break;
|
||||
case 'hostOnlyRecordingOn':
|
||||
this.socket.emit('roomAction', data);
|
||||
if (popup) this.roomStatus(action);
|
||||
break;
|
||||
case 'hostOnlyRecordingOff':
|
||||
this.socket.emit('roomAction', data);
|
||||
if (popup) this.roomStatus(action);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.roomStatus(action);
|
||||
@@ -4018,6 +4050,14 @@ class RoomClient {
|
||||
this.event(_EVENTS.lobbyOff);
|
||||
this.userLog('info', `${icons.lobby} Lobby is disabled`, 'top-end');
|
||||
break;
|
||||
case 'hostOnlyRecordingOn':
|
||||
this.event(_EVENTS.hostOnlyRecordingOn);
|
||||
this.userLog('info', `${icons.recording} Host only recording is enabled`, 'top-end');
|
||||
break;
|
||||
case 'hostOnlyRecordingOff':
|
||||
this.event(_EVENTS.hostOnlyRecordingOff);
|
||||
this.userLog('info', `${icons.recording} Host only recording is disabled`, 'top-end');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -4040,7 +4080,11 @@ class RoomClient {
|
||||
break;
|
||||
case 'notify':
|
||||
this.sound('switch');
|
||||
this.userLog('info', `${icons.share} Share room on join enabled ${status}`, 'top-end');
|
||||
this.userLog('info', `${icons.share} Share room on join ${status}`, 'top-end');
|
||||
break;
|
||||
case 'hostOnlyRecording':
|
||||
this.sound('switch');
|
||||
this.userLog('info', `${icons.recording} Only host recording ${status}`, 'top-end');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -4055,6 +4099,8 @@ class RoomClient {
|
||||
case 'KO':
|
||||
this.roomIsLocked();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4122,6 +4168,8 @@ class RoomClient {
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4429,6 +4477,8 @@ class RoomClient {
|
||||
case 'privacy':
|
||||
this.setVideoPrivacyStatus(words[1], words[2] == 'true');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
//...
|
||||
}
|
||||
}
|
||||
@@ -4500,6 +4550,8 @@ class RoomClient {
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
//...
|
||||
}
|
||||
}
|
||||
@@ -4525,6 +4577,8 @@ class RoomClient {
|
||||
case 'eject':
|
||||
this.exit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -4593,6 +4647,8 @@ class RoomClient {
|
||||
title = 'Stop screen share to the ' + whoMuteHideStop;
|
||||
text = "Once stop, you won't be able to start them, but they can start themselves at any time.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Swal.fire({
|
||||
background: swalBackground,
|
||||
@@ -4622,6 +4678,8 @@ class RoomClient {
|
||||
case 'stop':
|
||||
let peerScreenButton = this.getId(data.peer_id + '___pScreen');
|
||||
if (peerScreenButton) peerScreenButton.innerHTML = _PEER.screenOff;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.socket.emit('peerAction', data);
|
||||
@@ -4635,6 +4693,8 @@ class RoomClient {
|
||||
this.peerActionProgress(action, 'In progress, wait...', 2000, 'refresh');
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
//...
|
||||
}
|
||||
}
|
||||
@@ -4690,6 +4750,8 @@ class RoomClient {
|
||||
this.event(_EVENTS.lowerHand);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
let data = {
|
||||
peer_name: peer_name,
|
||||
@@ -4724,6 +4786,8 @@ class RoomClient {
|
||||
if (peer_hand) peer_hand.style.display = 'none';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isParticipantsListOpen) getRoomParticipants(true);
|
||||
|
||||
@@ -24,11 +24,12 @@ const BUTTONS = {
|
||||
exitButton: true,
|
||||
},
|
||||
settings: {
|
||||
lockRoomButton: true,
|
||||
unlockRoomButton: true,
|
||||
lobbyButton: true,
|
||||
lockRoomButton: true, // presenter
|
||||
unlockRoomButton: true, // presenter
|
||||
lobbyButton: true, // presenter
|
||||
tabRecording: true,
|
||||
pushToTalk: true,
|
||||
host_only_recording: true, // presenter
|
||||
},
|
||||
producerVideo: {
|
||||
videoPictureInPicture: true,
|
||||
@@ -102,9 +103,19 @@ function handleRules(isPresenter) {
|
||||
BUTTONS.consumerVideo.muteVideoButton = true;
|
||||
BUTTONS.whiteboard.whiteboardLockButton = true;
|
||||
//...
|
||||
|
||||
// ##################################
|
||||
// Auto detected rules for presenter
|
||||
// ##################################
|
||||
|
||||
// Room lobby
|
||||
isLobbyEnabled = lsSettings.lobby;
|
||||
switchLobby.checked = isLobbyEnabled;
|
||||
rc.roomAction(isLobbyEnabled ? 'lobbyOn' : 'lobbyOff', true, false);
|
||||
// ROom host-only-recording
|
||||
hostOnlyRecording = lsSettings.host_only_recording;
|
||||
switchHostOnlyRecording.checked = hostOnlyRecording;
|
||||
rc.roomAction(hostOnlyRecording ? 'hostOnlyRecordingOn' : 'hostOnlyRecordingOff', true, false);
|
||||
//...
|
||||
}
|
||||
// main. settings...
|
||||
|
||||
@@ -416,6 +416,34 @@ access to use this app.
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="roomRecording" class="hidden">
|
||||
<hr style="border: 1px solid grey" />
|
||||
<table class="settingsTable">
|
||||
<tr>
|
||||
<td class="custom-width">
|
||||
<div class="title">
|
||||
<i class="fa-solid fa-user-shield"></i>
|
||||
<p>Only host</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="form-check form-switch form-switch-md title">
|
||||
<input
|
||||
id="switchHostOnlyRecording"
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="recordingMessage" class="hidden">
|
||||
<div class="title">
|
||||
<i class="fa-solid fa-ban fa-2xl"></i>
|
||||
<p>The presenter has disabled meeting recording.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tabVideoShare" class="tabcontent">
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم