[mirotalksfu] - added raise hand & turn-off audio-video

هذا الالتزام موجود في:
Miroslav Pejic
2021-09-18 17:59:32 +02:00
الأصل 9f59886c0c
التزام a265f669b0
9 ملفات معدلة مع 287 إضافات و81 حذوفات

عرض الملف

@@ -116,6 +116,8 @@ access to use this app.
<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="raiseHandButton" class="hidden"><i class="fas fa-hand-rock"></i> Raise hand</button>
<button id="lowerHandButton" class="hidden"><i class="fas fa-hand-paper"></i> Lower hand</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>

عرض الملف

@@ -532,16 +532,6 @@ button:hover {
overflow: auto;
}
#roomParticipants button {
background: transparent;
color: red;
border-radius: 5px;
}
#roomParticipants button:hover {
color: white;
border-radius: 5px;
}
#roomParticipants table {
border-collapse: collapse;
width: 100%;

ثنائية
public/images/hide.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 1.8 KiB

ثنائية
public/images/mute.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 3.6 KiB

عرض الملف

@@ -4,6 +4,16 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
const RoomURL = window.location.href;
const _PEER = {
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>',
videoOff: '<i style="color: red;" class="fas fa-video-slash"></i>',
raiseHand: '<i style="color: rgb(0, 180, 50);" class="fas fa-hand-paper pulsate"></i>',
lowerHand: '',
ejectPeer: '<i class="fas fa-times"></i>',
};
const swalBackground = 'linear-gradient(to left, #1f1e1e, #000000)';
const swalImageUrl = '../images/pricing-illustration.svg';
@@ -174,6 +184,7 @@ function getPeerInfo() {
peer_name: peer_name,
peer_audio: isAudioOn,
peer_video: isVideoOn,
peer_hand: false,
};
}
@@ -389,6 +400,7 @@ function roomIsReady() {
show(fullScreenButton);
}
show(settingsButton);
show(raiseHandButton);
if (isAudioAllowed) show(startAudioButton);
if (isVideoAllowed) show(startVideoButton);
show(participantsButton);
@@ -534,6 +546,12 @@ function handleButtons() {
swapCameraButton.onclick = () => {
rc.closeThenProduce(RoomClient.mediaType.video, null, true);
};
raiseHandButton.onclick = () => {
rc.updatePeerInfo(peer_name, rc.peer_id, 'hand', true);
};
lowerHandButton.onclick = () => {
rc.updatePeerInfo(peer_name, rc.peer_id, 'hand', false);
};
startAudioButton.onclick = () => {
rc.produce(RoomClient.mediaType.audio, microphoneSelect.value);
// rc.resumeProducer(RoomClient.mediaType.audio);
@@ -633,6 +651,17 @@ function handleRoomClientEvents() {
show(startRecButton);
stopRecordingTimer();
});
rc.on(RoomClient.EVENTS.raiseHand, () => {
console.log('Room Client raise hand');
hide(raiseHandButton);
show(lowerHandButton);
setColor(lowerHandButton, 'green');
});
rc.on(RoomClient.EVENTS.lowerHand, () => {
console.log('Room Client lower hand');
hide(lowerHandButton);
show(raiseHandButton);
});
rc.on(RoomClient.EVENTS.startAudio, () => {
console.log('Room Client start audio');
hide(startAudioButton);
@@ -720,13 +749,13 @@ function closeNav() {
// SHOW LOG
// ####################################################
function userLog(icon, message, position) {
function userLog(icon, message, position, timer = 3000) {
const Toast = Swal.mixin({
background: swalBackground,
toast: true,
position: position,
showConfirmButton: false,
timer: 3000,
timer: timer,
});
Toast.fire({
icon: icon,
@@ -755,26 +784,7 @@ async function sound(name) {
async function getRoomParticipants() {
let room_info = await rc.getRoomInfo();
let peers = new Map(JSON.parse(room_info.peers));
let table = `<div id="roomParticipants"><table>
<tr>
<th></th>
<th></th>
</tr>`;
for (let peer of Array.from(peers.keys())) {
let peer_info = peers.get(peer).peer_info;
let peer_name = peer_info.peer_name;
let peer_id = peer_info.peer_id;
rc.peer_id === peer_id
? (table += `<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>`;
let table = await getParticipantsTable(peers);
sound('open');
@@ -783,15 +793,66 @@ async function getRoomParticipants() {
position: 'center',
title: `Participants ${peers.size}`,
html: table,
showCancelButton: true,
confirmButtonText: `Refresh`,
cancelButtonText: `Close`,
showClass: {
popup: 'animate__animated animate__fadeInDown',
},
hideClass: {
popup: 'animate__animated animate__fadeOutUp',
},
}).then((result) => {
if (result.isConfirmed) {
getRoomParticipants();
}
});
}
async function getParticipantsTable(peers) {
let table = `<div id="roomParticipants">
<table>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>`;
for (let peer of Array.from(peers.keys())) {
let peer_info = peers.get(peer).peer_info;
let peer_name = '👤 ' + peer_info.peer_name;
let peer_audio = peer_info.peer_audio ? _PEER.audioOn : _PEER.audioOff;
let peer_video = peer_info.peer_video ? _PEER.videoOn : _PEER.videoOff;
let peer_hand = peer_info.peer_hand ? _PEER.raiseHand : _PEER.lowerHand;
let peer_eject = _PEER.ejectPeer;
let peer_id = peer_info.peer_id;
if (rc.peer_id === peer_id) {
table += `
<tr>
<td>${peer_name} (me)</td>
<td><button>${peer_audio}</button></td>
<td><button>${peer_video}</button></td>
<td><button>${peer_hand}</button></td>
<td></td>
</tr>
`;
} else {
table += `
<tr id='${peer_id}'>
<td>${peer_name}</td>
<td><button id='${peer_id}__audio' onclick="rc.peerAction('me',this.id,'mute')">${peer_audio}</button></td>
<td><button id='${peer_id}__video' onclick="rc.peerAction('me',this.id,'hide')">${peer_video}</button></td>
<td><button>${peer_hand}</button></td>
<td><button id='${peer_id}__eject' onclick="rc.peerAction('me',this.id,'eject')">${peer_eject}</button></td>
</tr>
`;
}
}
table += `</table></div>`;
return table;
}
// ####################################################
// ABOUT
// ####################################################

عرض الملف

@@ -12,6 +12,8 @@ const image = {
poster: '../images/loader.gif',
delete: '../images/delete.png',
locked: '../images/locked.png',
mute: '../images/mute.png',
hide: '../images/hide.png',
};
const mediaType = {
@@ -28,6 +30,8 @@ const _EVENTS = {
pauseRec: 'pauseRec',
resumeRec: 'resumeRec',
stopRec: 'stopRec',
raiseHand: 'raiseHand',
lowerHand: 'lowerHand',
startVideo: 'startVideo',
pauseVideo: 'pauseVideo',
resumeVideo: 'resumeVideo',
@@ -381,6 +385,14 @@ class RoomClient {
}.bind(this),
);
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);
}.bind(this),
);
this.socket.on(
'disconnect',
function () {
@@ -606,7 +618,7 @@ class RoomClient {
let elem, d, p;
d = document.createElement('div');
d.className = 'Camera';
d.id = id + '_d';
d.id = id + '__d';
elem = document.createElement('video');
elem.setAttribute('id', id);
elem.setAttribute('playsinline', true);
@@ -614,7 +626,7 @@ class RoomClient {
elem.poster = image.poster;
this.isMobileDevice || type === mediaType.screen ? (elem.className = '') : (elem.className = 'mirror');
p = document.createElement('p');
p.id = id + '_name';
p.id = id + '__name';
p.innerHTML = '👤 ' + this.peer_name + ' (me)';
d.appendChild(elem);
d.appendChild(p);
@@ -684,11 +696,16 @@ class RoomClient {
}
let producer_id = this.producerLabel.get(type);
console.log('Close producer', producer_id);
this.socket.emit('producerClosed', {
producer_id,
});
let data = {
peer_name: this.peer_name,
producer_id: producer_id,
type: type,
status: false,
};
console.log('Close producer', data);
this.socket.emit('producerClosed', data);
this.producers.get(producer_id).close();
this.producers.delete(producer_id);
@@ -696,7 +713,7 @@ class RoomClient {
if (type !== mediaType.audio) {
let elem = this.getId(producer_id);
let d = this.getId(producer_id + '_d');
let d = this.getId(producer_id + '__d');
elem.srcObject.getTracks().forEach(function (track) {
track.stop();
});
@@ -786,7 +803,7 @@ class RoomClient {
case mediaType.video:
d = document.createElement('div');
d.className = 'Camera';
d.id = id + '_d';
d.id = id + '__d';
elem = document.createElement('video');
elem.setAttribute('id', id);
elem.setAttribute('playsinline', true);
@@ -794,7 +811,7 @@ class RoomClient {
elem.className = '';
elem.poster = image.poster;
p = document.createElement('p');
p.id = id + '_name';
p.id = id + '__name';
p.innerHTML = '👤 ' + peer_name;
d.appendChild(elem);
d.appendChild(p);
@@ -819,7 +836,7 @@ class RoomClient {
removeConsumer(consumer_id) {
let elem = this.getId(consumer_id);
let d = this.getId(consumer_id + '_d');
let d = this.getId(consumer_id + '__d');
elem.srcObject.getTracks().forEach(function (track) {
track.stop();
@@ -980,13 +997,13 @@ class RoomClient {
}
}
userLog(icon, message, position) {
userLog(icon, message, position, timer = 5000) {
const Toast = Swal.mixin({
background: swalBackground,
toast: true,
position: position,
showConfirmButton: false,
timer: 5000,
timer: timer,
});
Toast.fire({
icon: icon,
@@ -1436,45 +1453,136 @@ class RoomClient {
// PEER ACTION
// ####################################################
peerAction(from_peer_name, peer_id, action, emit = true) {
switch (action) {
case 'eject':
let peer = this.getId(peer_id);
if (peer) peer.parentNode.removeChild(peer);
if (peer_id === this.peer_id) {
this.sound(action);
let timerInterval;
Swal.fire({
allowOutsideClick: false,
background: swalBackground,
title: from_peer_name,
html: 'Will eject you from the room after <b style="color: red;"></b> milliseconds.',
timer: 5000,
timerProgressBar: true,
didOpen: () => {
Swal.showLoading();
const b = Swal.getHtmlContainer().querySelector('b');
timerInterval = setInterval(() => {
b.textContent = Swal.getTimerLeft();
}, 100);
},
willClose: () => {
clearInterval(timerInterval);
},
}).then(() => {
this.exit();
});
}
break;
// ...
}
peerAction(from_peer_name, id, action, emit = true, broadcast = false) {
let peer_id = id;
if (emit) {
const words = peer_id.split('__');
peer_id = words[0];
switch (action) {
case 'eject':
let peer = this.getId(peer_id);
if (peer) peer.parentNode.removeChild(peer);
break;
case 'mute':
let peerAudioButton = this.getId(peer_id + '__audio');
if (peerAudioButton) peerAudioButton.innerHTML = _PEER.audioOff;
break;
case 'hide':
let peerVideoButton = this.getId(peer_id + '__video');
if (peerVideoButton) peerVideoButton.innerHTML = _PEER.videoOff;
}
let data = {
from_peer_name: this.peer_name,
peer_id: peer_id,
action: action,
broadcast: broadcast,
};
this.socket.emit('peerAction', data);
} else {
switch (action) {
case 'eject':
if (peer_id === this.peer_id) {
this.sound(action);
let timerInterval;
Swal.fire({
allowOutsideClick: false,
background: swalBackground,
title: from_peer_name,
html: 'Will eject you from the room after <b style="color: red;"></b> milliseconds.',
timer: 5000,
timerProgressBar: true,
didOpen: () => {
Swal.showLoading();
const b = Swal.getHtmlContainer().querySelector('b');
timerInterval = setInterval(() => {
b.textContent = Swal.getTimerLeft();
}, 100);
},
willClose: () => {
clearInterval(timerInterval);
},
}).then(() => {
this.exit();
});
}
break;
case 'mute':
if (peer_id === this.peer_id) {
this.closeProducer(mediaType.audio);
this.userLog(
'warning',
from_peer_name + ' ' + _PEER.audioOff + ' has closed yours audio',
'top-end',
10000,
);
}
break;
case 'hide':
if (peer_id === this.peer_id) {
this.closeProducer(mediaType.video);
this.userLog(
'warning',
from_peer_name + ' ' + _PEER.videoOff + ' has closed yours video',
'top-end',
10000,
);
}
break;
// ...
}
}
}
// ####################################################
// UPDATE PEER INFO
// ####################################################
updatePeerInfo(peer_name, peer_id, type, status, emit = true) {
if (emit) {
switch (type) {
case 'audio':
this.peer_info.peer_audio = status;
break;
case 'video':
this.peer_info.peer_video = status;
break;
case 'hand':
this.peer_info.peer_hand = status;
if (status) {
this.event(_EVENTS.raiseHand);
this.sound('raiseHand');
} else {
this.event(_EVENTS.lowerHand);
}
break;
}
let data = {
peer_name: peer_name,
peer_id: peer_id,
type: type,
status: status,
};
this.socket.emit('updatePeerInfo', data);
} else {
switch (type) {
case 'audio':
break;
case 'video':
break;
case 'hand':
if (status)
this.userLog(
'warning',
peer_name + ' ' + _PEER.raiseHand + ' has raised the hand',
'top-end',
10000,
);
this.sound('raiseHand');
break;
}
}
}
@@ -1488,6 +1596,7 @@ class RoomClient {
'peer_name',
'peer_audio',
'peer_video',
'peer_hand',
'is_mobile_device',
'os_name',
'os_version',

ثنائية
public/sounds/raiseHand.wav Normal file

ملف ثنائي غير معروض.