[mirotalksfu] - add select devices before join
هذا الالتزام موجود في:
@@ -34,9 +34,10 @@ dependencies: {
|
|||||||
* @link GitHub: https://github.com/miroslavpejic85/mirotalksfu
|
* @link GitHub: https://github.com/miroslavpejic85/mirotalksfu
|
||||||
* @link Live demo: https://sfu.mirotalk.com
|
* @link Live demo: https://sfu.mirotalk.com
|
||||||
* @license For open source use: AGPLv3
|
* @license For open source use: AGPLv3
|
||||||
* @license For commercial or closed source, contact us at info.mirotalk@gmail.com
|
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or buy directly via CodeCanyon
|
||||||
|
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||||
* @version 1.0.0
|
* @version 1.0.1
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mirotalksfu",
|
"name": "mirotalksfu",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "WebRTC SFU browser-based video calls",
|
"description": "WebRTC SFU browser-based video calls",
|
||||||
"main": "Server.js",
|
"main": "Server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: url('../images/background.jpg');
|
/* background: url('../images/background.jpg'); */
|
||||||
|
background: var(--body-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------
|
/*--------------------------------------------------------------
|
||||||
@@ -97,27 +98,22 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------
|
/*--------------------------------------------------------------
|
||||||
# Loading...
|
# Init User
|
||||||
--------------------------------------------------------------*/
|
--------------------------------------------------------------*/
|
||||||
|
|
||||||
#loadingDiv {
|
.init-user {
|
||||||
color: #fff;
|
display: block;
|
||||||
padding: 30px;
|
padding: 5px;
|
||||||
border-radius: 10px;
|
|
||||||
background: transparent;
|
|
||||||
}
|
}
|
||||||
#loadingDiv h1 {
|
|
||||||
|
.init-user select {
|
||||||
|
margin-top: 15px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: 60px;
|
cursor: pointer;
|
||||||
font-family: 'Comfortaa';
|
|
||||||
background: rgba(0, 0, 0, 0.7);
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
}
|
||||||
#loadingDiv p {
|
|
||||||
padding: 10px;
|
.init-user button {
|
||||||
font-family: 'Comfortaa';
|
margin-top: 15px;
|
||||||
background: rgba(0, 0, 0, 0.7);
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------------------
|
/*--------------------------------------------------------------
|
||||||
|
|||||||
62
public/js/LocalStorage.js
Normal file
62
public/js/LocalStorage.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
'use-strict';
|
||||||
|
|
||||||
|
class LocalStorage {
|
||||||
|
constructor() {
|
||||||
|
this.MEDIA_TYPE = {
|
||||||
|
audio: 'audio',
|
||||||
|
video: 'video',
|
||||||
|
speaker: 'speaker',
|
||||||
|
};
|
||||||
|
|
||||||
|
this.DEVICES_COUNT = {
|
||||||
|
audio: 0,
|
||||||
|
speaker: 0,
|
||||||
|
video: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.LOCAL_STORAGE_DEVICES = {
|
||||||
|
audio: {
|
||||||
|
count: 0,
|
||||||
|
index: 0,
|
||||||
|
select: null,
|
||||||
|
},
|
||||||
|
speaker: {
|
||||||
|
count: 0,
|
||||||
|
index: 0,
|
||||||
|
select: null,
|
||||||
|
},
|
||||||
|
video: {
|
||||||
|
count: 0,
|
||||||
|
index: 0,
|
||||||
|
select: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setLocalStorageDevices(type, index, select) {
|
||||||
|
switch (type) {
|
||||||
|
case this.MEDIA_TYPE.audio:
|
||||||
|
this.LOCAL_STORAGE_DEVICES.audio.count = this.DEVICES_COUNT.audio;
|
||||||
|
this.LOCAL_STORAGE_DEVICES.audio.index = index;
|
||||||
|
this.LOCAL_STORAGE_DEVICES.audio.select = select;
|
||||||
|
break;
|
||||||
|
case this.MEDIA_TYPE.video:
|
||||||
|
this.LOCAL_STORAGE_DEVICES.video.count = this.DEVICES_COUNT.video;
|
||||||
|
this.LOCAL_STORAGE_DEVICES.video.index = index;
|
||||||
|
this.LOCAL_STORAGE_DEVICES.video.select = select;
|
||||||
|
break;
|
||||||
|
case this.MEDIA_TYPE.speaker:
|
||||||
|
this.LOCAL_STORAGE_DEVICES.speaker.count = this.DEVICES_COUNT.speaker;
|
||||||
|
this.LOCAL_STORAGE_DEVICES.speaker.index = index;
|
||||||
|
this.LOCAL_STORAGE_DEVICES.speaker.select = select;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
localStorage.setItem('LOCAL_STORAGE_DEVICES', JSON.stringify(this.LOCAL_STORAGE_DEVICES));
|
||||||
|
}
|
||||||
|
|
||||||
|
getLocalStorageDevices() {
|
||||||
|
return JSON.parse(localStorage.getItem('LOCAL_STORAGE_DEVICES'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,10 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
|
|||||||
* @link GitHub: https://github.com/miroslavpejic85/mirotalksfu
|
* @link GitHub: https://github.com/miroslavpejic85/mirotalksfu
|
||||||
* @link Live demo: https://sfu.mirotalk.com
|
* @link Live demo: https://sfu.mirotalk.com
|
||||||
* @license For open source use: AGPLv3
|
* @license For open source use: AGPLv3
|
||||||
* @license For commercial or closed source, contact us at info.mirotalk@gmail.com
|
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or buy directly via CodeCanyon
|
||||||
|
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||||
* @version 1.0.0
|
* @version 1.0.1
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -53,6 +54,8 @@ const wbHeight = 600;
|
|||||||
|
|
||||||
const swalImageUrl = '../images/pricing-illustration.svg';
|
const swalImageUrl = '../images/pricing-illustration.svg';
|
||||||
|
|
||||||
|
const lS = new LocalStorage();
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
// DYNAMIC SETTINGS
|
// DYNAMIC SETTINGS
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -109,6 +112,8 @@ let isButtonsBarOver = false;
|
|||||||
|
|
||||||
let isRoomLocked = false;
|
let isRoomLocked = false;
|
||||||
|
|
||||||
|
let initStream = null;
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
// INIT ROOM
|
// INIT ROOM
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -223,31 +228,27 @@ function makeId(length) {
|
|||||||
|
|
||||||
async function initEnumerateDevices() {
|
async function initEnumerateDevices() {
|
||||||
console.log('01 ----> init Enumerate Devices');
|
console.log('01 ----> init Enumerate Devices');
|
||||||
await initEnumerateAudioDevices();
|
whoAreYou();
|
||||||
await initEnumerateVideoDevices();
|
await initEnumerateVideoDevices();
|
||||||
|
await initEnumerateAudioDevices();
|
||||||
|
if (!isVideoAllowed) {
|
||||||
|
hide(initVideo);
|
||||||
|
hide(initVideoSelect);
|
||||||
|
}
|
||||||
|
if (!isAudioAllowed) {
|
||||||
|
hide(initMicrophoneSelect);
|
||||||
|
hide(initSpeakerSelect);
|
||||||
|
}
|
||||||
if (!isAudioAllowed && !isVideoAllowed && !joinRoomWithoutAudioVideo) {
|
if (!isAudioAllowed && !isVideoAllowed && !joinRoomWithoutAudioVideo) {
|
||||||
openURL(`/permission?room_id=${room_id}&message=Not allowed both Audio and Video`);
|
openURL(`/permission?room_id=${room_id}&message=Not allowed both Audio and Video`);
|
||||||
} else {
|
} else {
|
||||||
hide(loadingDiv);
|
setButtonsInit();
|
||||||
|
setSelectsInit();
|
||||||
|
handleSelectsInit();
|
||||||
getPeerGeoLocation();
|
getPeerGeoLocation();
|
||||||
whoAreYou();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initEnumerateAudioDevices() {
|
|
||||||
if (isEnumerateAudioDevices) return;
|
|
||||||
// allow the audio
|
|
||||||
await navigator.mediaDevices
|
|
||||||
.getUserMedia({ audio: true })
|
|
||||||
.then((stream) => {
|
|
||||||
enumerateAudioDevices(stream);
|
|
||||||
isAudioAllowed = true;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
isAudioAllowed = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initEnumerateVideoDevices() {
|
async function initEnumerateVideoDevices() {
|
||||||
if (isEnumerateVideoDevices) return;
|
if (isEnumerateVideoDevices) return;
|
||||||
// allow the video
|
// allow the video
|
||||||
@@ -262,31 +263,6 @@ async function initEnumerateVideoDevices() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function enumerateAudioDevices(stream) {
|
|
||||||
console.log('02 ----> Get Audio Devices');
|
|
||||||
navigator.mediaDevices
|
|
||||||
.enumerateDevices()
|
|
||||||
.then((devices) =>
|
|
||||||
devices.forEach((device) => {
|
|
||||||
let el = null;
|
|
||||||
if ('audioinput' === device.kind) {
|
|
||||||
el = microphoneSelect;
|
|
||||||
RoomClient.DEVICES_COUNT.audio++;
|
|
||||||
} else if ('audiooutput' === device.kind) {
|
|
||||||
el = speakerSelect;
|
|
||||||
RoomClient.DEVICES_COUNT.speaker++;
|
|
||||||
}
|
|
||||||
if (!el) return;
|
|
||||||
addChild(device, el);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
stopTracks(stream);
|
|
||||||
isEnumerateAudioDevices = true;
|
|
||||||
speakerSelect.disabled = !('sinkId' in HTMLMediaElement.prototype);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function enumerateVideoDevices(stream) {
|
function enumerateVideoDevices(stream) {
|
||||||
console.log('03 ----> Get Video Devices');
|
console.log('03 ----> Get Video Devices');
|
||||||
navigator.mediaDevices
|
navigator.mediaDevices
|
||||||
@@ -294,12 +270,14 @@ function enumerateVideoDevices(stream) {
|
|||||||
.then((devices) =>
|
.then((devices) =>
|
||||||
devices.forEach((device) => {
|
devices.forEach((device) => {
|
||||||
let el = null;
|
let el = null;
|
||||||
|
let eli = null;
|
||||||
if ('videoinput' === device.kind) {
|
if ('videoinput' === device.kind) {
|
||||||
el = videoSelect;
|
el = videoSelect;
|
||||||
RoomClient.DEVICES_COUNT.video++;
|
eli = initVideoSelect;
|
||||||
|
lS.DEVICES_COUNT.video++;
|
||||||
}
|
}
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
addChild(device, el);
|
addChild(device, [el, eli]);
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -308,17 +286,76 @@ function enumerateVideoDevices(stream) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initEnumerateAudioDevices() {
|
||||||
|
if (isEnumerateAudioDevices) return;
|
||||||
|
// allow the audio
|
||||||
|
await navigator.mediaDevices
|
||||||
|
.getUserMedia({ audio: true })
|
||||||
|
.then((stream) => {
|
||||||
|
enumerateAudioDevices(stream);
|
||||||
|
isAudioAllowed = true;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
isAudioAllowed = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function enumerateAudioDevices(stream) {
|
||||||
|
console.log('02 ----> Get Audio Devices');
|
||||||
|
navigator.mediaDevices
|
||||||
|
.enumerateDevices()
|
||||||
|
.then((devices) =>
|
||||||
|
devices.forEach((device) => {
|
||||||
|
let el = null;
|
||||||
|
let eli = null;
|
||||||
|
if ('audioinput' === device.kind) {
|
||||||
|
el = microphoneSelect;
|
||||||
|
eli = initMicrophoneSelect;
|
||||||
|
lS.DEVICES_COUNT.audio++;
|
||||||
|
} else if ('audiooutput' === device.kind) {
|
||||||
|
el = speakerSelect;
|
||||||
|
eli = initSpeakerSelect;
|
||||||
|
lS.DEVICES_COUNT.speaker++;
|
||||||
|
}
|
||||||
|
if (!el) return;
|
||||||
|
addChild(device, [el, eli]);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
stopTracks(stream);
|
||||||
|
isEnumerateAudioDevices = true;
|
||||||
|
const sinkId = 'sinkId' in HTMLMediaElement.prototype;
|
||||||
|
speakerSelect.disabled = !sinkId;
|
||||||
|
if (!sinkId) hide(initSpeakerSelect);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function stopTracks(stream) {
|
function stopTracks(stream) {
|
||||||
stream.getTracks().forEach((track) => {
|
stream.getTracks().forEach((track) => {
|
||||||
track.stop();
|
track.stop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addChild(device, el) {
|
function addChild(device, els) {
|
||||||
let option = document.createElement('option');
|
let kind = device.kind;
|
||||||
option.value = device.deviceId;
|
els.forEach((el) => {
|
||||||
option.innerText = device.label;
|
let option = document.createElement('option');
|
||||||
el.appendChild(option);
|
option.value = device.deviceId;
|
||||||
|
switch (kind) {
|
||||||
|
case 'videoinput':
|
||||||
|
option.innerHTML = `📹 ` + device.label || `📹 camera ${el.length + 1}`;
|
||||||
|
break;
|
||||||
|
case 'audioinput':
|
||||||
|
option.innerHTML = `🎤 ` + device.label || `🎤 microphone ${el.length + 1}`;
|
||||||
|
break;
|
||||||
|
case 'audiooutput':
|
||||||
|
option.innerHTML = `🔈 ` + device.label || `🔈 speaker ${el.length + 1}`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
el.appendChild(option);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -407,6 +444,7 @@ function getPeerGeoLocation() {
|
|||||||
|
|
||||||
function whoAreYou() {
|
function whoAreYou() {
|
||||||
console.log('04 ----> Who are you');
|
console.log('04 ----> Who are you');
|
||||||
|
sound('open');
|
||||||
|
|
||||||
if (peer_name) {
|
if (peer_name) {
|
||||||
checkMedia();
|
checkMedia();
|
||||||
@@ -420,21 +458,18 @@ function whoAreYou() {
|
|||||||
default_name = getCookie(room_id + '_name');
|
default_name = getCookie(room_id + '_name');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initUser = document.getElementById('initUser');
|
||||||
|
initUser.classList.toggle('hidden');
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
allowOutsideClick: false,
|
allowOutsideClick: false,
|
||||||
allowEscapeKey: false,
|
allowEscapeKey: false,
|
||||||
background: swalBackground,
|
background: swalBackground,
|
||||||
imageAlt: 'mirotalksfu-username',
|
title: 'MiroTalk SFU',
|
||||||
imageUrl: image.username,
|
|
||||||
input: 'text',
|
input: 'text',
|
||||||
inputPlaceholder: 'Enter your name',
|
inputPlaceholder: 'Enter your name',
|
||||||
inputValue: default_name,
|
inputValue: default_name,
|
||||||
html: `<br />
|
html: initUser, // Inject HTML
|
||||||
<div style="padding: 10px;">
|
|
||||||
<button id="initAudioButton" class="fas fa-microphone" onclick="handleAudio(event)"></button>
|
|
||||||
<button id="initVideoButton" class="fas fa-video" onclick="handleVideo(event)"></button>
|
|
||||||
<button id="initAudioVideoButton" class="fas fa-eye" onclick="handleAudioVideo(event)"></button>
|
|
||||||
</div>`,
|
|
||||||
confirmButtonText: `Join meeting`,
|
confirmButtonText: `Join meeting`,
|
||||||
showClass: {
|
showClass: {
|
||||||
popup: 'animate__animated animate__fadeInDown',
|
popup: 'animate__animated animate__fadeInDown',
|
||||||
@@ -451,23 +486,13 @@ function whoAreYou() {
|
|||||||
peer_name = name;
|
peer_name = name;
|
||||||
},
|
},
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
if (initStream) {
|
||||||
|
stopTracks(initStream);
|
||||||
|
hide(initVideo);
|
||||||
|
}
|
||||||
getPeerInfo();
|
getPeerInfo();
|
||||||
joinRoom(peer_name, room_id);
|
joinRoom(peer_name, room_id);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!DetectRTC.isMobileDevice) {
|
|
||||||
setTippy('initAudioButton', 'Toggle the audio', 'left');
|
|
||||||
setTippy('initVideoButton', 'Toggle the video', 'right');
|
|
||||||
setTippy('initAudioVideoButton', 'Toggle the audio & video', 'right');
|
|
||||||
}
|
|
||||||
|
|
||||||
initAudioButton = document.getElementById('initAudioButton');
|
|
||||||
initVideoButton = document.getElementById('initVideoButton');
|
|
||||||
initAudioVideoButton = document.getElementById('initAudioVideoButton');
|
|
||||||
if (!isAudioAllowed) hide(initAudioButton);
|
|
||||||
if (!isVideoAllowed) hide(initVideoButton);
|
|
||||||
if (!isAudioAllowed || !isVideoAllowed) hide(initAudioVideoButton);
|
|
||||||
isAudioVideoAllowed = isAudioAllowed && isVideoAllowed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAudio(e) {
|
function handleAudio(e) {
|
||||||
@@ -475,6 +500,7 @@ function handleAudio(e) {
|
|||||||
e.target.className = 'fas fa-microphone' + (isAudioAllowed ? '' : '-slash');
|
e.target.className = 'fas fa-microphone' + (isAudioAllowed ? '' : '-slash');
|
||||||
setColor(e.target, isAudioAllowed ? 'white' : 'red');
|
setColor(e.target, isAudioAllowed ? 'white' : 'red');
|
||||||
setColor(startAudioButton, isAudioAllowed ? 'white' : 'red');
|
setColor(startAudioButton, isAudioAllowed ? 'white' : 'red');
|
||||||
|
checkInitAudio(isAudioAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleVideo(e) {
|
function handleVideo(e) {
|
||||||
@@ -482,6 +508,7 @@ function handleVideo(e) {
|
|||||||
e.target.className = 'fas fa-video' + (isVideoAllowed ? '' : '-slash');
|
e.target.className = 'fas fa-video' + (isVideoAllowed ? '' : '-slash');
|
||||||
setColor(e.target, isVideoAllowed ? 'white' : 'red');
|
setColor(e.target, isVideoAllowed ? 'white' : 'red');
|
||||||
setColor(startVideoButton, isVideoAllowed ? 'white' : 'red');
|
setColor(startVideoButton, isVideoAllowed ? 'white' : 'red');
|
||||||
|
checkInitVideo(isVideoAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAudioVideo(e) {
|
function handleAudioVideo(e) {
|
||||||
@@ -500,6 +527,28 @@ function handleAudioVideo(e) {
|
|||||||
setColor(initVideoButton, isVideoAllowed ? 'white' : 'red');
|
setColor(initVideoButton, isVideoAllowed ? 'white' : 'red');
|
||||||
setColor(startAudioButton, isAudioAllowed ? 'white' : 'red');
|
setColor(startAudioButton, isAudioAllowed ? 'white' : 'red');
|
||||||
setColor(startVideoButton, isVideoAllowed ? 'white' : 'red');
|
setColor(startVideoButton, isVideoAllowed ? 'white' : 'red');
|
||||||
|
checkInitVideo(isVideoAllowed);
|
||||||
|
checkInitAudio(isAudioAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkInitVideo(isVideoAllowed) {
|
||||||
|
if (isVideoAllowed) {
|
||||||
|
if (initVideoSelect.value) changeCamera(initVideoSelect.value);
|
||||||
|
sound('joined');
|
||||||
|
} else {
|
||||||
|
if (initStream) {
|
||||||
|
stopTracks(initStream);
|
||||||
|
hide(initVideo);
|
||||||
|
sound('left');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initVideoSelect.disabled = !isVideoAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkInitAudio(isAudioAllowed) {
|
||||||
|
initMicrophoneSelect.disabled = !isAudioAllowed;
|
||||||
|
initSpeakerSelect.disabled = !isAudioAllowed;
|
||||||
|
isAudioAllowed ? sound('joined') : sound('left');
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkMedia() {
|
function checkMedia() {
|
||||||
@@ -557,7 +606,7 @@ async function shareRoom(useNavigator = false) {
|
|||||||
denyButtonText: `Email invite`,
|
denyButtonText: `Email invite`,
|
||||||
cancelButtonText: `Close`,
|
cancelButtonText: `Close`,
|
||||||
showClass: {
|
showClass: {
|
||||||
popup: 'animate__animated animate__fadeInUp',
|
popup: 'animate__animated animate__fadeInDown',
|
||||||
},
|
},
|
||||||
hideClass: {
|
hideClass: {
|
||||||
popup: 'animate__animated animate__fadeOutUp',
|
popup: 'animate__animated animate__fadeOutUp',
|
||||||
@@ -1003,25 +1052,119 @@ function handleButtons() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
// HTML SELECTS
|
// HANDLE INIT USER
|
||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
|
function setButtonsInit() {
|
||||||
|
if (!DetectRTC.isMobileDevice) {
|
||||||
|
setTippy('initAudioButton', 'Toggle the audio', 'left');
|
||||||
|
setTippy('initVideoButton', 'Toggle the video', 'right');
|
||||||
|
setTippy('initAudioVideoButton', 'Toggle the audio & video', 'right');
|
||||||
|
}
|
||||||
|
initAudioButton = document.getElementById('initAudioButton');
|
||||||
|
initVideoButton = document.getElementById('initVideoButton');
|
||||||
|
initAudioVideoButton = document.getElementById('initAudioVideoButton');
|
||||||
|
if (!isAudioAllowed) hide(initAudioButton);
|
||||||
|
if (!isVideoAllowed) hide(initVideoButton);
|
||||||
|
if (!isAudioAllowed || !isVideoAllowed) hide(initAudioVideoButton);
|
||||||
|
isAudioVideoAllowed = isAudioAllowed && isVideoAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelectsInit() {
|
||||||
|
// devices init options
|
||||||
|
initVideoSelect.onchange = () => {
|
||||||
|
changeCamera(initVideoSelect.value);
|
||||||
|
videoSelect.selectedIndex = initVideoSelect.selectedIndex;
|
||||||
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.video, videoSelect.selectedIndex, videoSelect.value);
|
||||||
|
};
|
||||||
|
initMicrophoneSelect.onchange = () => {
|
||||||
|
microphoneSelect.selectedIndex = initMicrophoneSelect.selectedIndex;
|
||||||
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.audio, microphoneSelect.selectedIndex, microphoneSelect.value);
|
||||||
|
};
|
||||||
|
initSpeakerSelect.onchange = () => {
|
||||||
|
speakerSelect.selectedIndex = initSpeakerSelect.selectedIndex;
|
||||||
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.speaker, initSpeakerSelect.selectedIndex, initSpeakerSelect.value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelectsInit() {
|
||||||
|
const localStorageDevices = lS.getLocalStorageDevices();
|
||||||
|
console.log('04 ----> Get Local Storage Devices before', localStorageDevices);
|
||||||
|
if (localStorageDevices) {
|
||||||
|
initMicrophoneSelect.selectedIndex = localStorageDevices.audio.index;
|
||||||
|
initSpeakerSelect.selectedIndex = localStorageDevices.speaker.index;
|
||||||
|
initVideoSelect.selectedIndex = localStorageDevices.video.index;
|
||||||
|
//
|
||||||
|
microphoneSelect.selectedIndex = initMicrophoneSelect.selectedIndex;
|
||||||
|
speakerSelect.selectedIndex = initSpeakerSelect.selectedIndex;
|
||||||
|
videoSelect.selectedIndex = initVideoSelect.selectedIndex;
|
||||||
|
//
|
||||||
|
if (lS.DEVICES_COUNT.audio != localStorageDevices.audio.count) {
|
||||||
|
console.log('04.1 ----> Audio devices seems changed, use default index 0');
|
||||||
|
initMicrophoneSelect.selectedIndex = 0;
|
||||||
|
microphoneSelect.selectedIndex = 0;
|
||||||
|
lS.setLocalStorageDevices(
|
||||||
|
lS.MEDIA_TYPE.audio,
|
||||||
|
initMicrophoneSelect.selectedIndex,
|
||||||
|
initMicrophoneSelect.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (lS.DEVICES_COUNT.speaker != localStorageDevices.speaker.count) {
|
||||||
|
console.log('04.2 ----> Speaker devices seems changed, use default index 0');
|
||||||
|
initSpeakerSelect.selectedIndex = 0;
|
||||||
|
speakerSelect.selectedIndex = 0;
|
||||||
|
lS.setLocalStorageDevices(
|
||||||
|
lS.MEDIA_TYPE.speaker,
|
||||||
|
initSpeakerSelect.selectedIndexIndex,
|
||||||
|
initSpeakerSelect.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (lS.DEVICES_COUNT.video != localStorageDevices.video.count) {
|
||||||
|
console.log('04.3 ----> Video devices seems changed, use default index 0');
|
||||||
|
initVideoSelect.selectedIndex = 0;
|
||||||
|
videoSelect.selectedIndex = 0;
|
||||||
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.video, initVideoSelect.selectedIndex, initVideoSelect.value);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
console.log('04.4 ----> Get Local Storage Devices after', lS.getLocalStorageDevices());
|
||||||
|
}
|
||||||
|
if (initVideoSelect.value) changeCamera(initVideoSelect.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeCamera(deviceId) {
|
||||||
|
if (initStream) {
|
||||||
|
stopTracks(initStream);
|
||||||
|
show(initVideo);
|
||||||
|
}
|
||||||
|
navigator.mediaDevices
|
||||||
|
.getUserMedia({ video: { deviceId: deviceId } })
|
||||||
|
.then((camStream) => {
|
||||||
|
initVideo.srcObject = camStream;
|
||||||
|
initStream = camStream;
|
||||||
|
console.log('04.5 ----> Success attached init video stream');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('[Error] changeCamera', err);
|
||||||
|
userLog('error', 'Error while swapping camera' + err.tostring(), 'top-end');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function handleSelects() {
|
function handleSelects() {
|
||||||
// devices options
|
// devices options
|
||||||
videoSelect.onchange = () => {
|
videoSelect.onchange = () => {
|
||||||
rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value);
|
rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value);
|
||||||
rc.setLocalStorageDevices(RoomClient.mediaType.video, videoSelect.selectedIndex, videoSelect.value);
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.video, videoSelect.selectedIndex, videoSelect.value);
|
||||||
};
|
};
|
||||||
videoQuality.onchange = () => {
|
videoQuality.onchange = () => {
|
||||||
rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value);
|
rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value);
|
||||||
};
|
};
|
||||||
microphoneSelect.onchange = () => {
|
microphoneSelect.onchange = () => {
|
||||||
rc.closeThenProduce(RoomClient.mediaType.audio, microphoneSelect.value);
|
rc.closeThenProduce(RoomClient.mediaType.audio, microphoneSelect.value);
|
||||||
rc.setLocalStorageDevices(RoomClient.mediaType.audio, microphoneSelect.selectedIndex, microphoneSelect.value);
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.audio, microphoneSelect.selectedIndex, microphoneSelect.value);
|
||||||
};
|
};
|
||||||
speakerSelect.onchange = () => {
|
initSpeakerSelect.onchange = () => {
|
||||||
rc.attachSinkId(rc.myAudioEl, speakerSelect.value);
|
rc.attachSinkId(rc.myAudioEl, initSpeakerSelect.value);
|
||||||
rc.setLocalStorageDevices(RoomClient.mediaType.speaker, speakerSelect.selectedIndex, speakerSelect.value);
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.speaker, initSpeakerSelect.selectedIndex, initSpeakerSelect.value);
|
||||||
};
|
};
|
||||||
// room
|
// room
|
||||||
switchSounds.onchange = (e) => {
|
switchSounds.onchange = (e) => {
|
||||||
@@ -2093,7 +2236,7 @@ function showAbout() {
|
|||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
showClass: {
|
showClass: {
|
||||||
popup: 'animate__animated animate__fadeInUp',
|
popup: 'animate__animated animate__fadeInDown',
|
||||||
},
|
},
|
||||||
hideClass: {
|
hideClass: {
|
||||||
popup: 'animate__animated animate__fadeOutUp',
|
popup: 'animate__animated animate__fadeOutUp',
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or buy directly via CodeCanyon
|
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or buy directly via CodeCanyon
|
||||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||||
* @version 1.0.0
|
* @version 1.0.1
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -66,30 +66,6 @@ const mediaType = {
|
|||||||
speaker: 'speakerType',
|
speaker: 'speakerType',
|
||||||
};
|
};
|
||||||
|
|
||||||
const LOCAL_STORAGE_DEVICES = {
|
|
||||||
audio: {
|
|
||||||
count: 0,
|
|
||||||
index: 0,
|
|
||||||
select: null,
|
|
||||||
},
|
|
||||||
speaker: {
|
|
||||||
count: 0,
|
|
||||||
index: 0,
|
|
||||||
select: null,
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
count: 0,
|
|
||||||
index: 0,
|
|
||||||
select: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const DEVICES_COUNT = {
|
|
||||||
audio: 0,
|
|
||||||
speaker: 0,
|
|
||||||
video: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const _EVENTS = {
|
const _EVENTS = {
|
||||||
openRoom: 'openRoom',
|
openRoom: 'openRoom',
|
||||||
exitRoom: 'exitRoom',
|
exitRoom: 'exitRoom',
|
||||||
@@ -653,30 +629,7 @@ class RoomClient {
|
|||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
startLocalMedia() {
|
startLocalMedia() {
|
||||||
let localStorageDevices = this.getLocalStorageDevices();
|
console.log('08 ----> Start local media');
|
||||||
console.log('08 ----> Get Local Storage Devices before', localStorageDevices);
|
|
||||||
if (localStorageDevices) {
|
|
||||||
microphoneSelect.selectedIndex = localStorageDevices.audio.index;
|
|
||||||
speakerSelect.selectedIndex = localStorageDevices.speaker.index;
|
|
||||||
videoSelect.selectedIndex = localStorageDevices.video.index;
|
|
||||||
//
|
|
||||||
if (DEVICES_COUNT.audio != localStorageDevices.audio.count) {
|
|
||||||
console.log('08.1 ----> Audio devices seems changed, use default index 0');
|
|
||||||
microphoneSelect.selectedIndex = 0;
|
|
||||||
this.setLocalStorageDevices(mediaType.audio, microphoneSelect.selectedIndex, microphoneSelect.value);
|
|
||||||
}
|
|
||||||
if (DEVICES_COUNT.speaker != localStorageDevices.speaker.count) {
|
|
||||||
console.log('08.2 ----> Speaker devices seems changed, use default index 0');
|
|
||||||
speakerSelect.selectedIndex = 0;
|
|
||||||
this.setLocalStorageDevices(mediaType.speaker, speakerSelect.selectedIndex, speakerSelect.value);
|
|
||||||
}
|
|
||||||
if (DEVICES_COUNT.video != localStorageDevices.video.count) {
|
|
||||||
console.log('08.3 ----> Video devices seems changed, use default index 0');
|
|
||||||
videoSelect.selectedIndex = 0;
|
|
||||||
this.setLocalStorageDevices(mediaType.video, videoSelect.selectedIndex, videoSelect.value);
|
|
||||||
}
|
|
||||||
console.log('08.4 ----> Get Local Storage Devices after', this.getLocalStorageDevices());
|
|
||||||
}
|
|
||||||
if (this.isAudioAllowed) {
|
if (this.isAudioAllowed) {
|
||||||
console.log('09 ----> Start audio media');
|
console.log('09 ----> Start audio media');
|
||||||
this.produce(mediaType.audio, microphoneSelect.value);
|
this.produce(mediaType.audio, microphoneSelect.value);
|
||||||
@@ -1804,7 +1757,7 @@ class RoomClient {
|
|||||||
console.error('Attach SinkId error: ', errorMessage);
|
console.error('Attach SinkId error: ', errorMessage);
|
||||||
this.userLog('error', errorMessage, 'top-end');
|
this.userLog('error', errorMessage, 'top-end');
|
||||||
speakerSelect.selectedIndex = 0;
|
speakerSelect.selectedIndex = 0;
|
||||||
this.setLocalStorageDevices(mediaType.speaker, 0, speakerSelect.value);
|
lS.setLocalStorageDevices(lS.MEDIA_TYPE.speaker, 0, speakerSelect.value);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let error = `Browser seems doesn't support output device selection.`;
|
let error = `Browser seems doesn't support output device selection.`;
|
||||||
@@ -4191,33 +4144,4 @@ class RoomClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ####################################################
|
|
||||||
// LOCAL STORAGE DEVICES
|
|
||||||
// ####################################################
|
|
||||||
|
|
||||||
setLocalStorageDevices(type, index, select) {
|
|
||||||
switch (type) {
|
|
||||||
case RoomClient.mediaType.audio:
|
|
||||||
LOCAL_STORAGE_DEVICES.audio.count = DEVICES_COUNT.audio;
|
|
||||||
LOCAL_STORAGE_DEVICES.audio.index = index;
|
|
||||||
LOCAL_STORAGE_DEVICES.audio.select = select;
|
|
||||||
break;
|
|
||||||
case RoomClient.mediaType.video:
|
|
||||||
LOCAL_STORAGE_DEVICES.video.count = DEVICES_COUNT.video;
|
|
||||||
LOCAL_STORAGE_DEVICES.video.index = index;
|
|
||||||
LOCAL_STORAGE_DEVICES.video.select = select;
|
|
||||||
break;
|
|
||||||
case RoomClient.mediaType.speaker:
|
|
||||||
LOCAL_STORAGE_DEVICES.speaker.count = DEVICES_COUNT.speaker;
|
|
||||||
LOCAL_STORAGE_DEVICES.speaker.index = index;
|
|
||||||
LOCAL_STORAGE_DEVICES.speaker.select = select;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
localStorage.setItem('LOCAL_STORAGE_DEVICES', JSON.stringify(LOCAL_STORAGE_DEVICES));
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocalStorageDevices() {
|
|
||||||
return JSON.parse(localStorage.getItem('LOCAL_STORAGE_DEVICES'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
|
|
||||||
<script defer src="/socket.io/socket.io.js"></script>
|
<script defer src="/socket.io/socket.io.js"></script>
|
||||||
<script defer src="../sfu/MediasoupClient.js"></script>
|
<script defer src="../sfu/MediasoupClient.js"></script>
|
||||||
|
<script defer src="../js/LocalStorage.js"></script>
|
||||||
<script defer src="../js/Rules.js"></script>
|
<script defer src="../js/Rules.js"></script>
|
||||||
<script defer src="../js/Room.js"></script>
|
<script defer src="../js/Room.js"></script>
|
||||||
<script defer src="../js/RoomClient.js"></script>
|
<script defer src="../js/RoomClient.js"></script>
|
||||||
@@ -90,10 +91,25 @@
|
|||||||
<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 id="loadingDiv" class="center pulsate">
|
<section>
|
||||||
<h1>Loading...</h1>
|
<div id="initUser" class="init-user hidden">
|
||||||
<p>Please allow the camera or microphone access to use this app.</p>
|
<p>Please allow the camera & microphone access to use this app.</p>
|
||||||
</div>
|
<video
|
||||||
|
id="initVideo"
|
||||||
|
playsinline="true"
|
||||||
|
autoplay=""
|
||||||
|
poster="../images/loader.gif"
|
||||||
|
class="mirror"
|
||||||
|
style="object-fit: var(--videoObjFit)"
|
||||||
|
></video>
|
||||||
|
<button id="initAudioButton" class="fas fa-microphone" onclick="handleAudio(event)"></button>
|
||||||
|
<button id="initVideoButton" class="fas fa-video" onclick="handleVideo(event)"></button>
|
||||||
|
<button id="initAudioVideoButton" class="fas fa-eye" onclick="handleAudioVideo(event)"></button>
|
||||||
|
<select id="initVideoSelect" class="form-select text-light bg-dark"></select>
|
||||||
|
<select id="initMicrophoneSelect" class="form-select text-light bg-dark"></select>
|
||||||
|
<select id="initSpeakerSelect" class="form-select text-light bg-dark"></select>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div id="control" class="fadein">
|
<div id="control" class="fadein">
|
||||||
<button id="shareButton" class="hidden"><i class="fas fa-share-alt"></i></button>
|
<button id="shareButton" class="hidden"><i class="fas fa-share-alt"></i></button>
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم