[mirotalksfu] - #134 WIP add room broadcasting, bug fixing, update dep

هذا الالتزام موجود في:
Miroslav Pejic
2023-11-30 21:04:17 +01:00
الأصل 2e471c59bb
التزام f92ca94a58
10 ملفات معدلة مع 401 إضافات و106 حذوفات

عرض الملف

@@ -12,6 +12,9 @@ module.exports = class Room {
this.audioLevelObserver = null;
this.audioLevelObserverEnabled = true;
this.audioLastUpdateTime = 0;
// ##########################
this._isBroadcasting = false;
// ##########################
this._isLocked = false;
this._isLobbyEnabled = false;
this._roomPassword = null;
@@ -109,6 +112,11 @@ module.exports = class Room {
// ROOM MODERATOR
// ####################################################
updateRoomModeratorALL(data) {
this._moderator = data;
log.debug('Update room moderator all data', this._moderator);
}
updateRoomModerator(data) {
log.debug('Update room moderator', data);
switch (data.type) {
@@ -137,6 +145,7 @@ module.exports = class Room {
toJson() {
return {
id: this.id,
broadcasting: this._isBroadcasting,
config: {
isLocked: this._isLocked,
isLobbyEnabled: this._isLobbyEnabled,
@@ -312,6 +321,10 @@ module.exports = class Room {
// ROOM STATUS
// ####################################################
// GET
isBroadcasting() {
return this._isBroadcasting;
}
getPassword() {
return this._roomPassword;
}
@@ -324,6 +337,11 @@ module.exports = class Room {
isHostOnlyRecording() {
return this._hostOnlyRecording;
}
// SET
setIsBroadcasting(status) {
this._isBroadcasting = status;
}
setLocked(status, password) {
this._isLocked = status;
this._roomPassword = password;

عرض الملف

@@ -40,7 +40,7 @@ dependencies: {
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.2.8
* @version 1.2.9
*
*/
@@ -630,7 +630,7 @@ function startServer() {
const room = roomList.get(socket.room_id);
let peerCounts = room.getPeersCount();
const peerCounts = room.getPeersCount();
log.debug('Peer counts', { peerCounts: peerCounts });
@@ -668,7 +668,13 @@ function startServer() {
const room = roomList.get(socket.room_id);
log.debug('Room action:', data);
switch (data.action) {
case 'broadcasting':
if (!isPresenter) return;
room.setIsBroadcasting(data.room_broadcasting);
room.broadCast(socket.id, 'roomAction', data.action);
break;
case 'lock':
if (!isPresenter) return;
if (!room.isLocked()) {
@@ -716,6 +722,7 @@ function startServer() {
break;
}
log.debug('Room status', {
broadcasting: room.isBroadcasting(),
locked: room.isLocked(),
lobby: room.isLobbyEnabled(),
hostOnlyRecording: room.isHostOnlyRecording(),
@@ -780,31 +787,58 @@ function startServer() {
const room = roomList.get(socket.room_id);
// update my peer_info status to all in the room
room.getPeers().get(socket.id).updatePeerInfo(data);
room.broadCast(socket.id, 'updatePeerInfo', data);
if (data.broadcast) {
log.info('updatePeerInfo broadcast data');
room.broadCast(socket.id, 'updatePeerInfo', data);
}
});
socket.on('updateRoomModerator', (dataObject) => {
socket.on('updateRoomModerator', async (dataObject) => {
if (!roomList.has(socket.room_id)) return;
const data = checkXSS(dataObject);
const room = roomList.get(socket.room_id);
room.updateRoomModerator(data);
const isPresenter = await isPeerPresenter(socket.room_id, socket.id, data.peer_name, data.peer_uuid);
switch (data.type) {
if (!isPresenter) return;
const moderator = data.moderator;
room.updateRoomModerator(moderator);
switch (moderator.type) {
case 'audio_cant_unmute':
case 'video_cant_unhide':
case 'screen_cant_share':
room.broadCast(socket.id, 'updateRoomModerator', data);
room.broadCast(socket.id, 'updateRoomModerator', moderator);
break;
default:
break;
}
});
socket.on('updateRoomModeratorALL', async (dataObject) => {
if (!roomList.has(socket.room_id)) return;
const data = checkXSS(dataObject);
const room = roomList.get(socket.room_id);
const isPresenter = await isPeerPresenter(socket.room_id, socket.id, data.peer_name, data.peer_uuid);
if (!isPresenter) return;
const moderator = data.moderator;
room.updateRoomModeratorALL(moderator);
room.broadCast(socket.id, 'updateRoomModeratorALL', moderator);
});
socket.on('fileInfo', (dataObject) => {
if (!roomList.has(socket.room_id)) return;
@@ -886,9 +920,10 @@ function startServer() {
const data = checkXSS(dataObject);
log.debug('Video off data', data.peer_name);
const room = roomList.get(socket.room_id);
log.debug('Video off', getPeerName(room));
room.broadCast(socket.id, 'setVideoOff', data);
});
@@ -930,7 +965,7 @@ function startServer() {
const isPeerValid = isAuthPeer(peer_username, peer_password);
log.debug('[' + socket.id + '] JOIN ROOM - HOST PROTECTED - USER AUTH check peer', {
log.debug('[Join] - HOST PROTECTED - USER AUTH check peer', {
ip: peer_ip,
peer_username: peer_username,
peer_password: peer_password,
@@ -953,8 +988,10 @@ function startServer() {
if (!(socket.room_id in presenters)) presenters[socket.room_id] = {};
const peer_name = room.getPeers()?.get(socket.id)?.peer_info?.peer_name;
const peer_uuid = room.getPeers()?.get(socket.id)?.peer_info?.peer_uuid;
const peer = room.getPeers()?.get(socket.id)?.peer_info;
const peer_id = peer.peer_id;
const peer_name = peer.peer_name;
const peer_uuid = peer.peer_uuid;
// Set the presenters
const presenter = {
@@ -995,8 +1032,8 @@ function startServer() {
'The user is currently waiting to join the room because the lobby is enabled, and they are not a presenter',
);
room.broadCast(socket.id, 'roomLobby', {
peer_id: data.peer_info.peer_id,
peer_name: data.peer_info.peer_name,
peer_id: peer_id,
peer_name: peer_name,
lobby_status: 'waiting',
});
return cb('isLobby');
@@ -1235,8 +1272,10 @@ function startServer() {
const room = roomList.get(socket.room_id);
const peerName = room.getPeers()?.get(socket.id)?.peer_info?.peer_name || '';
const peerUuid = room.getPeers()?.get(socket.id)?.peer_info?.peer_uuid || '';
const peer = room.getPeers()?.get(socket.id)?.peer_info;
const peerName = peer.peer_name || '';
const peerUuid = peer.peer_uuid || '';
const isPresenter = await isPeerPresenter(socket.room_id, socket.id, peerName, peerUuid);
@@ -1245,12 +1284,7 @@ function startServer() {
room.removePeer(socket.id);
if (room.getPeers().size === 0) {
if (room.isLocked()) {
room.setLocked(false);
}
if (room.isLobbyEnabled()) {
room.setLobbyEnabled(false);
}
//
roomList.delete(socket.room_id);
const activeRooms = getActiveRooms();
@@ -1275,8 +1309,11 @@ function startServer() {
const room = roomList.get(socket.room_id);
const peerName = room.getPeers()?.get(socket.id)?.peer_info?.peer_name || '';
const peerUuid = room.getPeers()?.get(socket.id)?.peer_info?.peer_uuid || '';
const peer = room.getPeers()?.get(socket.id)?.peer_info;
const peerName = peer.peer_name || '';
const peerUuid = peer.peer_uuid || '';
const isPresenter = await isPeerPresenter(socket.room_id, socket.id, peerName, peerUuid);
log.debug('Exit room', peerName);
@@ -1287,6 +1324,7 @@ function startServer() {
room.broadCast(socket.id, 'removeMe', removeMeData(room, peerName, isPresenter));
if (room.getPeers().size === 0) {
//
roomList.delete(socket.room_id);
delete presenters[socket.room_id];

عرض الملف

@@ -62,7 +62,7 @@ module.exports = {
Additional layers can be added to specify valid presenters and co-presenters by setting designated usernames.
*/
'Miroslav Pejic',
'MiroTalk Admin',
'MiroTalk SFU',
],
console: {
debug: true,

عرض الملف

@@ -1,6 +1,6 @@
{
"name": "mirotalksfu",
"version": "1.2.8",
"version": "1.2.9",
"description": "WebRTC SFU browser-based video calls",
"main": "Server.js",
"scripts": {
@@ -34,8 +34,8 @@
"author": "Miroslav Pejic",
"license": "AGPL-3.0",
"dependencies": {
"@sentry/integrations": "7.81.1",
"@sentry/node": "7.81.1",
"@sentry/integrations": "7.83.0",
"@sentry/node": "7.83.0",
"axios": "^1.6.2",
"body-parser": "1.20.2",
"colors": "1.4.0",
@@ -44,10 +44,10 @@
"crypto-js": "4.2.0",
"express": "4.18.2",
"httpolyglot": "0.1.2",
"mediasoup": "3.13.5",
"mediasoup": "3.13.6",
"mediasoup-client": "3.7.0",
"ngrok": "^4.3.3",
"openai": "^4.20.0",
"openai": "^4.20.1",
"qs": "6.11.2",
"socket.io": "4.7.2",
"swagger-ui-express": "5.0.0",

عرض الملف

@@ -252,7 +252,7 @@
.chat .chat-history .other-message {
background: var(--left-msg-bg);
text-align: right;
text-align: left;
}
.chat .chat-history .other-message:after {

عرض الملف

@@ -35,6 +35,7 @@ class LocalStorage {
mic_volume: 100, // %
video_fps: 0, // default 1280x768 30fps
screen_fps: 0, // max 30fps
broadcasting: false, // default false (one to many a/v streaming)
lobby: false, // default false
pitch_bar: true, // volume indicator
sounds: true, // room notify sounds

عرض الملف

@@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.2.8
* @version 1.2.9
*
*/
@@ -34,6 +34,8 @@ let redirect = {
};
const _PEER = {
presenter: '<i class="fa-solid fa-user-shield"></i>',
guest: '<i class="fa-solid fa-signal"></i>',
audioOn: '<i class="fas fa-microphone"></i>',
audioOff: '<i style="color: red;" class="fas fa-microphone-slash"></i>',
videoOn: '<i class="fas fa-video"></i>',
@@ -99,6 +101,7 @@ let isPushToTalkActive = false;
let isSpaceDown = false;
let isPitchBarEnabled = true;
let isSoundEnabled = true;
let isBroadcastingEnabled = false;
let isLobbyEnabled = false;
let isLobbyOpen = false;
let hostOnlyRecording = false;
@@ -164,6 +167,11 @@ function initClient() {
);
setTippy('lobbyAcceptAllBtn', 'Accept', 'top');
setTippy('lobbyRejectAllBtn', 'Reject', 'top');
setTippy(
'switchBroadcasting',
'Broadcasting is the dissemination of audio or video content to a large audience (one to many)',
'right',
);
setTippy(
'switchLobby',
'Lobby mode lets you protect your meeting by only allowing people to enter after a formal approval by a moderator',
@@ -252,7 +260,7 @@ function refreshMainButtonsToolTipPlacement() {
setTippy('stopRecButton', 'Stop recording', placement);
setTippy('raiseHandButton', 'Raise your hand', placement);
setTippy('lowerHandButton', 'Lower your hand', placement);
setTippy('roomEmojiPicker', 'Toggle emoji reaction', placement);
setTippy('emojiRoomButton', 'Toggle emoji reaction', placement);
setTippy('swapCameraButton', 'Swap the camera', placement);
setTippy('chatButton', 'Toggle the chat', placement);
setTippy('transcriptionButton', 'Toggle transcription', placement);
@@ -345,7 +353,7 @@ async function initEnumerateVideoDevices() {
}
function enumerateVideoDevices(stream) {
console.log('03 ----> Get Video Devices');
console.log('02 ----> Get Video Devices');
navigator.mediaDevices
.enumerateDevices()
.then((devices) =>
@@ -383,7 +391,7 @@ async function initEnumerateAudioDevices() {
}
function enumerateAudioDevices(stream) {
console.log('02 ----> Get Audio Devices');
console.log('03 ----> Get Audio Devices');
navigator.mediaDevices
.enumerateDevices()
.then((devices) =>
@@ -673,7 +681,7 @@ function getPeerInfo() {
// ####################################################
function whoAreYou() {
console.log('04 ----> Who are you');
console.log('04 ----> Who are you?');
hide(loadingDiv);
document.body.style.background = 'var(--body-bg)';
@@ -1001,7 +1009,7 @@ function roomIsReady() {
}
BUTTONS.main.chatButton && show(chatButton);
BUTTONS.main.raiseHandButton && show(raiseHandButton);
BUTTONS.main.emojiRoomButton && show(roomEmojiPicker);
BUTTONS.main.emojiRoomButton && show(emojiRoomButton);
!BUTTONS.chat.chatSaveButton && hide(chatSaveButton);
BUTTONS.chat.chatEmojiButton && show(chatEmojiButton);
BUTTONS.chat.chatMarkdownButton && show(chatMarkdownButton);
@@ -1058,6 +1066,7 @@ function roomIsReady() {
isVideoAllowed ? show(stopVideoButton) : BUTTONS.main.startVideoButton && show(startVideoButton);
show(fileShareButton);
BUTTONS.settings.lockRoomButton && show(lockRoomButton);
BUTTONS.settings.broadcastingButton && show(broadcastingButton);
BUTTONS.settings.lobbyButton && show(lobbyButton);
BUTTONS.settings.host_only_recording && show(roomRecording);
BUTTONS.main.aboutButton && show(aboutButton);
@@ -1513,7 +1522,7 @@ function handleSelectsInit() {
function setSelectsInit() {
const localStorageDevices = lS.getLocalStorageDevices();
console.log('04 ----> Get Local Storage Devices before', localStorageDevices);
console.log('04.0 ----> Get Local Storage Devices before', localStorageDevices);
if (localStorageDevices) {
initMicrophoneSelect.selectedIndex = localStorageDevices.audio.index;
initSpeakerSelect.selectedIndex = localStorageDevices.speaker.index;
@@ -1703,6 +1712,13 @@ function handleSelects() {
}
});
// room
switchBroadcasting.onchange = (e) => {
isBroadcastingEnabled = e.currentTarget.checked;
rc.roomAction('broadcasting');
lsSettings.broadcasting = isBroadcastingEnabled;
lS.setSettings(lsSettings);
e.target.blur();
};
switchLobby.onchange = (e) => {
isLobbyEnabled = e.currentTarget.checked;
rc.roomAction(isLobbyEnabled ? 'lobbyOn' : 'lobbyOff');
@@ -1951,10 +1967,16 @@ function handleInputs() {
':N': '🥶',
':J': '🥴',
};
for (let i in chatInputEmoji) {
let regex = new RegExp(i.replace(/([()[{*+.$^\\|?])/g, '\\$1'), 'gim');
this.value = this.value.replace(regex, chatInputEmoji[i]);
}
// Create a regular expression pattern for all keys in chatInputEmoji
const regexPattern = new RegExp(
Object.keys(chatInputEmoji)
.map((key) => key.replace(/([()[{*+.$^\\|?])/g, '\\$1'))
.join('|'),
'gim',
);
// Replace matching patterns with corresponding emojis
this.value = this.value.replace(regexPattern, (match) => chatInputEmoji[match]);
rc.checkLineBreaks();
};
@@ -1992,7 +2014,7 @@ function handleRoomEmojiPicker() {
emojiPickerContainer.appendChild(emojiRoomPicker);
emojiPickerContainer.style.display = 'none';
roomEmojiPicker.onclick = () => {
emojiRoomButton.onclick = () => {
toggleEmojiPicker();
};
closeEmojiPickerContainer.onclick = () => {
@@ -2016,10 +2038,10 @@ function handleRoomEmojiPicker() {
function toggleEmojiPicker() {
if (emojiPickerContainer.style.display === 'block') {
emojiPickerContainer.style.display = 'none';
setColor(roomEmojiPicker, 'white');
setColor(emojiRoomButton, 'white');
} else {
emojiPickerContainer.style.display = 'block';
setColor(roomEmojiPicker, 'yellow');
setColor(emojiRoomButton, 'yellow');
}
}
}
@@ -2968,6 +2990,7 @@ async function getRoomParticipants() {
participantsList.innerHTML = lists;
refreshParticipantsCount(participantsCount, false);
setParticipantsTippy(peers);
console.log('*** Refresh Chat participant lists ***');
}
async function getParticipantsList(peers) {
@@ -3045,6 +3068,7 @@ async function getParticipantsList(peers) {
for (const peer of Array.from(peers.keys())) {
const peer_info = peers.get(peer).peer_info;
const peer_name = peer_info.peer_name;
//const peer_presenter = peer_info.peer_presenter ? _PEER.presenter : _PEER.guest;
const peer_audio = peer_info.peer_audio ? _PEER.audioOn : _PEER.audioOff;
const peer_video = peer_info.peer_video ? _PEER.videoOn : _PEER.videoOff;
const peer_screen = peer_info.peer_screen ? _PEER.screenOn : _PEER.screenOff;
@@ -3100,6 +3124,9 @@ async function getParticipantsList(peers) {
<button class="ml5" id='${peer_id}___pScreen' onclick="rc.peerAction('me',this.id,'stop')">${peer_screen}</button>
`;
// li += `
// <button class="ml5" >${peer_presenter}</button>`;
if (peer_info.peer_hand) {
li += `
<button class="ml5" >${peer_hand}</button>`;
@@ -3127,7 +3154,11 @@ async function getParticipantsList(peers) {
<div class="name">${peer_name}</div>
<div class="status"> <i class="fa fa-circle online"></i> online <i id="${peer_id}-unread-msg" class="fas fa-comments hidden"></i> </div>
</div>
`;
// NO ROOM BROADCASTING
if (!isBroadcastingEnabled) {
li += `
<div style="class="dropdown">
<button
class="dropdown-toggle"
@@ -3143,7 +3174,10 @@ async function getParticipantsList(peers) {
<li><button class="btn-sm ml5" id="${peer_id}___sendVideoTo" onclick="rc.shareVideo('${peer_id}');">${_PEER.sendVideo} Share Audio/Video</button></li>
</ul>
</div>
`;
}
li += `
<br/>
<div class="about-buttons mt5">
@@ -3151,10 +3185,15 @@ async function getParticipantsList(peers) {
<button class="ml5" id='${peer_id}___pVideo'>${peer_video}</button>
<button class="ml5" id='${peer_id}___pScreen'>${peer_screen}</button>
`;
// li += `
// <button class="ml5" >${peer_presenter}</button>`;
if (peer_info.peer_hand) {
li += `
<button class="ml5" >${peer_hand}</button>`;
}
li += `
</div>
</li>
@@ -3175,9 +3214,14 @@ function setParticipantsTippy(peers) {
for (let peer of Array.from(peers.keys())) {
const peer_info = peers.get(peer).peer_info;
const peer_id = peer_info.peer_id;
setTippy(peer_id + '___pAudio', 'Mute', 'top');
setTippy(peer_id + '___pVideo', 'Hide', 'top');
setTippy(peer_id + '___pScreen', 'Stop', 'top');
const peerAudioBtn = rc.getId(peer_id + '___pAudio');
const peerVideoBtn = rc.getId(peer_id + '___pVideo');
const peerScreenBtn = rc.getId(peer_id + '___pScreen');
if (peerAudioBtn) setTippy(peerAudioBtn.id, 'Mute', 'top');
if (peerVideoBtn) setTippy(peerVideoBtn.id, 'Hide', 'top');
if (peerScreenBtn) setTippy(peerScreenBtn.id, 'Stop', 'top');
}
}
}

عرض الملف

@@ -9,7 +9,7 @@
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.2.8
* @version 1.2.9
*
*/
@@ -42,6 +42,7 @@ const html = {
};
const icons = {
room: '<i class="fas fa-home"></i>',
chat: '<i class="fas fa-comments"></i>',
user: '<i class="fas fa-user"></i>',
transcript: '<i class="fas fa-closed-captioning"></i>',
@@ -358,7 +359,11 @@ class RoomClient {
this.device = await this.loadDevice(data);
console.log('07.3 ----> Get Router Rtp Capabilities codecs: ', this.device.rtpCapabilities.codecs);
await this.initTransports(this.device);
await this.startLocalMedia();
if (isBroadcastingEnabled) {
isPresenter ? await this.startLocalMedia() : await this.handleRoomBroadcasting();
} else {
await this.startLocalMedia();
}
this.socket.emit('getProducers');
}
@@ -369,13 +374,19 @@ class RoomClient {
redirect = room.redirect;
let peers = new Map(JSON.parse(room.peers));
participantsCount = peers.size;
// ME
for (let peer of Array.from(peers.keys()).filter((id) => id == this.peer_id)) {
let my_peer_info = peers.get(peer).peer_info;
console.log('07.1 ----> My Peer info', my_peer_info);
isPresenter = window.localStorage.isReconnected === 'true' ? isPresenter : my_peer_info.peer_presenter;
this.peer_info.peer_presenter = isPresenter;
this.getId('isUserPresenter').innerText = isPresenter;
window.localStorage.isReconnected = false;
handleRules(isPresenter);
// ###################################################################################################
isBroadcastingEnabled = isPresenter && !room.broadcasting ? isBroadcastingEnabled : room.broadcasting;
console.log('07.1 ----> ROOM BROADCASTING', isBroadcastingEnabled);
// ###################################################################################################
room.config.hostOnlyRecording
? (console.log('07.1 ----> WARNING Room Host only recording enabled'),
this.event(_EVENTS.hostOnlyRecordingOn))
@@ -404,13 +415,17 @@ class RoomClient {
this._moderator.video_cant_unhide ? hide(tabVideoDevicesBtn) : show(tabVideoDevicesBtn);
}
}
adaptAspectRatio(participantsCount);
// PARTICIPANTS
for (let peer of Array.from(peers.keys()).filter((id) => id !== this.peer_id)) {
let peer_info = peers.get(peer).peer_info;
// console.log('07.1 ----> Remote Peer info', peer_info);
if (!peer_info.peer_video) {
const canSetVideoOff = !isBroadcastingEnabled || (isBroadcastingEnabled && peer_info.peer_presenter);
if (!peer_info.peer_video && canSetVideoOff) {
console.log('Detected peer video off ' + peer_info.peer_name);
await this.setVideoOff(peer_info, true);
}
if (peer_info.peer_recording) {
this.handleRecordingAction({
peer_id: peer_info.id,
@@ -419,8 +434,11 @@ class RoomClient {
});
}
}
this.refreshParticipantsCount();
console.log('07.2 Participants Count ---->', participantsCount);
// notify && participantsCount == 1 ? shareRoom() : sound('joined');
if (notify && participantsCount == 1) {
shareRoom();
@@ -605,7 +623,7 @@ class RoomClient {
this.socket.on(
'consumerClosed',
function ({ consumer_id, consumer_kind }) {
console.log('Closing consumer', { consumer_id: consumer_id, consumer_kind: consumer_kind });
console.log('SocketOn Closing consumer', { consumer_id: consumer_id, consumer_kind: consumer_kind });
this.removeConsumer(consumer_id, consumer_kind);
}.bind(this),
);
@@ -613,19 +631,24 @@ class RoomClient {
this.socket.on(
'setVideoOff',
function (data) {
console.log('Video off:', data);
this.setVideoOff(data, true);
if (!isBroadcastingEnabled || (isBroadcastingEnabled && data.peer_presenter)) {
console.log('SocketOn setVideoOff', {
peer_name: data.peer_name,
peer_presenter: data.peer_presenter,
});
this.setVideoOff(data, true);
}
}.bind(this),
);
this.socket.on(
'removeMe',
function (data) {
console.log('Remove me:', data);
console.log('SocketOn Remove me:', data);
this.removeVideoOff(data.peer_id);
this.lobbyRemoveMe(data.peer_id);
participantsCount = data.peer_counts;
adaptAspectRatio(participantsCount);
if (!isBroadcastingEnabled) adaptAspectRatio(participantsCount);
if (isParticipantsListOpen) getRoomParticipants();
}.bind(this),
);
@@ -633,9 +656,14 @@ class RoomClient {
this.socket.on(
'refreshParticipantsCount',
function (data) {
console.log('Participants Count:', data);
console.log('SocketOn Participants Count:', data);
participantsCount = data.peer_counts;
adaptAspectRatio(participantsCount);
if (isBroadcastingEnabled) {
if (isParticipantsListOpen) getRoomParticipants();
wbUpdate();
} else {
adaptAspectRatio(participantsCount);
}
}.bind(this),
);
@@ -643,7 +671,7 @@ class RoomClient {
'newProducers',
async function (data) {
if (data.length > 0) {
console.log('New producers', data);
console.log('SocketOn New producers', data);
for (let { producer_id, peer_name, peer_info, type } of data) {
await this.consume(producer_id, peer_name, peer_info, type);
}
@@ -654,7 +682,7 @@ class RoomClient {
this.socket.on(
'message',
function (data) {
console.log('New message:', data);
console.log('SocketOn New message:', data);
this.showMessage(data);
}.bind(this),
);
@@ -662,7 +690,7 @@ class RoomClient {
this.socket.on(
'roomAction',
function (data) {
console.log('Room action:', data);
console.log('SocketOn Room action:', data);
this.roomAction(data, false);
}.bind(this),
);
@@ -670,7 +698,7 @@ class RoomClient {
this.socket.on(
'roomPassword',
function (data) {
console.log('Room password:', data.password);
console.log('SocketOn Room password:', data.password);
this.roomPassword(data);
}.bind(this),
);
@@ -678,7 +706,7 @@ class RoomClient {
this.socket.on(
'roomLobby',
function (data) {
console.log('Room lobby:', data);
console.log('SocketOn Room lobby:', data);
this.roomLobby(data);
}.bind(this),
);
@@ -686,7 +714,7 @@ class RoomClient {
this.socket.on(
'cmd',
function (data) {
console.log('Peer cmd:', data);
console.log('SocketOn Peer cmd:', data);
this.handleCmd(data);
}.bind(this),
);
@@ -694,7 +722,7 @@ class RoomClient {
this.socket.on(
'peerAction',
function (data) {
console.log('Peer action:', data);
console.log('SocketOn Peer action:', data);
this.peerAction(data.from_peer_name, data.peer_id, data.action, false, data.broadcast);
}.bind(this),
);
@@ -702,15 +730,15 @@ class RoomClient {
this.socket.on(
'updatePeerInfo',
function (data) {
console.log('Peer info update:', data);
this.updatePeerInfo(data.peer_name, data.peer_id, data.type, data.status, false);
console.log('SocketOn Peer info update:', data);
this.updatePeerInfo(data.peer_name, data.peer_id, data.type, data.status, false, data.peer_presenter);
}.bind(this),
);
this.socket.on(
'fileInfo',
function (data) {
console.log('File info:', data);
console.log('SocketOn File info:', data);
this.handleFileInfo(data);
}.bind(this),
);
@@ -739,7 +767,7 @@ class RoomClient {
this.socket.on(
'wbCanvasToJson',
function (data) {
console.log('Received whiteboard canvas JSON');
console.log('SocketOn Received whiteboard canvas JSON');
JsonToWbCanvas(data);
}.bind(this),
);
@@ -762,15 +790,23 @@ class RoomClient {
this.socket.on(
'updateRoomModerator',
function (data) {
console.log('Update room moderator', data);
console.log('SocketOn Update room moderator', data);
this.handleUpdateRoomModerator(data);
}.bind(this),
);
this.socket.on(
'updateRoomModeratorALL',
function (data) {
console.log('SocketOn Update room moderator ALL', data);
this.handleUpdateRoomModeratorALL(data);
}.bind(this),
);
this.socket.on(
'recordingAction',
function (data) {
console.log('Recording action:', data);
console.log('SocketOn Recording action:', data);
this.handleRecordingAction(data);
}.bind(this),
);
@@ -778,7 +814,7 @@ class RoomClient {
this.socket.on(
'connect',
function () {
console.log('Connected to signaling server!');
console.log('SocketOn Connected to signaling server!');
this._isConnected = true;
// location.reload();
getPeerName() ? location.reload() : openURL(this.getReconnectDirectJoinURL());
@@ -849,6 +885,34 @@ class RoomClient {
});
}
// ####################################################
// HANDLE ROOM BROADCASTING
// ####################################################
async handleRoomBroadcasting() {
console.log('07.4 ----> Room Broadcasting is currently active, and you are not the designated presenter');
this.peer_info.peer_audio = false;
this.peer_info.peer_video = false;
this.peer_info.peer_screen = false;
const mediaTypes = ['audio', 'video', 'screen'];
mediaTypes.forEach((type) => {
const data = {
peer_name: this.peer_name,
peer_id: this.peer_id,
peer_presenter: isPresenter,
type: type,
status: false,
broadcast: true,
};
this.socket.emit('updatePeerInfo', data);
});
handleRulesBroadcasting();
}
// ####################################################
// START LOCAL AUDIO VIDEO MEDIA
// ####################################################
@@ -1077,7 +1141,7 @@ class RoomClient {
this.event(_EVENTS.startScreen);
break;
default:
return;
break;
}
this.sound('joined');
} catch (err) {
@@ -1682,7 +1746,7 @@ class RoomClient {
this.event(_EVENTS.stopScreen);
break;
default:
return;
break;
}
this.sound('left');
@@ -1749,7 +1813,7 @@ class RoomClient {
wbUpdate();
this.getConsumeStream(producer_id, peer_info.peer_id, type).then(
function ({ consumer, stream, kind }) {
async function ({ consumer, stream, kind }) {
console.log('CONSUMER MEDIA TYPE ----> ' + type);
console.log('CONSUMER', consumer);
@@ -1814,12 +1878,12 @@ class RoomClient {
let remotePeerId = peer_info.peer_id;
let remoteIsScreen = type == mediaType.screen;
let remotePeerAudio = peer_info.peer_audio;
let remotePrivacyOn = peer_info.peer_video_privacy;
switch (type) {
case mediaType.video:
case mediaType.screen:
let remotePeerAudio = peer_info.peer_audio;
this.removeVideoOff(remotePeerId);
d = document.createElement('div');
d.className = 'Camera';
@@ -1939,6 +2003,7 @@ class RoomClient {
this.setTippy(pv.id, '🔊 Volume', 'bottom');
this.setTippy(ko.id, 'Eject', 'bottom');
}
this.setPeerAudio(remotePeerId, remotePeerAudio);
break;
case mediaType.audio:
elem = document.createElement('audio');
@@ -1952,6 +2017,7 @@ class RoomClient {
let inputPv = this.getId(audioConsumerId);
if (inputPv) {
this.handlePV(id + '___' + audioConsumerId);
this.setPeerAudio(remotePeerId, remotePeerAudio);
}
console.log('[Add audioConsumers]', this.audioConsumers);
break;
@@ -2016,6 +2082,7 @@ class RoomClient {
// ####################################################
async setVideoOff(peer_info, remotePeer = false) {
//console.log('setVideoOff', peer_info);
let d, vb, i, h, au, sf, sm, sv, ko, p, pm, pb, pv;
let peer_id = peer_info.peer_id;
let peer_name = peer_info.peer_name;
@@ -2104,6 +2171,8 @@ class RoomClient {
this.setTippy(pv.id, '🔊 Volume', 'bottom');
this.setTippy(ko.id, 'Eject', 'bottom');
}
remotePeer ? this.setPeerAudio(peer_id, peer_audio) : this.setIsAudio(peer_id, peer_audio);
console.log('[setVideoOff] Video-element-count', this.videoMediaContainer.childElementCount);
//
wbUpdate();
@@ -2315,25 +2384,44 @@ class RoomClient {
return 'data:image/svg+xml,' + svg.replace(/#/g, '%23').replace(/"/g, "'").replace(/&/g, '&amp;');
}
setPeerAudio(peer_id, status) {
if (!isBroadcastingEnabled || (isBroadcastingEnabled && isPresenter)) {
console.log('Set peer audio enabled: ' + status);
const audioStatus = this.getPeerAudioBtn(peer_id); // producer, consumers
const audioVolume = this.getPeerAudioVolumeBtn(peer_id); // consumers
if (audioStatus) audioStatus.className = status ? html.audioOn : html.audioOff;
if (audioVolume) status ? show(audioVolume) : hide(audioVolume);
}
}
setIsAudio(peer_id, status) {
this.peer_info.peer_audio = status;
let b = this.getPeerAudioBtn(peer_id);
if (b) b.className = this.peer_info.peer_audio ? html.audioOn : html.audioOff;
if (!isBroadcastingEnabled || (isBroadcastingEnabled && isPresenter)) {
console.log('Set audio enabled: ' + status);
this.peer_info.peer_audio = status;
const audioStatus = this.getPeerAudioBtn(peer_id); // producer, consumers
if (audioStatus) audioStatus.className = status ? html.audioOn : html.audioOff;
}
}
setIsVideo(status) {
this.peer_info.peer_video = status;
if (!this.peer_info.peer_video) {
this.setVideoOff(this.peer_info, false);
this.sendVideoOff();
if (!isBroadcastingEnabled || (isBroadcastingEnabled && isPresenter)) {
this.peer_info.peer_video = status;
if (!this.peer_info.peer_video) {
console.log('Set video enabled: ' + status);
this.setVideoOff(this.peer_info, false);
this.sendVideoOff();
}
}
}
setIsScreen(status) {
this.peer_info.peer_screen = status;
if (!this.peer_info.peer_screen && !this.peer_info.peer_video) {
this.setVideoOff(this.peer_info, false);
this.sendVideoOff();
if (!isBroadcastingEnabled || (isBroadcastingEnabled && isPresenter)) {
this.peer_info.peer_screen = status;
if (!this.peer_info.peer_screen && !this.peer_info.peer_video) {
console.log('Set screen enabled: ' + status);
this.setVideoOff(this.peer_info, false);
this.sendVideoOff();
}
}
}
@@ -2394,6 +2482,10 @@ class RoomClient {
return this.getId(peer_id + '__audio');
}
getPeerAudioVolumeBtn(peer_id) {
return this.getId(peer_id + '___pVolume');
}
getPeerHandBtn(peer_id) {
return this.getId(peer_id + '__hand');
}
@@ -4462,7 +4554,8 @@ class RoomClient {
// ####################################################
roomAction(action, emit = true, popup = true) {
let data = {
const data = {
room_broadcasting: isBroadcastingEnabled,
room_id: this.room_id,
peer_id: this.peer_id,
peer_name: this.peer_name,
@@ -4472,6 +4565,10 @@ class RoomClient {
};
if (emit) {
switch (action) {
case 'broadcasting':
this.socket.emit('roomAction', data);
if (popup) this.roomStatus(action);
break;
case 'lock':
if (room_password) {
this.socket
@@ -4481,10 +4578,11 @@ class RoomClient {
// Only the presenter can lock the room
if (isPresenter || res.peerCounts == 1) {
isPresenter = true;
this.peer_info.peer_presenter = isPresenter;
this.getId('isUserPresenter').innerText = isPresenter;
data.password = room_password;
this.socket.emit('roomAction', data);
this.roomStatus(action);
if (popup) this.roomStatus(action);
}
}.bind(this),
)
@@ -4519,7 +4617,7 @@ class RoomClient {
break;
case 'unlock':
this.socket.emit('roomAction', data);
this.roomStatus(action);
if (popup) this.roomStatus(action);
break;
case 'lobbyOn':
this.socket.emit('roomAction', data);
@@ -4547,6 +4645,9 @@ class RoomClient {
roomStatus(action) {
switch (action) {
case 'broadcasting':
this.userLog('info', `${icons.room} BROADCASTING ${isBroadcastingEnabled ? 'On' : 'Off'}`, 'top-end');
break;
case 'lock':
this.sound('locked');
this.event(_EVENTS.roomLock);
@@ -4666,7 +4767,7 @@ class RoomClient {
// ROOM LOBBY
// ####################################################
roomLobby(data) {
async roomLobby(data) {
console.log('LOBBY--->', data);
switch (data.lobby_status) {
case 'waiting':
@@ -4702,7 +4803,7 @@ class RoomClient {
}
break;
case 'accept':
this.joinAllowed(data.room);
await this.joinAllowed(data.room);
control.style.display = 'flex';
this.msgPopup('info', 'Your join meeting was be accepted by moderator');
break;
@@ -5464,10 +5565,26 @@ class RoomClient {
updateRoomModerator(data) {
if (!isRulesActive || isPresenter) {
this.socket.emit('updateRoomModerator', data);
const moderator = this.getModeratorData(data);
this.socket.emit('updateRoomModerator', moderator);
}
}
updateRoomModeratorALL(data) {
if (!isRulesActive || isPresenter) {
const moderator = this.getModeratorData(data);
this.socket.emit('updateRoomModeratorALL', moderator);
}
}
getModeratorData(data) {
return {
peer_name: this.peer_name,
peer_uuid: this.peer_uuid,
moderator: data,
};
}
handleUpdateRoomModerator(data) {
switch (data.type) {
case 'audio_cant_unmute':
@@ -5488,6 +5605,11 @@ class RoomClient {
}
}
handleUpdateRoomModeratorALL(data) {
this._moderator = data;
console.log('Update Room Moderator data all', this._moderator);
}
getModerator() {
console.log('Get Moderator', this._moderator);
return this._moderator;
@@ -5497,7 +5619,7 @@ class RoomClient {
// UPDATE PEER INFO
// ####################################################
updatePeerInfo(peer_name, peer_id, type, status, emit = true) {
updatePeerInfo(peer_name, peer_id, type, status, emit = true, presenter = false) {
if (emit) {
switch (type) {
case 'audio':
@@ -5524,23 +5646,23 @@ class RoomClient {
default:
break;
}
let data = {
const data = {
peer_name: peer_name,
peer_id: peer_id,
type: type,
status: status,
broadcast: true,
};
this.socket.emit('updatePeerInfo', data);
} else {
const canUpdateMediaStatus = !isBroadcastingEnabled || (isBroadcastingEnabled && presenter);
switch (type) {
case 'audio':
this.setIsAudio(peer_id, status);
if (canUpdateMediaStatus) this.setPeerAudio(peer_id, status);
break;
case 'video':
this.setIsVideo(status);
break;
case 'screen':
this.setIsScreen(status);
break;
case 'hand':
let peer_hand = this.getPeerHandBtn(peer_id);

عرض الملف

@@ -28,6 +28,7 @@ const BUTTONS = {
settings: {
lockRoomButton: true, // presenter
unlockRoomButton: true, // presenter
broadcastingButton: true, // presenter
lobbyButton: true, // presenter
micOptionsButton: true, // presenter
tabModerator: true, // presenter
@@ -80,7 +81,7 @@ const BUTTONS = {
};
function handleRules(isPresenter) {
console.log('06.1 ----> IsPresenter: ' + isPresenter);
console.log('07.1 ----> IsPresenter: ' + isPresenter);
if (!isRulesActive) return;
if (!isPresenter) {
// ##################################
@@ -89,6 +90,7 @@ function handleRules(isPresenter) {
BUTTONS.participantsList.saveInfoButton = false;
BUTTONS.settings.lockRoomButton = false;
BUTTONS.settings.unlockRoomButton = false;
BUTTONS.settings.broadcastingButton = false;
BUTTONS.settings.lobbyButton = false;
BUTTONS.settings.micOptionsButton = false;
BUTTONS.settings.tabModerator = false;
@@ -106,6 +108,7 @@ function handleRules(isPresenter) {
BUTTONS.participantsList.saveInfoButton = true;
BUTTONS.settings.lockRoomButton = !isRoomLocked;
BUTTONS.settings.unlockRoomButton = isRoomLocked;
BUTTONS.settings.broadcastingButton = true;
BUTTONS.settings.lobbyButton = true;
BUTTONS.settings.micOptionsButton = true;
BUTTONS.settings.tabModerator = true;
@@ -121,6 +124,10 @@ function handleRules(isPresenter) {
// Auto detected rules for presenter
// ##################################
// Room broadcasting
isBroadcastingEnabled = lsSettings.broadcasting;
switchBroadcasting.checked = isBroadcastingEnabled;
rc.roomAction('broadcasting', true, false);
// Room lobby
isLobbyEnabled = lsSettings.lobby;
switchLobby.checked = isLobbyEnabled;
@@ -135,15 +142,20 @@ function handleRules(isPresenter) {
switchEveryoneCantUnmute.checked = lsSettings.moderator_audio_cant_unmute;
switchEveryoneCantUnhide.checked = lsSettings.moderator_video_cant_unhide;
switchEveryoneCantShareScreen.checked = lsSettings.moderator_screen_cant_share;
rc.updateRoomModerator({ type: 'audio_start_muted', status: switchEveryoneMute.checked });
rc.updateRoomModerator({ type: 'video_start_hidden', status: switchEveryoneHidden.checked });
rc.updateRoomModerator({ type: 'audio_cant_unmute', status: switchEveryoneCantUnmute.checked });
rc.updateRoomModerator({ type: 'video_cant_unhide', status: switchEveryoneCantUnhide.checked });
rc.updateRoomModerator({ type: 'screen_cant_share', status: switchEveryoneCantShareScreen.checked });
// Update moderator settings...
const moderatorData = {
audio_start_muted: switchEveryoneMute.checked,
video_start_hidden: switchEveryoneHidden.checked,
audio_cant_unmute: switchEveryoneCantUnmute.checked,
video_cant_unhide: switchEveryoneCantUnhide.checked,
screen_cant_share: switchEveryoneCantShareScreen.checked,
};
rc.updateRoomModeratorALL(moderatorData);
}
// main. settings...
BUTTONS.settings.lockRoomButton ? show(lockRoomButton) : hide(lockRoomButton);
BUTTONS.settings.unlockRoomButton ? show(unlockRoomButton) : hide(unlockRoomButton);
BUTTONS.settings.broadcastingButton ? show(broadcastingButton) : hide(broadcastingButton);
BUTTONS.settings.lobbyButton ? show(lobbyButton) : hide(lobbyButton);
!BUTTONS.settings.micOptionsButton && hide(micOptionsButton);
!BUTTONS.settings.tabModerator && hide(tabModeratorBtn);
@@ -153,3 +165,50 @@ function handleRules(isPresenter) {
: elemDisplay('whiteboardLockButton', false, 'flex');
//...
}
function handleRulesBroadcasting() {
console.log('07.2 ----> handleRulesBroadcasting');
BUTTONS.main.shareButton = false;
BUTTONS.main.hideMeButton = false;
BUTTONS.main.startAudioButton = false;
BUTTONS.main.startVideoButton = false;
BUTTONS.main.startScreenButton = false;
BUTTONS.main.swapCameraButton = false;
BUTTONS.main.raiseHandButton = false;
BUTTONS.main.whiteboardButton = false;
//BUTTONS.main.emojiRoomButton = false,
BUTTONS.main.transcriptionButton = false;
BUTTONS.main.settingsButton = false;
BUTTONS.participantsList.saveInfoButton = false;
BUTTONS.settings.lockRoomButton = false;
BUTTONS.settings.unlockRoomButton = false;
BUTTONS.settings.lobbyButton = false;
BUTTONS.videoOff.muteAudioButton = false;
BUTTONS.videoOff.ejectButton = false;
BUTTONS.consumerVideo.sendMessageButton = false;
BUTTONS.consumerVideo.sendFileButton = false;
BUTTONS.consumerVideo.sendVideoButton = false;
BUTTONS.consumerVideo.ejectButton = false;
BUTTONS.consumerVideo.muteAudioButton = false;
BUTTONS.consumerVideo.muteVideoButton = false;
BUTTONS.whiteboard.whiteboardLockButton = false;
//...
elemDisplay('shareButton', false);
elemDisplay('hideMeButton', false);
elemDisplay('startAudioButton', false);
elemDisplay('stopAudioButton', false);
elemDisplay('startVideoButton', false);
elemDisplay('stopVideoButton', false);
elemDisplay('startScreenButton', false);
elemDisplay('stopScreenButton', false);
elemDisplay('swapCameraButton', false);
elemDisplay('raiseHandButton', false);
elemDisplay('whiteboardButton', false);
//elemDisplay('emojiRoomButton', false);
elemDisplay('transcriptionButton', false);
elemDisplay('lockRoomButton', false);
elemDisplay('unlockRoomButton', false);
elemDisplay('lobbyButton', false);
elemDisplay('settingsButton', false);
//...
}

عرض الملف

@@ -154,7 +154,7 @@ access to use this app.
<button id="stopRecButton" style="color: red" class="hidden"><i class="fas fa-record-vinyl"></i></button>
<button id="raiseHandButton" class="hidden"><i class="fas fa-hand-paper"></i></button>
<button id="lowerHandButton" class="hidden"><i id="lowerHandIcon" class="fas fa-hand-paper"></i></button>
<button id="roomEmojiPicker" class="hidden"><i class="fas fa-face-smile"></i></button>
<button id="emojiRoomButton" class="hidden"><i class="fas fa-face-smile"></i></button>
<button id="chatButton" class="hidden"><i class="fas fa-comments"></i></button>
<button id="transcriptionButton" class="hidden"><i class="fas fa-closed-captioning"></i></button>
<button id="whiteboardButton" class="hidden"><i class="fas fa-chalkboard-teacher"></i></button>
@@ -230,6 +230,19 @@ access to use this app.
</button>
<hr style="border: 1px solid grey" />
<table class="settingsTable">
<tr id="broadcastingButton" class="hidden">
<td class="custom-width">
<div class="title">
<i class="fa-solid fa-wifi"></i>
<p>Broadcast</p>
</div>
</td>
<td>
<div class="form-check form-switch form-switch-md title">
<input id="switchBroadcasting" class="form-check-input" type="checkbox" />
</div>
</td>
</tr>
<tr id="lobbyButton" class="hidden">
<td class="custom-width">
<div class="title">