[mirotalksfu] - improve Video grid view and UI

هذا الالتزام موجود في:
Miroslav Pejic
2021-09-17 13:27:20 +02:00
الأصل 2c692fbf22
التزام 63ce1c7e4d
6 ملفات معدلة مع 394 إضافات و269 حذوفات

عرض الملف

@@ -34,6 +34,7 @@
<!-- StyleSheet --> <!-- StyleSheet -->
<link rel="stylesheet" href="/css/Room.css" /> <link rel="stylesheet" href="/css/Room.css" />
<link rel="stylesheet" href="/css/VideoGrid.css" />
<!-- https://animate.style 4 using for swal fadeIn-Out --> <!-- https://animate.style 4 using for swal fadeIn-Out -->
@@ -61,6 +62,7 @@
<script src="/modules/MediasoupClient.js"></script> <script src="/modules/MediasoupClient.js"></script>
<script src="/js/Room.js"></script> <script src="/js/Room.js"></script>
<script src="/js/RoomClient.js"></script> <script src="/js/RoomClient.js"></script>
<script src="/js/VideoGrid.js"></script>
<script src="https://kit.fontawesome.com/d2f1016e6f.js" crossorigin="anonymous"></script> <script src="https://kit.fontawesome.com/d2f1016e6f.js" crossorigin="anonymous"></script>
<script src="https://cdn.rawgit.com/muaz-khan/DetectRTC/master/DetectRTC.js"></script> <script src="https://cdn.rawgit.com/muaz-khan/DetectRTC/master/DetectRTC.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
@@ -71,107 +73,68 @@
</head> </head>
<body onload="initClient()"> <body onload="initClient()">
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div class="container-xxl">
<div id="control" class="fadein hidden"> <div id="loadingDiv" class="center pulsate">
<button id="exitButton" class="hidden"> <h1>Loading...</h1>
<i class="fas fa-arrow-left"></i> <pre>
</button> Please allow the camera or microphone
<button id="shareButton" class="hidden"> access to use this app.
<i class="fas fa-share-alt"></i> </pre>
</button> </div>
<div class="dropdown">
<button id="devicesButton" class="hidden"> <button id="openNavButton" class="hidden">&#9776; open</button>
<i class="fas fa-cogs"></i> <div id="control" class="sidenav hidden">
</button> <button id="closeNavButton" class="closebtn">&times;</button>
<div id="myDevices" class="dropdown-content fadein"> <button id="shareButton" class="hidden"><i class="fas fa-share-alt"></i> Share</button>
<div id="devicesList"> <div class="dropdown">
<br /> <button id="settingsButton" class="hidden"><i class="fas fa-cogs"></i> Settings</button>
<i class="fas fa-video"></i> Video: <div id="settings" class="dropdown-content fadein">
<select id="videoSelect" class="form-select text-light bg-dark"></select> <div id="devicesList">
<br /> <i class="fas fa-video"></i> Video
<i class="fas fa-microphone"></i> Microphone: <select id="videoSelect" class="form-select text-light bg-dark"></select>
<select id="microphoneSelect" class="form-select text-light bg-dark"></select> <br />
<br /> <i class="fas fa-microphone"></i> Microphone
<i class="fas fa-volume-up"></i> Speaker: <select id="microphoneSelect" class="form-select text-light bg-dark"></select>
<select id="speakerSelect" class="form-select text-light bg-dark"></select> <br />
</div> <i class="fas fa-volume-up"></i> Speaker
<select id="speakerSelect" class="form-select text-light bg-dark"></select>
</div> </div>
</div> </div>
<div class="dropdown"> </div>
<button id="recButton" class="hidden"> <div class="dropdown">
<i class="fas fa-record-vinyl"></i> <button id="recButton" class="hidden"><i class="fas fa-record-vinyl"></i> Recording</button>
</button> <div id="recording" class="dropdown-content fadein">
<div id="recording" class="dropdown-content fadein"> <div id="recordingCommand" class="recording">
<div id="recordingCommand" class="recording"> <button id="startRecButton" class="hidden"><i class="fas fa-record-vinyl"></i> Start</button>
<br /> <button id="stopRecButton" class="hidden"><i class="fas fa-stop-circle"></i> Stop</button>
<button id="startRecButton" class="hidden"> <button id="pauseRecButton" class="hidden"><i class="far fa-pause-circle"></i> Pause</button>
<i class="fas fa-record-vinyl"></i> <button id="resumeRecButton" class="hidden"><i class="far fa-play-circle"></i> Resume</button>
</button> <p id="recordingStatus">🔴 REC 0s</p>
<button id="stopRecButton" class="hidden">
<i class="fas fa-stop-circle"></i>
</button>
<button id="pauseRecButton" class="hidden">
<i class="far fa-pause-circle"></i>
</button>
<button id="resumeRecButton" class="hidden">
<i class="far fa-play-circle"></i>
</button>
<p id="recordingStatus">🔴 REC 0s</p>
</div>
</div> </div>
</div> </div>
<button id="chatButton" class="hidden">
<i class="fas fa-comments"></i>
</button>
<button id="fullScreenButton" class="hidden">
<i class="fas fa-expand-alt"></i>
</button>
<button id="swapCameraButton" class="hidden">
<i class="fas fa-sync-alt"></i>
</button>
<button id="startAudioButton" class="hidden">
<i class="fas fa-microphone-slash"></i>
</button>
<button id="stopAudioButton" class="hidden">
<i class="fas fa-microphone"></i>
</button>
<button id="startVideoButton" class="hidden">
<i class="fas fa-video-slash"></i>
</button>
<button id="stopVideoButton" class="hidden">
<i class="fas fa-video"></i>
</button>
<button id="startScreenButton" class="hidden">
<i class="fas fa-desktop"></i>
</button>
<button id="stopScreenButton" class="hidden">
<i class="fas fa-stop-circle"></i>
</button>
<button id="participantsButton" class="hidden">
<i class="fas fa-users"></i>
</button>
<button id="lockRoomButton" class="hidden">
<i class="fas fa-lock-open"></i>
</button>
<button id="unlockRoomButton" class="hidden">
<i class="fas fa-lock"></i>
</button>
<button id="aboutButton" class="hidden">
<i class="fas fa-question"></i>
</button>
<p id="sessionTime"></p>
</div> </div>
<button id="chatButton" class="hidden"><i class="fas fa-comments"></i> Chat</button>
<button id="fullScreenButton" class="hidden"><i class="fas fa-expand-alt"></i> Full screen</button>
<button id="swapCameraButton" class="hidden"><i class="fas fa-sync-alt"></i> Swap Cam</button>
<button id="startAudioButton" class="hidden"><i class="fas fa-microphone-slash"></i> Start audio</button>
<button id="stopAudioButton" class="hidden"><i class="fas fa-microphone"></i> Stop audio</button>
<button id="startVideoButton" class="hidden"><i class="fas fa-video-slash"></i> Start video</button>
<button id="stopVideoButton" class="hidden"><i class="fas fa-video"></i> Stop video</button>
<button id="startScreenButton" class="hidden"><i class="fas fa-desktop"></i> Start screen</button>
<button id="stopScreenButton" class="hidden"><i class="fas fa-stop-circle"></i> Stop screen</button>
<button id="participantsButton" class="hidden"><i class="fas fa-users"></i> Participants</button>
<button id="lockRoomButton" class="hidden"><i class="fas fa-lock-open"></i> Lock room</button>
<button id="unlockRoomButton" class="hidden"><i class="fas fa-lock"></i> Unlock room</button>
<button id="aboutButton" class="hidden"><i class="fas fa-question"></i> About</button>
<button id="exitButton" class="hidden"><i class="fas fa-phone-slash"></i> Leave</button>
<button id="sessionTime" class="far fa-clock"></button>
</div> </div>
<div class="container-xxl">
<div id="videoMedia" class="hidden"> <div id="videoMediaContainer">
<div id="localMedia" class="containers"> <!-- <div class="Camera"></div> -->
<!--<video id="localVideo" autoplay inline class="vid mirror"></video>-->
<!--<video id="localScreen" autoplay inline class="vid"></video>-->
</div>
<div id="remoteVideos" class="containers"></div>
<div id="remoteAudios"></div>
</div>
</div> </div>
<div id="remoteAudios"></div>
<section id="chatRoom" class="chat-room center fadein"> <section id="chatRoom" class="chat-room center fadein">
<section id="msger" class="msger"> <section id="msger" class="msger">
<header id="chatHeader" class="chat-header"> <header id="chatHeader" class="chat-header">

عرض الملف

@@ -1,3 +1,5 @@
@import url('https://fonts.googleapis.com/css?family=Comfortaa:wght@500&display=swap');
/*-------------------------------------------------------------- /*--------------------------------------------------------------
# Keyframes # Keyframes
--------------------------------------------------------------*/ --------------------------------------------------------------*/
@@ -30,11 +32,12 @@
} }
:root { :root {
--body-bg: linear-gradient(to left, #1f1e1e, #000000);
--msger-top: 50%; --msger-top: 50%;
--msger-left: 50%; --msger-left: 50%;
--msger-height: 680px; --msger-height: 680px;
--msger-width: 420px; --msger-width: 420px;
--msger-bg: linear-gradient(to left, #383838, #000000); --msger-bg: linear-gradient(to left, #1f1e1e, #000000);
--left-msg-bg: #222328; --left-msg-bg: #222328;
--right-msg-bg: #0a0b0c; --right-msg-bg: #0a0b0c;
--box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); --box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
@@ -42,7 +45,7 @@
* { * {
outline: none; outline: none;
font-family: 'Verdana'; font-family: 'Comfortaa';
} }
html { html {
@@ -50,37 +53,113 @@ html {
} }
body { body {
background-image: url('../images/background.jpg'); background: var(--body-bg);
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
} }
/*-------------------------------------------------------------- /*--------------------------------------------------------------
# Control buttons # Loading...
--------------------------------------------------------------*/ --------------------------------------------------------------*/
#loadingDiv {
color: white;
padding: 30px;
border-radius: 10px;
background: var(--body-bg);
}
#loadingDiv h1 {
font-size: 70px;
}
#loadingDiv pre {
padding: 5px;
}
/*--------------------------------------------------------------
# Buttons bar
--------------------------------------------------------------*/
#openNavButton {
z-index: 2;
position: absolute;
cursor: pointer;
padding: 10px;
font-size: 24px;
color: white;
background: rgba(0, 0, 0, 0.4);
border-radius: 10px;
}
.sidenav {
z-index: 3;
height: 100%;
width: 0;
position: fixed;
top: 0;
left: 0;
background-color: transparent;
overflow-x: hidden;
transition: 0.5s;
padding-top: 60px;
animation: show 0.4s ease;
}
.sidenav button {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 20px;
transition: 0.3s;
}
.sidenav button:hover {
color: rgb(0, 180, 50);
}
.sidenav .closebtn {
position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
.sidenav::-webkit-scrollbar {
width: 5px;
}
.sidenav::-webkit-scrollbar-track {
background: transparent;
}
.sidenav::-webkit-scrollbar-thumb {
background: rgb(255 255 255 / 40%);
}
@media screen and (max-height: 450px) {
.sidenav {
padding-top: 20px;
}
.sidenav button {
font-size: 20px;
}
}
#control { #control {
z-index: 1;
position: fixed; position: fixed;
padding: 10px; padding: 10px;
top: 0; top: 0;
width: 100%; width: 250px;
background: black; background: black;
} }
#control button { #control button {
border-radius: 5px; border-radius: 5px;
} }
#control p {
font-size: small;
cursor: default;
}
#exitButton:hover { #exitButton:hover {
color: red; color: red;
} }
#settings {
position: relative;
}
/*-------------------------------------------------------------- /*--------------------------------------------------------------
# Room QR # Room QR
--------------------------------------------------------------*/ --------------------------------------------------------------*/
@@ -91,100 +170,6 @@ body {
align-items: center; align-items: center;
} }
/*--------------------------------------------------------------
# Video grid
--------------------------------------------------------------*/
.containers {
display: grid;
grid-template-columns: repeat(2, 1fr);
column-gap: 10px;
row-gap: 10px;
border-radius: 5px;
}
@media only screen and (max-width: 720px) {
.containers {
display: grid;
grid-template-columns: 1fr;
column-gap: 10px;
row-gap: 10px;
border-radius: 5px;
}
}
.vid {
flex: 0 1 auto;
height: 360px;
border-radius: 10px;
cursor: pointer;
}
video {
width: 100%;
height: 100%;
object-fit: cover;
box-shadow: var(--box-shadow);
}
video:hover {
opacity: 0.9;
}
video:fullscreen {
object-fit: contain; /* cover; */
opacity: 1;
}
.mirror {
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
transform: rotateY(180deg);
}
#videoMedia {
margin-top: 50px;
}
#localMedia,
#remoteVideos {
margin: 10px;
cursor: default;
}
.pn {
position: absolute;
display: flex;
align-items: center;
padding: 10px;
margin: 10px;
width: auto;
height: 30px;
border-radius: 5px;
margin-top: 325px;
color: white;
background: rgba(0, 0, 0, 0.7);
}
.d,
.d video {
position: relative;
}
.d p {
position: absolute;
padding: 10px;
margin: 10px;
width: auto;
height: 30px;
border-radius: 5px;
top: 315px;
color: white;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
}
/*-------------------------------------------------------------- /*--------------------------------------------------------------
# Dropdown menù # Dropdown menù
--------------------------------------------------------------*/ --------------------------------------------------------------*/
@@ -195,21 +180,20 @@ video:fullscreen {
} }
.dropdown-content { .dropdown-content {
z-index: 2;
display: none; display: none;
position: absolute; position: absolute;
margin: auto; margin: auto;
padding: 10px; padding: 10px;
min-width: 200px; max-width: 230px;
background-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.7);
color: white; color: white;
overflow: auto; overflow: hidden;
border-radius: 5px; border-radius: 5px;
box-shadow: var(--box-shadow); box-shadow: var(--box-shadow);
} }
.dropdown-content select { .dropdown-content select {
width: auto; width: 210px;
font-size: small; font-size: small;
} }
@@ -217,15 +201,15 @@ video:fullscreen {
# Recording # Recording
--------------------------------------------------------------*/ --------------------------------------------------------------*/
.recording { #recording {
display: flex; position: relative;
} }
.recording button, #recording button,
.recording p { #recording p {
padding: 5px; padding: 5px;
margin: 1px; margin: 1px;
font-size: 0.8em; font-size: 1.2rem;
border-radius: 5px; border-radius: 5px;
} }
@@ -234,7 +218,7 @@ video:fullscreen {
--------------------------------------------------------------*/ --------------------------------------------------------------*/
.chat-room { .chat-room {
z-index: 3; z-index: 4;
display: none; display: none;
position: fixed; position: fixed;
height: var(--msger-height); height: var(--msger-height);
@@ -406,7 +390,7 @@ video:fullscreen {
.chat-msger-inputarea { .chat-msger-inputarea {
display: flex; display: flex;
padding: 10px; padding: 10px;
background: #222328; background: #1f1e1e;
} }
.chat-msger-input { .chat-msger-input {
@@ -427,14 +411,13 @@ video:fullscreen {
--------------------------------------------------------------*/ --------------------------------------------------------------*/
emoji-picker { emoji-picker {
top: 0px;
position: absolute; position: absolute;
top: 45px;
width: 100%; width: 100%;
height: 100%; height: 92%;
--background: #16171b; --background: #16171b;
--num-columns: 9; --num-columns: 8;
--emoji-size: 1.5rem; --emoji-size: 1.5rem;
overflow: hidden;
} }
/*-------------------------------------------------------------- /*--------------------------------------------------------------
@@ -506,6 +489,7 @@ emoji-picker {
} }
.center { .center {
position: fixed;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
@@ -525,7 +509,7 @@ emoji-picker {
p, p,
button { button {
background: black; background: transparent;
color: white; color: white;
border: none; border: none;
} }
@@ -619,3 +603,11 @@ button:hover {
opacity: 0.5; opacity: 0.5;
} }
} }
/*
z-index:
- 1 videoMediaContainer
- 2 buttonBar
- 3 sidenav
- 4 chat
*/

80
public/css/VideoGrid.css Normal file
عرض الملف

@@ -0,0 +1,80 @@
/*--------------------------------------------------------------
# Video grid
--------------------------------------------------------------*/
#videoMediaContainer {
z-index: 1;
display: flex;
align-content: center;
flex-wrap: wrap;
align-items: center;
justify-content: center;
vertical-align: middle;
position: absolute;
left: 0px;
bottom: 0px;
top: 0px;
right: 0px;
}
#videoMediaContainer div {
/* Camera */
position: relative;
vertical-align: middle;
align-self: center;
border-radius: 10px;
overflow: hidden;
display: inline-block;
background: transparent;
box-shadow: 0px 12px 22px rgba(0, 0, 0, 0.4);
animation: show 0.4s ease;
}
#videoMediaContainer p {
position: absolute;
bottom: 0;
color: white;
font-size: 14px;
display: flex;
align-items: center;
padding: 5px;
margin: 5px;
width: auto;
height: 25px;
border-radius: 5px;
background: rgba(0, 0, 0, 0.4);
}
video {
width: 100%;
height: 100%;
object-fit: cover;
box-shadow: var(--box-shadow);
cursor: pointer;
}
video:hover {
opacity: 0.9;
}
video:fullscreen {
object-fit: contain;
opacity: 1;
}
.mirror {
-webkit-transform: rotateY(180deg);
-moz-transform: rotateY(180deg);
transform: rotateY(180deg);
}
@keyframes show {
0% {
opacity: 0;
transform: scale(0.4) translateY(20px);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
}
}

عرض الملف

@@ -4,7 +4,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
const RoomURL = window.location.href; const RoomURL = window.location.href;
const swalBackground = 'rgba(0, 0, 0, 0.7)'; const swalBackground = 'linear-gradient(to left, #1f1e1e, #000000)';
const swalImageUrl = '../images/pricing-illustration.svg'; const swalImageUrl = '../images/pricing-illustration.svg';
const url = { const url = {
@@ -43,34 +43,14 @@ function getRandomNumber(length) {
function initClient() { function initClient() {
if (!DetectRTC.isMobileDevice) { if (!DetectRTC.isMobileDevice) {
setTippy('sessionTime', 'Session time', 'bottom'); setTippy('closeNavButton', 'Close', 'right');
setTippy('exitButton', 'Exit room', 'bottom');
setTippy('shareButton', 'Share Room', 'bottom');
setTippy('devicesButton', 'Devices', 'bottom');
setTippy('chatButton', 'Chat', 'bottom');
setTippy('chatCleanButton', 'Clean', 'bottom');
setTippy('chatSaveButton', 'Save', 'bottom');
setTippy('chatCloseButton', 'Close', 'bottom');
setTippy('chatMessage', 'Press enter to send', 'top-start'); setTippy('chatMessage', 'Press enter to send', 'top-start');
setTippy('chatSendButton', 'Send', 'top'); setTippy('chatSendButton', 'Send', 'top');
setTippy('chatEmojiButton', 'Emoji', 'top'); setTippy('chatEmojiButton', 'Emoji', 'top');
setTippy('fullScreenButton', 'Full Screen', 'bottom'); setTippy('chatCleanButton', 'Clean', 'bottom');
setTippy('recButton', 'Recording', 'bottom'); setTippy('chatSaveButton', 'Save', 'bottom');
setTippy('startRecButton', 'Start Recording', 'bottom'); setTippy('chatCloseButton', 'Close', 'bottom');
setTippy('stopRecButton', 'Stop Recording', 'bottom'); setTippy('sessionTime', 'Session time', 'right');
setTippy('pauseRecButton', 'Pause Recording', 'bottom');
setTippy('resumeRecButton', 'Resume Recording', 'bottom');
setTippy('stopAudioButton', 'Stop Audio', 'bottom');
setTippy('startAudioButton', 'Start Audio', 'bottom');
setTippy('swapCameraButton', 'Swap Camera', 'bottom');
setTippy('startVideoButton', 'Start Video', 'bottom');
setTippy('stopVideoButton', 'Stop Video', 'bottom');
setTippy('startScreenButton', 'Start Screen', 'bottom');
setTippy('stopScreenButton', 'Stop Screen', 'bottom');
setTippy('participantsButton', 'Show participants', 'bottom');
setTippy('lockRoomButton', 'Room Lock', 'bottom');
setTippy('unlockRoomButton', 'Room Unlock', 'bottom');
setTippy('aboutButton', 'About', 'bottom');
} }
initEnumerateDevices(); initEnumerateDevices();
} }
@@ -115,6 +95,7 @@ async function initEnumerateDevices() {
if (!isAudioAllowed && !isVideoAllowed) { if (!isAudioAllowed && !isVideoAllowed) {
window.location.href = `/permission?room_id=${room_id}&message=Not allowed both Audio and Video`; window.location.href = `/permission?room_id=${room_id}&message=Not allowed both Audio and Video`;
} else { } else {
hide(loadingDiv);
getPeerGeoLocation(); getPeerGeoLocation();
whoAreYou(); whoAreYou();
} }
@@ -251,11 +232,15 @@ function whoAreYou() {
function handleAudio(e) { function handleAudio(e) {
isAudioOn = isAudioOn ? false : true; isAudioOn = isAudioOn ? false : true;
e.target.className = 'fas fa-microphone' + (isAudioOn ? '' : '-slash'); e.target.className = 'fas fa-microphone' + (isAudioOn ? '' : '-slash');
setColor(e.target, isAudioOn ? 'white' : 'red');
setColor(startAudioButton, isAudioOn ? 'white' : 'red');
} }
function handleVideo(e) { function handleVideo(e) {
isVideoOn = isVideoOn ? false : true; isVideoOn = isVideoOn ? false : true;
e.target.className = 'fas fa-video' + (isVideoOn ? '' : '-slash'); e.target.className = 'fas fa-video' + (isVideoOn ? '' : '-slash');
setColor(e.target, isVideoOn ? 'white' : 'red');
setColor(startVideoButton, isVideoOn ? 'white' : 'red');
} }
// #################################################### // ####################################################
@@ -287,8 +272,8 @@ async function shareRoom(useNavigator = false) {
<canvas id="qrRoom"></canvas> <canvas id="qrRoom"></canvas>
</div> </div>
<br/><br/> <br/><br/>
<p style="color:white;">Share this meeting invite others to join.</p> <p style="background:transparent; color:white;">Share this meeting invite others to join.</p>
<p style="color:rgb(8, 189, 89);">` + <p style="background:transparent; color:rgb(8, 189, 89);">` +
RoomURL + RoomURL +
`</p>`, `</p>`,
showDenyButton: true, showDenyButton: true,
@@ -323,12 +308,13 @@ async function shareRoom(useNavigator = false) {
// #################################################### // ####################################################
function makeRoomQR() { function makeRoomQR() {
let qrSize = DetectRTC.isMobileDevice ? 128 : 256;
let qr = new QRious({ let qr = new QRious({
element: document.getElementById('qrRoom'), element: document.getElementById('qrRoom'),
value: RoomURL, value: RoomURL,
}); });
qr.set({ qr.set({
size: 256, size: qrSize,
}); });
} }
@@ -359,9 +345,8 @@ function joinRoom(peer_name, room_id) {
} else { } else {
console.log('05 ----> join to Room ' + room_id); console.log('05 ----> join to Room ' + room_id);
rc = new RoomClient( rc = new RoomClient(
localMedia,
remoteVideos,
remoteAudios, remoteAudios,
videoMediaContainer,
window.mediasoupClient, window.mediasoupClient,
socket, socket,
room_id, room_id,
@@ -379,7 +364,7 @@ function joinRoom(peer_name, room_id) {
} }
function roomIsReady() { function roomIsReady() {
control.className = ''; show(openNavButton);
show(exitButton); show(exitButton);
show(shareButton); show(shareButton);
show(recButton); show(recButton);
@@ -402,10 +387,9 @@ function roomIsReady() {
}; };
show(fullScreenButton); show(fullScreenButton);
} }
show(devicesButton); show(settingsButton);
if (isAudioAllowed) show(startAudioButton); if (isAudioAllowed) show(startAudioButton);
if (isVideoAllowed) show(startVideoButton); if (isVideoAllowed) show(startVideoButton);
show(videoMedia);
show(participantsButton); show(participantsButton);
show(lockRoomButton); show(lockRoomButton);
show(aboutButton); show(aboutButton);
@@ -423,6 +407,10 @@ function show(elem) {
elem.className = ''; elem.className = '';
} }
function setColor(elem, color) {
elem.style.color = color;
}
// #################################################### // ####################################################
// SET CHAT MOBILE // SET CHAT MOBILE
// #################################################### // ####################################################
@@ -441,7 +429,7 @@ function startSessionTimer() {
let callStartTime = Date.now(); let callStartTime = Date.now();
setInterval(function printTime() { setInterval(function printTime() {
let callElapsedTime = Date.now() - callStartTime; let callElapsedTime = Date.now() - callStartTime;
sessionTime.innerHTML = getTimeToString(callElapsedTime); sessionTime.innerHTML = ' ' + getTimeToString(callElapsedTime);
}, 1000); }, 1000);
} }
@@ -491,13 +479,19 @@ function stopRecordingTimer() {
// #################################################### // ####################################################
function handleButtons() { function handleButtons() {
openNavButton.onclick = () => {
openNav();
};
closeNavButton.onclick = () => {
closeNav();
};
exitButton.onclick = () => { exitButton.onclick = () => {
rc.exit(); rc.exit();
}; };
shareButton.onclick = () => { shareButton.onclick = () => {
shareRoom(true); shareRoom(true);
}; };
devicesButton.onclick = () => { settingsButton.onclick = () => {
rc.toggleDevices(); rc.toggleDevices();
}; };
chatButton.onclick = () => { chatButton.onclick = () => {
@@ -584,7 +578,7 @@ function handleSelects() {
rc.closeThenProduce(RoomClient.mediaType.audio, microphoneSelect.value); rc.closeThenProduce(RoomClient.mediaType.audio, microphoneSelect.value);
}; };
speakerSelect.onchange = () => { speakerSelect.onchange = () => {
rc.attachSinkId(localMedia, speakerSelect.value); rc.attachSinkId(rc.myVideoEl, speakerSelect.value);
}; };
videoSelect.onchange = () => { videoSelect.onchange = () => {
rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value); rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value);
@@ -614,20 +608,24 @@ function handleInputs() {
function handleRoomClientEvents() { function handleRoomClientEvents() {
rc.on(RoomClient.EVENTS.startRec, () => { rc.on(RoomClient.EVENTS.startRec, () => {
console.log('Room Client start recoding');
hide(startRecButton); hide(startRecButton);
show(stopRecButton); show(stopRecButton);
show(pauseRecButton); show(pauseRecButton);
startRecordingTimer(); startRecordingTimer();
}); });
rc.on(RoomClient.EVENTS.pauseRec, () => { rc.on(RoomClient.EVENTS.pauseRec, () => {
console.log('Room Client pause recoding');
hide(pauseRecButton); hide(pauseRecButton);
show(resumeRecButton); show(resumeRecButton);
}); });
rc.on(RoomClient.EVENTS.resumeRec, () => { rc.on(RoomClient.EVENTS.resumeRec, () => {
console.log('Room Client resume recoding');
hide(resumeRecButton); hide(resumeRecButton);
show(pauseRecButton); show(pauseRecButton);
}); });
rc.on(RoomClient.EVENTS.stopRec, () => { rc.on(RoomClient.EVENTS.stopRec, () => {
console.log('Room Client stop recoding');
hide(stopRecButton); hide(stopRecButton);
hide(pauseRecButton); hide(pauseRecButton);
hide(resumeRecButton); hide(resumeRecButton);
@@ -635,8 +633,10 @@ function handleRoomClientEvents() {
stopRecordingTimer(); stopRecordingTimer();
}); });
rc.on(RoomClient.EVENTS.startAudio, () => { rc.on(RoomClient.EVENTS.startAudio, () => {
console.log('Room Client start audio');
hide(startAudioButton); hide(startAudioButton);
show(stopAudioButton); show(stopAudioButton);
setColor(startAudioButton, 'red');
}); });
rc.on(RoomClient.EVENTS.pauseAudio, () => { rc.on(RoomClient.EVENTS.pauseAudio, () => {
console.log('Room Client pause audio'); console.log('Room Client pause audio');
@@ -649,12 +649,15 @@ function handleRoomClientEvents() {
show(stopAudioButton); show(stopAudioButton);
}); });
rc.on(RoomClient.EVENTS.stopAudio, () => { rc.on(RoomClient.EVENTS.stopAudio, () => {
console.log('Room Client stop audio');
hide(stopAudioButton); hide(stopAudioButton);
show(startAudioButton); show(startAudioButton);
}); });
rc.on(RoomClient.EVENTS.startVideo, () => { rc.on(RoomClient.EVENTS.startVideo, () => {
console.log('Room Client start video');
hide(startVideoButton); hide(startVideoButton);
show(stopVideoButton); show(stopVideoButton);
setColor(startVideoButton, 'red');
}); });
rc.on(RoomClient.EVENTS.pauseVideo, () => { rc.on(RoomClient.EVENTS.pauseVideo, () => {
console.log('Room Client pause video'); console.log('Room Client pause video');
@@ -667,10 +670,12 @@ function handleRoomClientEvents() {
show(stopVideoButton); show(stopVideoButton);
}); });
rc.on(RoomClient.EVENTS.stopVideo, () => { rc.on(RoomClient.EVENTS.stopVideo, () => {
console.log('Room Client stop audio');
hide(stopVideoButton); hide(stopVideoButton);
show(startVideoButton); show(startVideoButton);
}); });
rc.on(RoomClient.EVENTS.startScreen, () => { rc.on(RoomClient.EVENTS.startScreen, () => {
console.log('Room Client start screen');
hide(startScreenButton); hide(startScreenButton);
show(stopScreenButton); show(stopScreenButton);
}); });
@@ -681,22 +686,35 @@ function handleRoomClientEvents() {
console.log('Room Client resume screen'); console.log('Room Client resume screen');
}); });
rc.on(RoomClient.EVENTS.stopScreen, () => { rc.on(RoomClient.EVENTS.stopScreen, () => {
console.log('Room Client stop screen');
hide(stopScreenButton); hide(stopScreenButton);
show(startScreenButton); show(startScreenButton);
}); });
rc.on(RoomClient.EVENTS.roomLock, () => { rc.on(RoomClient.EVENTS.roomLock, () => {
console.log('Room Client lock room');
hide(lockRoomButton); hide(lockRoomButton);
show(unlockRoomButton); show(unlockRoomButton);
setColor(unlockRoomButton, 'red');
}); });
rc.on(RoomClient.EVENTS.roomUnlock, () => { rc.on(RoomClient.EVENTS.roomUnlock, () => {
console.log('Room Client unlock room');
hide(unlockRoomButton); hide(unlockRoomButton);
show(lockRoomButton); show(lockRoomButton);
}); });
rc.on(RoomClient.EVENTS.exitRoom, () => { rc.on(RoomClient.EVENTS.exitRoom, () => {
console.log('Room Client leave room');
window.location.href = '/newroom'; window.location.href = '/newroom';
}); });
} }
function openNav() {
control.classList.toggle('show');
}
function closeNav() {
control.classList.toggle('show');
}
// #################################################### // ####################################################
// SHOW LOG // SHOW LOG
// #################################################### // ####################################################
@@ -746,8 +764,14 @@ async function getRoomParticipants() {
let peer_name = peer_info.peer_name; let peer_name = peer_info.peer_name;
let peer_id = peer_info.peer_id; let peer_id = peer_info.peer_id;
rc.peer_id === peer_id rc.peer_id === peer_id
? (table += `<tr><td>- 👤 ${peer_name} (me)</td><td></td></tr>`) ? (table += `<tr>
: (table += `<tr id='${peer_id}'><td>- 👤 ${peer_name}</td><td><button id='${peer_id}' onclick="rc.peerAction('me',this.id,'eject')">eject</button></td></tr>`); <td>👤 ${peer_name} (me)</td>
<td></td>
</tr>`)
: (table += `<tr id='${peer_id}'>
<td>👤 ${peer_name}</td>
<td><button id='${peer_id}' onclick="rc.peerAction('me',this.id,'eject')">eject</button></td>
</tr>`);
} }
table += `</table></div>`; table += `</table></div>`;

عرض الملف

@@ -48,9 +48,8 @@ let recordedBlobs;
class RoomClient { class RoomClient {
constructor( constructor(
localMediaEl,
remoteVideoEl,
remoteAudioEl, remoteAudioEl,
videoMediaContainer,
mediasoupClient, mediasoupClient,
socket, socket,
room_id, room_id,
@@ -63,9 +62,8 @@ class RoomClient {
isVideoOn, isVideoOn,
successCallback, successCallback,
) { ) {
this.localMediaEl = localMediaEl;
this.remoteVideoEl = remoteVideoEl;
this.remoteAudioEl = remoteAudioEl; this.remoteAudioEl = remoteAudioEl;
this.videoMediaContainer = videoMediaContainer;
this.mediasoupClient = mediasoupClient; this.mediasoupClient = mediasoupClient;
this.socket = socket; this.socket = socket;
@@ -103,6 +101,7 @@ class RoomClient {
this.recScreenStream = null; this.recScreenStream = null;
this._isRecording = false; this._isRecording = false;
this.myVideoEl = null;
this.connectedRoom = null; this.connectedRoom = null;
this.debug = false; this.debug = false;
@@ -484,6 +483,8 @@ class RoomClient {
track.stop(); track.stop();
}); });
elem.parentNode.removeChild(elem); elem.parentNode.removeChild(elem);
resizeVideoMedia();
} }
this.producers.delete(producer.id); this.producers.delete(producer.id);
}); });
@@ -495,6 +496,8 @@ class RoomClient {
track.stop(); track.stop();
}); });
elem.parentNode.removeChild(elem); elem.parentNode.removeChild(elem);
resizeVideoMedia();
} }
this.producers.delete(producer.id); this.producers.delete(producer.id);
}); });
@@ -602,27 +605,27 @@ class RoomClient {
async handleProducer(id, type, stream) { async handleProducer(id, type, stream) {
let elem, d, p; let elem, d, p;
d = document.createElement('div'); d = document.createElement('div');
d.className = 'd'; d.className = 'Camera';
d.id = id + '_d'; d.id = id + '_d';
elem = document.createElement('video'); elem = document.createElement('video');
elem.setAttribute('id', id); elem.setAttribute('id', id);
elem.setAttribute('playsinline', true); elem.setAttribute('playsinline', true);
elem.autoplay = true; elem.autoplay = true;
elem.poster = image.poster; elem.poster = image.poster;
if (this.isMobileDevice || type === mediaType.screen) elem.className = 'vid'; this.isMobileDevice || type === mediaType.screen ? (elem.className = '') : (elem.className = 'mirror');
else elem.className = 'vid mirror';
p = document.createElement('p'); p = document.createElement('p');
p.id = id + '_name'; p.id = id + '_name';
p.className = 'pn';
p.innerHTML = '👤 ' + this.peer_name + ' (me)'; p.innerHTML = '👤 ' + this.peer_name + ' (me)';
d.appendChild(elem); d.appendChild(elem);
d.appendChild(p); d.appendChild(p);
this.localMediaEl.appendChild(d); this.videoMediaContainer.appendChild(d);
this.attachMediaStream(elem, stream, type, 'Producer'); this.attachMediaStream(elem, stream, type, 'Producer');
this.myVideoEl = elem;
this.handleFS(elem.id); this.handleFS(elem.id);
this.setTippy(elem.id, 'Full Screen', 'top-end'); this.setTippy(elem.id, 'Full Screen', 'top-end');
this.popupPeerInfo(p.id, this.peer_info); this.popupPeerInfo(p.id, this.peer_info);
this.sound('joined'); this.sound('joined');
resizeVideoMedia();
return elem; return elem;
} }
@@ -698,6 +701,8 @@ class RoomClient {
track.stop(); track.stop();
}); });
d.parentNode.removeChild(d); d.parentNode.removeChild(d);
resizeVideoMedia();
} }
switch (type) { switch (type) {
@@ -780,25 +785,26 @@ class RoomClient {
switch (type) { switch (type) {
case mediaType.video: case mediaType.video:
d = document.createElement('div'); d = document.createElement('div');
d.className = 'd'; d.className = 'Camera';
d.id = id + '_d'; d.id = id + '_d';
elem = document.createElement('video'); elem = document.createElement('video');
elem.setAttribute('id', id); elem.setAttribute('id', id);
elem.setAttribute('playsinline', true); elem.setAttribute('playsinline', true);
elem.autoplay = true; elem.autoplay = true;
elem.className = 'vid'; elem.className = '';
elem.poster = image.poster; elem.poster = image.poster;
p = document.createElement('p'); p = document.createElement('p');
p.id = id + '_name'; p.id = id + '_name';
p.innerHTML = '👤 ' + peer_name; p.innerHTML = '👤 ' + peer_name;
d.appendChild(elem); d.appendChild(elem);
d.appendChild(p); d.appendChild(p);
this.remoteVideoEl.appendChild(d); this.videoMediaContainer.appendChild(d);
this.attachMediaStream(elem, stream, type, 'Consumer'); this.attachMediaStream(elem, stream, type, 'Consumer');
this.handleFS(elem.id); this.handleFS(elem.id);
this.setTippy(elem.id, 'Full Screen', 'top-end'); this.setTippy(elem.id, 'Full Screen', 'top-end');
this.popupPeerInfo(p.id, peer_info); this.popupPeerInfo(p.id, peer_info);
this.sound('joined'); this.sound('joined');
resizeVideoMedia();
break; break;
case mediaType.audio: case mediaType.audio:
elem = document.createElement('audio'); elem = document.createElement('audio');
@@ -822,6 +828,8 @@ class RoomClient {
if (elem) elem.parentNode.removeChild(elem); if (elem) elem.parentNode.removeChild(elem);
if (d) d.parentNode.removeChild(d); if (d) d.parentNode.removeChild(d);
resizeVideoMedia();
this.consumers.delete(consumer_id); this.consumers.delete(consumer_id);
this.sound('left'); this.sound('left');
} }
@@ -959,7 +967,7 @@ class RoomClient {
// #################################################### // ####################################################
toggleDevices() { toggleDevices() {
this.getId('myDevices').classList.toggle('show'); this.getId('settings').classList.toggle('show');
} }
async sound(name) { async sound(name) {

58
public/js/VideoGrid.js Normal file
عرض الملف

@@ -0,0 +1,58 @@
'use strict';
function Area(Increment, Count, Width, Height, Margin = 10) {
let i = 0;
let w = 0;
let h = Increment * 0.75 + Margin * 2;
while (i < Count) {
if (w + Increment > Width) {
w = 0;
h = h + Increment * 0.75 + Margin * 2;
}
w = w + Increment + Margin * 2;
i++;
}
if (h > Height) return false;
else return Increment;
}
function resizeVideoMedia() {
let Margin = 2;
let Scenary = document.getElementById('videoMediaContainer');
let Width = Scenary.offsetWidth - Margin * 2;
let Height = Scenary.offsetHeight - Margin * 2;
let Cameras = document.getElementsByClassName('Camera');
let max = 0;
// loop (i recommend you optimize this)
let i = 1;
while (i < 5000) {
let w = Area(i, Cameras.length, Width, Height, Margin);
if (w === false) {
max = i - 1;
break;
}
i++;
}
max = max - Margin * 2;
setWidth(max, Margin);
}
function setWidth(width, margin) {
let Cameras = document.getElementsByClassName('Camera');
for (var s = 0; s < Cameras.length; s++) {
Cameras[s].style.width = width + 'px';
Cameras[s].style.margin = margin + 'px';
Cameras[s].style.height = width * 0.7 + 'px';
}
}
window.addEventListener(
'load',
function (event) {
resizeVideoMedia();
window.onresize = resizeVideoMedia;
},
false,
);