[mirotalk] - refactoring live caption feature
This commit is contained in:
+2
-9
@@ -221,7 +221,7 @@ function getMeetingURL(host) {
|
||||
// end of MiroTalk API v1
|
||||
|
||||
// not match any of page before, so 404 not found
|
||||
app.get('*', function(req, res) {
|
||||
app.get('*', function (req, res) {
|
||||
res.sendFile(path.join(__dirname, '../../', 'public/view/404.html'));
|
||||
});
|
||||
|
||||
@@ -695,13 +695,6 @@ io.sockets.on('connect', (socket) => {
|
||||
let room_id = config.room_id;
|
||||
sendToRoom(room_id, socket.id, 'whiteboardAction', config);
|
||||
});
|
||||
|
||||
// for live subtitle or transcripts
|
||||
socket.on('speech_transcript', (config) => {
|
||||
log.debug(config);
|
||||
let room_id = config.room_id;
|
||||
sendToRoom(room_id, socket.id, 'speech_transcript', config);
|
||||
});
|
||||
}); // end [sockets.on-connect]
|
||||
|
||||
/**
|
||||
@@ -731,4 +724,4 @@ async function sendToPeer(peer_id, sockets, msg, config = {}) {
|
||||
if (peer_id in sockets) {
|
||||
await sockets[peer_id].emit(msg, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,7 +982,9 @@ video:fullscreen {
|
||||
#myPeerNameSetBtn,
|
||||
#muteEveryoneBtn,
|
||||
#hideEveryoneBtn,
|
||||
#lockUnlockRoomBtn {
|
||||
#lockUnlockRoomBtn,
|
||||
#speechRecognitionStart,
|
||||
#speechRecognitionStop {
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
@@ -990,7 +992,9 @@ video:fullscreen {
|
||||
}
|
||||
|
||||
#myPeerNameSetBtn:hover,
|
||||
#lockUnlockRoomBtn:hover {
|
||||
#lockUnlockRoomBtn:hover,
|
||||
#speechRecognitionStart:hover,
|
||||
#speechRecognitionStop:hover {
|
||||
color: var(--hover-color);
|
||||
transform: var(--btns-hover-scale);
|
||||
transition: all 0.3s ease-in-out;
|
||||
@@ -1007,7 +1011,7 @@ video:fullscreen {
|
||||
.tab {
|
||||
overflow: hidden;
|
||||
border: 1px solid rgb(0, 0, 0);
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
background-color: rgba(0, 0, 0);
|
||||
}
|
||||
|
||||
/* Style the buttons inside the tab */
|
||||
@@ -1031,7 +1035,7 @@ video:fullscreen {
|
||||
|
||||
/* Create an active/current tablink class */
|
||||
.tab button.active {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
background-color: rgb(30 29 29);
|
||||
}
|
||||
|
||||
/* Style the tab content */
|
||||
|
||||
+205
-131
@@ -85,7 +85,7 @@ let myVideoStatus = true;
|
||||
let myAudioStatus = true;
|
||||
let isScreenStreaming = false;
|
||||
let isChatRoomVisible = false;
|
||||
let isCaptionBoxVisible = false; //added for caption button
|
||||
let isCaptionBoxVisible = false;
|
||||
let isChatEmojiVisible = false;
|
||||
let isButtonsVisible = false;
|
||||
let isMySettingsVisible = false;
|
||||
@@ -134,7 +134,7 @@ let screenShareBtn;
|
||||
let recordStreamBtn;
|
||||
let fullScreenBtn;
|
||||
let chatRoomBtn;
|
||||
let captionBtn; //for text transcript
|
||||
let captionBtn;
|
||||
let myHandBtn;
|
||||
let whiteboardBtn;
|
||||
let fileShareBtn;
|
||||
@@ -188,6 +188,8 @@ let screenFpsSelect;
|
||||
let themeSelect;
|
||||
let btnsBarSelect;
|
||||
let selectors;
|
||||
let speechRecognitionStart;
|
||||
let speechRecognitionStop;
|
||||
// my video element
|
||||
let myVideo;
|
||||
let myVideoWrap;
|
||||
@@ -270,7 +272,7 @@ function getHtmlElementsById() {
|
||||
screenShareBtn = getId('screenShareBtn');
|
||||
recordStreamBtn = getId('recordStreamBtn');
|
||||
fullScreenBtn = getId('fullScreenBtn');
|
||||
captionBtn = getId('captionBtn'); //for getting caption buttons
|
||||
captionBtn = getId('captionBtn');
|
||||
chatRoomBtn = getId('chatRoomBtn');
|
||||
whiteboardBtn = getId('whiteboardBtn');
|
||||
fileShareBtn = getId('fileShareBtn');
|
||||
@@ -324,6 +326,8 @@ function getHtmlElementsById() {
|
||||
screenFpsSelect = getId('screenFps');
|
||||
themeSelect = getId('mirotalkTheme');
|
||||
btnsBarSelect = getId('mirotalkBtnsBar');
|
||||
speechRecognitionStart = getId('speechRecognitionStart');
|
||||
speechRecognitionStop = getId('speechRecognitionStop');
|
||||
// my conference name, hand, video - audio status
|
||||
myVideoParagraph = getId('myVideoParagraph');
|
||||
myHandStatusIcon = getId('myHandStatusIcon');
|
||||
@@ -401,9 +405,8 @@ function setButtonsTitle() {
|
||||
content: 'OPEN the chat',
|
||||
placement: 'right-start',
|
||||
});
|
||||
//for hover pop-over
|
||||
tippy(captionBtn, {
|
||||
content: 'See Caption',
|
||||
content: 'OPEN the caption',
|
||||
placement: 'right-start',
|
||||
});
|
||||
tippy(myHandBtn, {
|
||||
@@ -445,7 +448,7 @@ function setButtonsTitle() {
|
||||
content: 'Save messages',
|
||||
});
|
||||
tippy(msgerClose, {
|
||||
content: 'Close the chat',
|
||||
content: 'Close',
|
||||
});
|
||||
tippy(msgerEmojiBtn, {
|
||||
content: 'Emoji',
|
||||
@@ -454,6 +457,20 @@ function setButtonsTitle() {
|
||||
content: 'Send',
|
||||
});
|
||||
|
||||
// caption buttons
|
||||
tippy(captionTheme, {
|
||||
content: 'Ghost theme',
|
||||
});
|
||||
tippy(captionClean, {
|
||||
content: 'Clean messages',
|
||||
});
|
||||
tippy(captionSaveBtn, {
|
||||
content: 'Save messages',
|
||||
});
|
||||
tippy(msgerClose, {
|
||||
content: 'Close',
|
||||
});
|
||||
|
||||
// settings
|
||||
tippy(mySettingsCloseBtn, {
|
||||
content: 'Close settings',
|
||||
@@ -462,6 +479,20 @@ function setButtonsTitle() {
|
||||
content: 'Change name',
|
||||
});
|
||||
|
||||
// tab btns
|
||||
tippy(tabDevicesBtn, {
|
||||
content: 'Devices',
|
||||
});
|
||||
tippy(tabBandwidthBtn, {
|
||||
content: 'Bandwidth',
|
||||
});
|
||||
tippy(tabRoomBtn, {
|
||||
content: 'Room',
|
||||
});
|
||||
tippy(tabStylingBtn, {
|
||||
content: 'Styling',
|
||||
});
|
||||
|
||||
// whiteboard btns
|
||||
tippy(wbDrawingColorEl, {
|
||||
content: 'DRAWING color',
|
||||
@@ -687,7 +718,6 @@ function initClientPeer() {
|
||||
signalingSocket.on('videoPlayer', handleVideoPlayer);
|
||||
signalingSocket.on('disconnect', handleDisconnect);
|
||||
signalingSocket.on('removePeer', handleRemovePeer);
|
||||
signalingSocket.on('speech_transcript', handleSpeechTranscript);
|
||||
} // end [initClientPeer]
|
||||
|
||||
/**
|
||||
@@ -703,7 +733,7 @@ async function sendToServer(msg, config = {}) {
|
||||
* Connected to Signaling Server. Once the user has given us access to their
|
||||
* microphone/cam, join the channel and start peering up
|
||||
*/
|
||||
function handleConnect(socket) {
|
||||
function handleConnect() {
|
||||
console.log('Connected to signaling server');
|
||||
if (localMediaStream) joinToChannel();
|
||||
else
|
||||
@@ -828,7 +858,8 @@ function welcomeUser() {
|
||||
title: '<strong>Welcome ' + myPeerName + '</strong>',
|
||||
imageAlt: 'mirotalk-welcome',
|
||||
imageUrl: welcomeImg,
|
||||
html: `
|
||||
html:
|
||||
`
|
||||
<br/>
|
||||
<p style="color:white;">Share this meeting invite others to join.</p>
|
||||
<p style="color:rgb(8, 189, 89);">` +
|
||||
@@ -959,9 +990,16 @@ function handleRTCDataChannels(peer_id) {
|
||||
case 'mirotalk_chat_channel':
|
||||
try {
|
||||
let dataMessage = JSON.parse(msg.data);
|
||||
handleDataChannelChat(dataMessage);
|
||||
switch (dataMessage.type) {
|
||||
case 'chat':
|
||||
handleDataChannelChat(dataMessage);
|
||||
break;
|
||||
case 'speech':
|
||||
handleDataChannelSpeechTranscript(dataMessage);
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('handleDataChannelChat', err);
|
||||
console.error('mirotalk_chat_channel', err);
|
||||
}
|
||||
break;
|
||||
case 'mirotalk_file_sharing_channel':
|
||||
@@ -969,7 +1007,7 @@ function handleRTCDataChannels(peer_id) {
|
||||
let dataFile = msg.data;
|
||||
handleDataChannelFileSharing(dataFile);
|
||||
} catch (err) {
|
||||
console.error('handleDataChannelFS', err);
|
||||
console.error('mirotalk_file_sharing_channel', err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1245,7 +1283,7 @@ function setTheme(theme) {
|
||||
document.documentElement.style.setProperty('--private-msg-bg', 'rgba(252, 110, 110, 0.7)');
|
||||
document.documentElement.style.setProperty('--right-msg-bg', 'rgba(0, 0, 0, 0.7)');
|
||||
break;
|
||||
// ...
|
||||
// ...
|
||||
default:
|
||||
console.log('No theme found');
|
||||
}
|
||||
@@ -1822,6 +1860,7 @@ function manageLeftButtons() {
|
||||
setRecordStreamBtn();
|
||||
setFullScreenBtn();
|
||||
setChatRoomBtn();
|
||||
setCaptionRoomBtn();
|
||||
setChatEmojiBtn();
|
||||
setMyHandBtn();
|
||||
setMyWhiteboardBtn();
|
||||
@@ -1836,7 +1875,7 @@ function manageLeftButtons() {
|
||||
* Copy - share room url button click event
|
||||
*/
|
||||
function setShareRoomBtn() {
|
||||
shareRoomBtn.addEventListener('click', async(e) => {
|
||||
shareRoomBtn.addEventListener('click', async (e) => {
|
||||
shareRoomUrl();
|
||||
});
|
||||
}
|
||||
@@ -1934,7 +1973,7 @@ function setFullScreenBtn() {
|
||||
*/
|
||||
function setChatRoomBtn() {
|
||||
// adapt chat room size for mobile
|
||||
setChatRoomForMobile();
|
||||
setChatRoomAndCaptionForMobile();
|
||||
|
||||
// open hide chat room
|
||||
chatRoomBtn.addEventListener('click', (e) => {
|
||||
@@ -1959,19 +1998,6 @@ function setChatRoomBtn() {
|
||||
}
|
||||
});
|
||||
|
||||
// ghost theme + undo
|
||||
captionTheme.addEventListener('click', (e) => {
|
||||
if (mirotalkTheme == 'ghost') return;
|
||||
|
||||
if (e.target.className == 'fas fa-ghost') {
|
||||
e.target.className = 'fas fa-undo';
|
||||
document.documentElement.style.setProperty('--msger-bg', 'rgba(0, 0, 0, 0.100)');
|
||||
} else {
|
||||
e.target.className = 'fas fa-ghost';
|
||||
document.documentElement.style.setProperty('--msger-bg', 'linear-gradient(to left, #383838, #000000)');
|
||||
}
|
||||
});
|
||||
|
||||
// show msger participants section
|
||||
msgerCPBtn.addEventListener('click', (e) => {
|
||||
if (!thereIsPeerConnections()) {
|
||||
@@ -1991,11 +2017,6 @@ function setChatRoomBtn() {
|
||||
cleanMessages();
|
||||
});
|
||||
|
||||
// clean caption transcripts
|
||||
captionClean.addEventListener('click', (e) => {
|
||||
cleanCaptions();
|
||||
});
|
||||
|
||||
// save chat messages to file
|
||||
msgerSaveBtn.addEventListener('click', (e) => {
|
||||
if (chatMessages.length != 0) {
|
||||
@@ -2005,37 +2026,12 @@ function setChatRoomBtn() {
|
||||
userLog('info', 'No chat messages to save');
|
||||
});
|
||||
|
||||
// save caption transcripts to file
|
||||
captionSaveBtn.addEventListener('click', (e) => {
|
||||
if (transcripts.length != 0) {
|
||||
downloadCaptions();
|
||||
return;
|
||||
}
|
||||
userLog('info', 'No captions to save');
|
||||
});
|
||||
|
||||
// open hide chat room
|
||||
captionBtn.addEventListener('click', (e) => {
|
||||
if (!isCaptionBoxVisible) {
|
||||
showCaptionDraggable();
|
||||
} else {
|
||||
//hideChatRoomAndEmojiPicker();
|
||||
e.target.className = 'fas fa-closed-captioning';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// close chat room - show left button and status menu if hide
|
||||
msgerClose.addEventListener('click', (e) => {
|
||||
hideChatRoomAndEmojiPicker();
|
||||
showButtonsBarAndMenu();
|
||||
});
|
||||
|
||||
// close caption box - show left button and status menu if hide
|
||||
captionClose.addEventListener('click', (e) => {
|
||||
hideCaptionBox();
|
||||
showButtonsBarAndMenu();
|
||||
});
|
||||
// open Video Url Player
|
||||
msgerVideoUrlBtn.addEventListener('click', (e) => {
|
||||
sendVideoUrl();
|
||||
@@ -2051,7 +2047,7 @@ function setChatRoomBtn() {
|
||||
});
|
||||
|
||||
// on input check 4emoji from map
|
||||
msgerInput.oninput = function() {
|
||||
msgerInput.oninput = function () {
|
||||
for (let i in chatInputEmoji) {
|
||||
let regex = new RegExp(escapeSpecialChars(i), 'gim');
|
||||
this.value = this.value.replace(regex, chatInputEmoji[i]);
|
||||
@@ -2066,6 +2062,70 @@ function setChatRoomBtn() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Caption room buttons click event
|
||||
*/
|
||||
function setCaptionRoomBtn() {
|
||||
if ('webkitSpeechRecognition' in window) {
|
||||
// open hide caption
|
||||
captionBtn.addEventListener('click', (e) => {
|
||||
if (!isCaptionBoxVisible) {
|
||||
showCaptionDraggable();
|
||||
} else {
|
||||
hideCaptionBox();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
captionBtn.style.display = 'none';
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API#browser_compatibility
|
||||
}
|
||||
|
||||
// ghost theme + undo
|
||||
captionTheme.addEventListener('click', (e) => {
|
||||
if (mirotalkTheme == 'ghost') return;
|
||||
|
||||
if (e.target.className == 'fas fa-ghost') {
|
||||
e.target.className = 'fas fa-undo';
|
||||
document.documentElement.style.setProperty('--msger-bg', 'rgba(0, 0, 0, 0.100)');
|
||||
} else {
|
||||
e.target.className = 'fas fa-ghost';
|
||||
document.documentElement.style.setProperty('--msger-bg', 'linear-gradient(to left, #383838, #000000)');
|
||||
}
|
||||
});
|
||||
|
||||
// clean caption transcripts
|
||||
captionClean.addEventListener('click', (e) => {
|
||||
cleanCaptions();
|
||||
});
|
||||
|
||||
// save caption transcripts to file
|
||||
captionSaveBtn.addEventListener('click', (e) => {
|
||||
if (transcripts.length != 0) {
|
||||
downloadCaptions();
|
||||
return;
|
||||
}
|
||||
userLog('info', 'No captions to save');
|
||||
});
|
||||
|
||||
// close caption box - show left button and status menu if hide
|
||||
captionClose.addEventListener('click', (e) => {
|
||||
hideCaptionBox();
|
||||
showButtonsBarAndMenu();
|
||||
});
|
||||
|
||||
// hide it
|
||||
speechRecognitionStop.style.display = 'none';
|
||||
|
||||
// start recognition speech
|
||||
speechRecognitionStart.addEventListener('click', (e) => {
|
||||
startSpeech(true);
|
||||
});
|
||||
// stop recognition speech
|
||||
speechRecognitionStop.addEventListener('click', (e) => {
|
||||
startSpeech(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Emoji picker chat room button click event
|
||||
*/
|
||||
@@ -2088,7 +2148,7 @@ function setChatEmojiBtn() {
|
||||
* Set my hand button click event
|
||||
*/
|
||||
function setMyHandBtn() {
|
||||
myHandBtn.addEventListener('click', async(e) => {
|
||||
myHandBtn.addEventListener('click', async (e) => {
|
||||
setMyHandStatus();
|
||||
});
|
||||
}
|
||||
@@ -2376,10 +2436,10 @@ function getVideoConstraints(videoQuality) {
|
||||
switch (videoQuality) {
|
||||
case 'useVideo':
|
||||
return useVideo;
|
||||
// Firefox not support set frameRate (OverconstrainedError) O.o
|
||||
// Firefox not support set frameRate (OverconstrainedError) O.o
|
||||
case 'default':
|
||||
return { frameRate: frameRate };
|
||||
// video cam constraints default
|
||||
// video cam constraints default
|
||||
case 'qvgaVideo':
|
||||
return {
|
||||
width: { exact: 320 },
|
||||
@@ -2581,7 +2641,13 @@ function attachMediaStream(element, stream) {
|
||||
* if mobile and mySettings open do nothing return
|
||||
*/
|
||||
function showButtonsBarAndMenu() {
|
||||
if (isButtonsVisible || (isMobileDevice && isChatRoomVisible) || (isMobileDevice && isMySettingsVisible)) return;
|
||||
if (
|
||||
isButtonsVisible ||
|
||||
(isMobileDevice && isChatRoomVisible) ||
|
||||
(isMobileDevice && isCaptionBoxVisible) ||
|
||||
(isMobileDevice && isMySettingsVisible)
|
||||
)
|
||||
return;
|
||||
toggleClassElements('statusMenu', 'inline');
|
||||
buttonsBar.style.display = 'flex';
|
||||
isButtonsVisible = true;
|
||||
@@ -2628,7 +2694,8 @@ async function shareRoomUrl() {
|
||||
title: 'Share the Room',
|
||||
// imageAlt: 'mirotalk-share',
|
||||
// imageUrl: shareUrlImg,
|
||||
html: `
|
||||
html:
|
||||
`
|
||||
<br/>
|
||||
<div id="qrRoomContainer">
|
||||
<canvas id="qrRoom"></canvas>
|
||||
@@ -2716,9 +2783,9 @@ function handleAudio(e, init, force = null) {
|
||||
localMediaStream.getAudioTracks()[0].enabled =
|
||||
force != null ? force : !localMediaStream.getAudioTracks()[0].enabled;
|
||||
myAudioStatus = localMediaStream.getAudioTracks()[0].enabled;
|
||||
force != null ?
|
||||
(e.className = 'fas fa-microphone' + (myAudioStatus ? '' : '-slash')) :
|
||||
(e.target.className = 'fas fa-microphone' + (myAudioStatus ? '' : '-slash'));
|
||||
force != null
|
||||
? (e.className = 'fas fa-microphone' + (myAudioStatus ? '' : '-slash'))
|
||||
: (e.target.className = 'fas fa-microphone' + (myAudioStatus ? '' : '-slash'));
|
||||
if (init) {
|
||||
audioBtn.className = 'fas fa-microphone' + (myAudioStatus ? '' : '-slash');
|
||||
if (!isMobileDevice) {
|
||||
@@ -2729,12 +2796,6 @@ function handleAudio(e, init, force = null) {
|
||||
}
|
||||
}
|
||||
setMyAudioStatus(myAudioStatus);
|
||||
if (myAudioStatus) {
|
||||
start_stop_speech(true); //speech to text transcript function
|
||||
} else {
|
||||
start_stop_speech(false); //speech to text transcript function
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2747,9 +2808,9 @@ function handleVideo(e, init, force = null) {
|
||||
localMediaStream.getVideoTracks()[0].enabled =
|
||||
force != null ? force : !localMediaStream.getVideoTracks()[0].enabled;
|
||||
myVideoStatus = localMediaStream.getVideoTracks()[0].enabled;
|
||||
force != null ?
|
||||
(e.className = 'fas fa-video' + (myVideoStatus ? '' : '-slash')) :
|
||||
(e.target.className = 'fas fa-video' + (myVideoStatus ? '' : '-slash'));
|
||||
force != null
|
||||
? (e.className = 'fas fa-video' + (myVideoStatus ? '' : '-slash'))
|
||||
: (e.target.className = 'fas fa-video' + (myVideoStatus ? '' : '-slash'));
|
||||
if (init) {
|
||||
videoBtn.className = 'fas fa-video' + (myVideoStatus ? '' : '-slash');
|
||||
if (!isMobileDevice) {
|
||||
@@ -3198,13 +3259,15 @@ function createChatDataChannel(peer_id) {
|
||||
/**
|
||||
* Set the chat room on full screen mode for mobile
|
||||
*/
|
||||
function setChatRoomForMobile() {
|
||||
function setChatRoomAndCaptionForMobile() {
|
||||
if (isMobileDevice) {
|
||||
document.documentElement.style.setProperty('--msger-height', '99%');
|
||||
document.documentElement.style.setProperty('--msger-width', '99%');
|
||||
} else {
|
||||
// make chat room draggable for desktop
|
||||
dragElement(msgerDraggable, msgerHeader);
|
||||
// make caption draggable for desktop
|
||||
dragElement(captionDraggable, captionHeader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3231,7 +3294,6 @@ function showChatRoomDraggable() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show caption box draggable on center screen position
|
||||
*/
|
||||
@@ -3318,8 +3380,6 @@ function cleanCaptions() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Hide chat room and emoji picker
|
||||
*/
|
||||
@@ -3343,14 +3403,12 @@ function hideChatRoomAndEmojiPicker() {
|
||||
*/
|
||||
function hideCaptionBox() {
|
||||
captionDraggable.style.display = 'none';
|
||||
msgerEmojiPicker.style.display = 'none';
|
||||
captionBtn.className = 'far fa-closed-captioning';
|
||||
captionBtn.className = 'fas fa-closed-captioning';
|
||||
isCaptionBoxVisible = false;
|
||||
isChatEmojiVisible = false;
|
||||
// only for desktop
|
||||
if (!isMobileDevice) {
|
||||
tippy(captionBtn, {
|
||||
content: 'OPEN the caption box',
|
||||
content: 'OPEN the caption',
|
||||
placement: 'right-start',
|
||||
});
|
||||
}
|
||||
@@ -3401,6 +3459,49 @@ function handleDataChannelChat(dataMessage) {
|
||||
appendMessage(msgFrom, leftChatAvatar, 'left', msg, msgPrivate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle text transcipt getting from peers
|
||||
* @param {*} config
|
||||
*/
|
||||
function handleDataChannelSpeechTranscript(config) {
|
||||
handleSpeechTranscript(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle text transcipt getting from peers
|
||||
* @param {*} data
|
||||
*/
|
||||
function handleSpeechTranscript(config) {
|
||||
if (!config) return;
|
||||
|
||||
let time_stamp = getFormatDate(new Date());
|
||||
let name = config.peer_name;
|
||||
let avatar_image = avatarApiUrl + '?name=' + name + '&size=32' + '&background=random&rounded=true';
|
||||
let transcipt = config.text_data;
|
||||
|
||||
console.log('Handle speech transcript', config);
|
||||
|
||||
const msgHTML = `
|
||||
<div class="msg left-msg">
|
||||
<div class="msg-img" style="background-image: url('${avatar_image}')"></div>
|
||||
<div>
|
||||
<div class="msg-info">
|
||||
<div class="msg-info-name" style="color:white;">${name} : ${time_stamp}</div>
|
||||
</div>
|
||||
<div class="msg-text" style="color:white;">${transcipt}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
captionChat.insertAdjacentHTML('beforeend', msgHTML);
|
||||
captionChat.scrollTop += 500;
|
||||
transcripts.push({
|
||||
time: time_stamp,
|
||||
name: name,
|
||||
caption: transcipt,
|
||||
});
|
||||
playSound('speech');
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape Special Chars
|
||||
* @param {*} regex
|
||||
@@ -3578,6 +3679,7 @@ function emitMsg(from, to, msg, privateMsg) {
|
||||
if (!msg) return;
|
||||
|
||||
let chatMessage = {
|
||||
type: 'chat',
|
||||
from: from,
|
||||
to: to,
|
||||
msg: msg,
|
||||
@@ -4050,8 +4152,10 @@ function disableAllPeers(element) {
|
||||
position: 'center',
|
||||
imageUrl: element == 'audio' ? audioOffImg : camOffImg,
|
||||
title: element == 'audio' ? 'Mute everyone except yourself?' : 'Hide everyone except yourself?',
|
||||
text: element == 'audio' ?
|
||||
"Once muted, you won't be able to unmute them, but they can unmute themselves at any time." : "Once hided, you won't be able to unhide them, but they can unhide themselves at any time.",
|
||||
text:
|
||||
element == 'audio'
|
||||
? "Once muted, you won't be able to unmute them, but they can unmute themselves at any time."
|
||||
: "Once hided, you won't be able to unhide them, but they can unhide themselves at any time.",
|
||||
showDenyButton: true,
|
||||
confirmButtonText: element == 'audio' ? `Mute` : `Hide`,
|
||||
denyButtonText: `Cancel`,
|
||||
@@ -4092,8 +4196,10 @@ function disablePeer(peer_id, element) {
|
||||
position: 'center',
|
||||
imageUrl: element == 'audio' ? audioOffImg : camOffImg,
|
||||
title: element == 'audio' ? 'Mute this participant?' : 'Hide this participant?',
|
||||
text: element == 'audio' ?
|
||||
"Once muted, you won't be able to unmute them, but they can unmute themselves at any time." : "Once hided, you won't be able to unhide them, but they can unhide themselves at any time.",
|
||||
text:
|
||||
element == 'audio'
|
||||
? "Once muted, you won't be able to unmute them, but they can unmute themselves at any time."
|
||||
: "Once hided, you won't be able to unhide them, but they can unhide themselves at any time.",
|
||||
showDenyButton: true,
|
||||
confirmButtonText: element == 'audio' ? `Mute` : `Hide`,
|
||||
denyButtonText: `Cancel`,
|
||||
@@ -4314,7 +4420,7 @@ function whiteboardAddObj(type) {
|
||||
if (result.isConfirmed) {
|
||||
let wbCanvasImgURL = result.value;
|
||||
if (isImageURL(wbCanvasImgURL)) {
|
||||
fabric.Image.fromURL(wbCanvasImgURL, function(myImg) {
|
||||
fabric.Image.fromURL(wbCanvasImgURL, function (myImg) {
|
||||
addWbCanvasObj(myImg);
|
||||
});
|
||||
} else {
|
||||
@@ -4342,10 +4448,10 @@ function whiteboardAddObj(type) {
|
||||
let wbCanvasImg = result.value;
|
||||
if (wbCanvasImg && wbCanvasImg.size > 0) {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
reader.onload = function (event) {
|
||||
let imgObj = new Image();
|
||||
imgObj.src = event.target.result;
|
||||
imgObj.onload = function() {
|
||||
imgObj.onload = function () {
|
||||
let image = new fabric.Image(imgObj);
|
||||
image.set({ top: 0, left: 0 }).scale(0.3);
|
||||
addWbCanvasObj(image);
|
||||
@@ -4432,16 +4538,16 @@ function addWbCanvasObj(obj) {
|
||||
* Whiteboard: Local listners
|
||||
*/
|
||||
function setupWhiteboardLocalListners() {
|
||||
wbCanvas.on('mouse:down', function(e) {
|
||||
wbCanvas.on('mouse:down', function (e) {
|
||||
mouseDown(e);
|
||||
});
|
||||
wbCanvas.on('mouse:up', function() {
|
||||
wbCanvas.on('mouse:up', function () {
|
||||
mouseUp();
|
||||
});
|
||||
wbCanvas.on('mouse:move', function() {
|
||||
wbCanvas.on('mouse:move', function () {
|
||||
mouseMove();
|
||||
});
|
||||
wbCanvas.on('object:added', function() {
|
||||
wbCanvas.on('object:added', function () {
|
||||
objectAdded();
|
||||
});
|
||||
}
|
||||
@@ -4662,7 +4768,7 @@ function handleWhiteboardAction(config, logme = true) {
|
||||
case 'toggle':
|
||||
toggleWhiteboard();
|
||||
break;
|
||||
//...
|
||||
//...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5133,7 +5239,8 @@ function handleKickedOut(config) {
|
||||
position: 'center',
|
||||
imageUrl: kickedOutImg,
|
||||
title: 'Kicked out!',
|
||||
html: `<h2 style="color: red;">` +
|
||||
html:
|
||||
`<h2 style="color: red;">` +
|
||||
`User ` +
|
||||
peer_name +
|
||||
`</h2> will kick out you after <b style="color: red;"></b> milliseconds.`,
|
||||
@@ -5371,7 +5478,7 @@ function userLog(type, message) {
|
||||
title: message,
|
||||
});
|
||||
break;
|
||||
// ......
|
||||
// ......
|
||||
default:
|
||||
alert(message);
|
||||
}
|
||||
@@ -5429,36 +5536,3 @@ function getSl(selector) {
|
||||
function getEcN(className) {
|
||||
return document.getElementsByClassName(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle text transcipt getting from peers
|
||||
* @param {*} data
|
||||
*/
|
||||
function handleSpeechTranscript(config) {
|
||||
let peer_id = config.peer_id;
|
||||
let time_stamp = getFormatDate(new Date());;
|
||||
let name = config.peer_name;
|
||||
let avatar_image = avatarApiUrl + '?name=' + name + '&size=32' + '&background=random&rounded=true';
|
||||
let transcipt = config.text_data;
|
||||
console.log(config);
|
||||
|
||||
const msgHTML = `
|
||||
<div class="msg left-msg">
|
||||
<div class="msg-img" style="background-image: url('${avatar_image}')"></div>
|
||||
<div>
|
||||
<div class="msg-info">
|
||||
<div class="msg-info-name" style="color:white;">${name}</div>
|
||||
<div class="msg-info-time" style="color:white;">${time_stamp}</div>
|
||||
</div>
|
||||
<div class="msg-text" style="color:white;">${transcipt}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
captionChat.insertAdjacentHTML('beforeend', msgHTML);
|
||||
captionChat.scrollTop += 500;
|
||||
transcripts.push({
|
||||
time: time_stamp,
|
||||
name: name,
|
||||
caption: transcipt,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API
|
||||
*/
|
||||
let isWebkitSpeechRecognitionSupported = false;
|
||||
let recognitionRunning = false;
|
||||
let recognition;
|
||||
|
||||
if ('webkitSpeechRecognition' in window) {
|
||||
recognition = new webkitSpeechRecognition();
|
||||
recognition.maxAlternatives = 1;
|
||||
recognition.continuous = true;
|
||||
|
||||
recognition.onstart = function () {
|
||||
console.log('Start speech recognition');
|
||||
speechRecognitionStart.style.display = 'none';
|
||||
speechRecognitionStop.style.display = 'block';
|
||||
};
|
||||
|
||||
// Detect the said words
|
||||
recognition.onresult = (e) => {
|
||||
let current = e.resultIndex;
|
||||
// Get a transcript of what was said.
|
||||
let transcript = e.results[current][0].transcript;
|
||||
config = {
|
||||
type: 'speech',
|
||||
room_id: roomId,
|
||||
peer_name: myPeerName,
|
||||
text_data: transcript,
|
||||
time_stamp: new Date(),
|
||||
};
|
||||
// save also my speech to text
|
||||
handleSpeechTranscript(config);
|
||||
|
||||
if (thereIsPeerConnections()) {
|
||||
// Send speech transcript through RTC Data Channels
|
||||
for (let peer_id in chatDataChannels) {
|
||||
if (chatDataChannels[peer_id].readyState === 'open')
|
||||
chatDataChannels[peer_id].send(JSON.stringify(config));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
recognition.onerror = function (event) {
|
||||
console.warn('Speech recognition error', event.error);
|
||||
};
|
||||
|
||||
recognition.onend = function () {
|
||||
console.log('Stop speech recognition');
|
||||
// if (recognitionRunning) recognition.start();
|
||||
speechRecognitionStop.style.display = 'none';
|
||||
speechRecognitionStart.style.display = 'block';
|
||||
};
|
||||
|
||||
isWebkitSpeechRecognitionSupported = true;
|
||||
console.info('Browser supports webkitSpeechRecognition');
|
||||
} else {
|
||||
console.warn(
|
||||
'This browser not supports webkitSpeechRecognition, check out supported browsers: https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API#browser_compatibility',
|
||||
);
|
||||
}
|
||||
|
||||
//start or stop decider
|
||||
function startSpeech(config) {
|
||||
if (isWebkitSpeechRecognitionSupported) {
|
||||
if (config) {
|
||||
try {
|
||||
recognitionRunning = true;
|
||||
recognition.start();
|
||||
} catch (error) {
|
||||
console.log('Start speech', error);
|
||||
}
|
||||
} else {
|
||||
recognitionRunning = false;
|
||||
recognition.stop();
|
||||
}
|
||||
} else {
|
||||
userLog('info', 'This browser not supports webkitSpeechRecognition');
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
let recordingStarted = false;
|
||||
// initialize SpeechRecognition object
|
||||
let recognition = new webkitSpeechRecognition();
|
||||
recognition.maxAlternatives = 1;
|
||||
recognition.continuous = true;
|
||||
// Detect the said words
|
||||
recognition.onresult = e => {
|
||||
let current = event.resultIndex;
|
||||
// Get a transcript of what was said.
|
||||
let transcript = event.results[current][0].transcript;
|
||||
// Add the current transcript with existing said values
|
||||
config = {
|
||||
room_id: roomId,
|
||||
peer_name: myPeerName,
|
||||
text_data: transcript,
|
||||
time_stamp: new Date(),
|
||||
};
|
||||
sendToServer('speech_transcript', config); //sending data to signaling server for specific room
|
||||
}
|
||||
|
||||
//start or stop decider
|
||||
function start_stop_speech(config) {
|
||||
if (config) {
|
||||
try {
|
||||
// Start recognition
|
||||
recognition.start();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
} else {
|
||||
//stop recognition
|
||||
recognition.stop();
|
||||
}
|
||||
}
|
||||
|
||||
navigator.getUserMedia({ audio: true }, startUserMedia, function(e) {
|
||||
__log('No live audio input: ' + e);
|
||||
});
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Chris Wilson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Usage:
|
||||
audioNode = createAudioMeter(audioContext,clipLevel,averaging,clipLag);
|
||||
|
||||
audioContext: the AudioContext you're using.
|
||||
clipLevel: the level (0 to 1) that you would consider "clipping".
|
||||
Defaults to 0.98.
|
||||
averaging: how "smoothed" you would like the meter to be over time.
|
||||
Should be between 0 and less than 1. Defaults to 0.95.
|
||||
clipLag: how long you would like the "clipping" indicator to show
|
||||
after clipping has occured, in milliseconds. Defaults to 750ms.
|
||||
|
||||
Access the clipping through node.checkClipping(); use node.shutdown to get rid of it.
|
||||
*/
|
||||
|
||||
function createAudioMeter(audioContext, clipLevel, averaging, clipLag) {
|
||||
var processor = audioContext.createScriptProcessor(512);
|
||||
processor.onaudioprocess = volumeAudioProcess;
|
||||
processor.clipping = false;
|
||||
processor.lastClip = 0;
|
||||
processor.volume = 0;
|
||||
processor.clipLevel = clipLevel || 0.98;
|
||||
processor.averaging = averaging || 0.95;
|
||||
processor.clipLag = clipLag || 750;
|
||||
|
||||
// this will have no effect, since we don't copy the input to the output,
|
||||
// but works around a current Chrome bug.
|
||||
processor.connect(audioContext.destination);
|
||||
|
||||
processor.checkClipping =
|
||||
function() {
|
||||
if (!this.clipping)
|
||||
return false;
|
||||
if ((this.lastClip + this.clipLag) < window.performance.now())
|
||||
this.clipping = false;
|
||||
return this.clipping;
|
||||
};
|
||||
|
||||
processor.shutdown =
|
||||
function() {
|
||||
this.disconnect();
|
||||
this.onaudioprocess = null;
|
||||
};
|
||||
|
||||
return processor;
|
||||
}
|
||||
|
||||
function volumeAudioProcess(event) {
|
||||
var buf = event.inputBuffer.getChannelData(0);
|
||||
var bufLength = buf.length;
|
||||
var sum = 0;
|
||||
var x;
|
||||
|
||||
// Do a root-mean-square on the samples: sum up the squares...
|
||||
for (var i = 0; i < bufLength; i++) {
|
||||
x = buf[i];
|
||||
if (Math.abs(x) >= this.clipLevel) {
|
||||
this.clipping = true;
|
||||
this.lastClip = window.performance.now();
|
||||
}
|
||||
sum += x * x;
|
||||
}
|
||||
|
||||
// ... then take the square root of the sum.
|
||||
var rms = Math.sqrt(sum / bufLength);
|
||||
|
||||
// Now smooth this out with the averaging factor applied
|
||||
// to the previous sample - take the max here because we
|
||||
// want "fast attack, slow release."
|
||||
this.volume = Math.max(rms, this.volume * this.averaging);
|
||||
}
|
||||
Binary file not shown.
+307
-281
@@ -1,216 +1,237 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
|
||||
<head>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-3XM60XK9RQ"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-3XM60XK9RQ"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-3XM60XK9RQ');
|
||||
</script>
|
||||
|
||||
gtag('config', 'G-3XM60XK9RQ');
|
||||
</script>
|
||||
<!-- Title and Icon -->
|
||||
|
||||
<!-- Title and Icon -->
|
||||
<title>MiroTalk WebRTC Video call, Chat Room & Screen Sharing.</title>
|
||||
<link rel="shortcut icon" href="../images/logo.svg" />
|
||||
<link rel="apple-touch-icon" href="../images/logo.svg" />
|
||||
|
||||
<title>MiroTalk WebRTC Video call, Chat Room & Screen Sharing.</title>
|
||||
<link rel="shortcut icon" href="../images/logo.svg" />
|
||||
<link rel="apple-touch-icon" href="../images/logo.svg" />
|
||||
<!-- Meta Information -->
|
||||
|
||||
<!-- Meta Information -->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="MiroTalk powered by WebRTC, Real-time Simple Secure Fast video calls, chat and screen sharing capabilities in the browser, from your mobile or desktop."
|
||||
/>
|
||||
<meta
|
||||
name="keywords"
|
||||
content="webrtc, webrtc stun, webrtc turn, video meeting, video chat, multi video chat, peer to peer, p2p, zoom"
|
||||
/>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
|
||||
<meta name="description" content="MiroTalk powered by WebRTC, Real-time Simple Secure Fast video calls, chat and screen sharing capabilities in the browser, from your mobile or desktop." />
|
||||
<meta name="keywords" content="webrtc, webrtc stun, webrtc turn, video meeting, video chat, multi video chat, peer to peer, p2p, zoom" />
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
<meta property="og:type" content="app-webrtc" />
|
||||
<meta property="og:site_name" content="MiroTalk" />
|
||||
<meta property="og:title" content="Click the link to join this call." />
|
||||
<meta property="og:description" content="Free WebRTC browser-based video call." />
|
||||
<meta property="og:image" content="https://mirotalk.up.railway.app/images/preview.png" />
|
||||
<meta property="og:url" content="https://mirotalk.herokuapp.com/" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="../images/favicon.png" />
|
||||
|
||||
<meta property="og:type" content="app-webrtc" />
|
||||
<meta property="og:site_name" content="MiroTalk" />
|
||||
<meta property="og:title" content="Click the link to join this call." />
|
||||
<meta property="og:description" content="Free WebRTC browser-based video call." />
|
||||
<meta property="og:image" content="https://mirotalk.up.railway.app/images/preview.png" />
|
||||
<meta property="og:url" content="https://mirotalk.herokuapp.com/" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="../images/favicon.png" />
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<!-- StyleSheet -->
|
||||
<link rel="stylesheet" href="../css/client.css" />
|
||||
<link rel="stylesheet" href="../css/whiteboard.css" />
|
||||
<!-- https://animate.style 4 using for swal fadeIn-Out -->
|
||||
|
||||
<link rel="stylesheet" href="../css/client.css" />
|
||||
<link rel="stylesheet" href="../css/whiteboard.css" />
|
||||
<!-- https://animate.style 4 using for swal fadeIn-Out -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
|
||||
</head>
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
|
||||
</head>
|
||||
<body onload="initClientPeer()">
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
<body onload="initClientPeer()">
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<!-- just 4SEO Optimization -->
|
||||
|
||||
<!-- just 4SEO Optimization -->
|
||||
<div id="webRTCSeo">
|
||||
<h1>WebRTC</h1>
|
||||
</div>
|
||||
|
||||
<div id="webRTCSeo">
|
||||
<h1>WebRTC</h1>
|
||||
</div>
|
||||
<!-- show this before to join -->
|
||||
|
||||
<!-- show this before to join -->
|
||||
|
||||
<div id="loadingDiv">
|
||||
<h1 class="pulsate">Loading...</h1>
|
||||
<pre>
|
||||
<div id="loadingDiv">
|
||||
<h1 class="pulsate">Loading...</h1>
|
||||
<pre>
|
||||
Please allow camera & microphone
|
||||
access to use this app.
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Start buttons bar
|
||||
<!-- Start buttons bar
|
||||
https://fontawesome.com/icons?d=gallery
|
||||
-->
|
||||
|
||||
<div id="buttonsBar">
|
||||
<button id="shareRoomBtn" class="fas fa-users"></button>
|
||||
<button id="audioBtn" class="fas fa-microphone"></button>
|
||||
<button id="videoBtn" class="fas fa-video"></button>
|
||||
<button id="swapCameraBtn" class="fas fa-sync-alt"></button>
|
||||
<button id="screenShareBtn" class="fas fa-desktop"></button>
|
||||
<button id="recordStreamBtn" class="fas fa-record-vinyl"></button>
|
||||
<button id="fullScreenBtn" class="fas fa-expand-alt"></button>
|
||||
<button id="chatRoomBtn" class="fas fa-comment"></button>
|
||||
<button id="captionBtn" class="fas fa-closed-captioning"></button>
|
||||
<button id="myHandBtn" class="fas fa-hand-paper"></button>
|
||||
<button id="whiteboardBtn" class="fas fa-chalkboard-teacher"></button>
|
||||
<button id="fileShareBtn" class="fas fa-folder-open"></button>
|
||||
<button id="mySettingsBtn" class="fas fa-cogs"></button>
|
||||
<button id="aboutBtn" class="fas fa-question"></button>
|
||||
<button id="leaveRoomBtn" class="fas fa-phone-slash"></button>
|
||||
</div>
|
||||
<div id="buttonsBar">
|
||||
<button id="shareRoomBtn" class="fas fa-users"></button>
|
||||
<button id="audioBtn" class="fas fa-microphone"></button>
|
||||
<button id="videoBtn" class="fas fa-video"></button>
|
||||
<button id="swapCameraBtn" class="fas fa-sync-alt"></button>
|
||||
<button id="screenShareBtn" class="fas fa-desktop"></button>
|
||||
<button id="recordStreamBtn" class="fas fa-record-vinyl"></button>
|
||||
<button id="fullScreenBtn" class="fas fa-expand-alt"></button>
|
||||
<button id="chatRoomBtn" class="fas fa-comment"></button>
|
||||
<button id="captionBtn" class="fas fa-closed-captioning"></button>
|
||||
<button id="myHandBtn" class="fas fa-hand-paper"></button>
|
||||
<button id="whiteboardBtn" class="fas fa-chalkboard-teacher"></button>
|
||||
<button id="fileShareBtn" class="fas fa-folder-open"></button>
|
||||
<button id="mySettingsBtn" class="fas fa-cogs"></button>
|
||||
<button id="aboutBtn" class="fas fa-question"></button>
|
||||
<button id="leaveRoomBtn" class="fas fa-phone-slash"></button>
|
||||
</div>
|
||||
|
||||
<!-- End left buttons -->
|
||||
<!-- End left buttons -->
|
||||
|
||||
<!-- Start chat room
|
||||
<!-- Start chat room
|
||||
https://codepen.io/sajadhsm/pen/odaBdd
|
||||
https://getemoji.com
|
||||
-->
|
||||
|
||||
<section id="msgerDraggable" class="msger-draggable">
|
||||
<section id="msger" class="msger">
|
||||
<header id="msgerHeader" class="msger-header">
|
||||
<div class="msger-header-title"><i class="fas fa-comment-alt"></i> Chat</div>
|
||||
<div class="msger-header-options">
|
||||
<button id="msgerTheme" class="fas fa-ghost"></button>
|
||||
<button id="msgerCPBtn" class="fas fa-users"></button>
|
||||
<button id="msgerClean" class="fas fa-trash"></button>
|
||||
<button id="msgerSaveBtn" class="fas fa-save"></button>
|
||||
<button id="msgerClose" class="fas fa-times"></button>
|
||||
</div>
|
||||
</header>
|
||||
<section id="msgerDraggable" class="msger-draggable">
|
||||
<section id="msger" class="msger">
|
||||
<header id="msgerHeader" class="msger-header">
|
||||
<div class="msger-header-title"><i class="fas fa-comment-alt"></i> Chat</div>
|
||||
<div class="msger-header-options">
|
||||
<button id="msgerTheme" class="fas fa-ghost"></button>
|
||||
<button id="msgerCPBtn" class="fas fa-users"></button>
|
||||
<button id="msgerClean" class="fas fa-trash"></button>
|
||||
<button id="msgerSaveBtn" class="fas fa-save"></button>
|
||||
<button id="msgerClose" class="fas fa-times"></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="msgerChat" class="msger-chat"></main>
|
||||
<main id="msgerChat" class="msger-chat"></main>
|
||||
|
||||
<!-- Start emoji picker
|
||||
<!-- Start emoji picker
|
||||
https://github.com/nolanlawson/emoji-picker-element ]
|
||||
-->
|
||||
|
||||
<section id="msgerEmojiPicker">
|
||||
<emoji-picker class="dark"></emoji-picker>
|
||||
<!-- <emoji-picker class="light"></emoji-picker> -->
|
||||
<section id="msgerEmojiPicker">
|
||||
<emoji-picker class="dark"></emoji-picker>
|
||||
<!-- <emoji-picker class="light"></emoji-picker> -->
|
||||
</section>
|
||||
|
||||
<!-- End emoji picker -->
|
||||
|
||||
<div class="msger-inputarea">
|
||||
<input id="msgerInput" class="msger-input" type="text" placeholder="💬 Enter your message..." />
|
||||
<button id="msgerVideoUrlBtn" class="fab fa-youtube"></button>
|
||||
<button id="msgerEmojiBtn" class="fas fa-smile"></button>
|
||||
<button id="msgerSendBtn" class="fas fa-paper-plane"></button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- End emoji picker -->
|
||||
<!-- Start private msg -->
|
||||
|
||||
<div class="msger-inputarea">
|
||||
<input id="msgerInput" class="msger-input" type="text" placeholder="💬 Enter your message..." />
|
||||
<button id="msgerVideoUrlBtn" class="fab fa-youtube"></button>
|
||||
<button id="msgerEmojiBtn" class="fas fa-smile"></button>
|
||||
<button id="msgerSendBtn" class="fas fa-paper-plane"></button>
|
||||
</div>
|
||||
<section id="msgerCP">
|
||||
<section id="msgerCPSec" class="msger">
|
||||
<header id="msgerCPHeader" class="msger-private-header">
|
||||
<div class="msger-header-title"><i class="fas fa-comment-alt"></i> Send Private messages</div>
|
||||
<div class="msger-header-options">
|
||||
<button id="msgerCPCloseBtn" class="fas fa-times"></button>
|
||||
</div>
|
||||
</header>
|
||||
<main id="msgerCPChat" class="msger-chat">
|
||||
<div class="search-container">
|
||||
<input
|
||||
id="searchPeerBarName"
|
||||
type="text"
|
||||
placeholder=" 🔍 Search peer by name..."
|
||||
name="search"
|
||||
onkeyup="searchPeer()"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div id="msgerCPList"></div>
|
||||
</main>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- End private msg -->
|
||||
</section>
|
||||
|
||||
<!-- Start private msg -->
|
||||
<!-- End chat room -->
|
||||
|
||||
<section id="msgerCP">
|
||||
<section id="msgerCPSec" class="msger">
|
||||
<header id="msgerCPHeader" class="msger-private-header">
|
||||
<div class="msger-header-title"><i class="fas fa-comment-alt"></i> Send Private messages</div>
|
||||
<!-- Start of caption section -->
|
||||
|
||||
<section id="captionDraggable" class="msger-draggable">
|
||||
<section id="caption" class="msger">
|
||||
<header id="captionHeader" class="msger-header">
|
||||
<div class="msger-header-title"><i class="fas fa-comment-alt"></i> Captions</div>
|
||||
<div class="msger-header-options">
|
||||
<button id="msgerCPCloseBtn" class="fas fa-times"></button>
|
||||
<button id="captionTheme" class="fas fa-ghost"></button>
|
||||
<button id="captionClean" class="fas fa-trash"></button>
|
||||
<button id="captionSaveBtn" class="fas fa-save"></button>
|
||||
<button id="captionClose" class="fas fa-times"></button>
|
||||
</div>
|
||||
</header>
|
||||
<main id="msgerCPChat" class="msger-chat">
|
||||
<div class="search-container">
|
||||
<input id="searchPeerBarName" type="text" placeholder=" 🔍 Search peer by name..." name="search" onkeyup="searchPeer()" />
|
||||
</div>
|
||||
<br />
|
||||
<div id="msgerCPList"></div>
|
||||
</main>
|
||||
|
||||
<main id="captionChat" class="msger-chat"></main>
|
||||
<div class="msger-inputarea">
|
||||
<label>Speech recognition</label>
|
||||
<button type="button" id="speechRecognitionStart" class="fas fa-play"> Start</button>
|
||||
<button type="button" id="speechRecognitionStop" class="fas fa-stop"> Stop</button>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- End private msg -->
|
||||
</section>
|
||||
<!-- End of caption section -->
|
||||
|
||||
<!-- End chat room -->
|
||||
<!-- Start my settings -->
|
||||
|
||||
<!-- start of caption section -->
|
||||
<section id="captionDraggable" class="msger-draggable">
|
||||
<section id="caption" class="msger">
|
||||
<header id="captionHeader" class="msger-header">
|
||||
<div class="caption-header-title"><i class="fas fa-comment-alt"></i>Captions</div>
|
||||
<div class="caption-header-options">
|
||||
<button id="captionTheme" class="fas fa-ghost"></button>
|
||||
<button id="captionClean" class="fas fa-trash"></button>
|
||||
<button id="captionSaveBtn" class="fas fa-save"></button>
|
||||
<button id="captionClose" class="fas fa-times"></button>
|
||||
</div>
|
||||
<section id="mySettings">
|
||||
<header id="mySettingsHeader">
|
||||
<button id="mySettingsCloseBtn" class="fas fa-times"></button>
|
||||
</header>
|
||||
|
||||
<main id="captionChat" class="msger-chat"></main>
|
||||
</section>
|
||||
</section>
|
||||
<!-- End of caption section -->
|
||||
|
||||
<!-- Start my settings -->
|
||||
|
||||
<section id="mySettings">
|
||||
<header id="mySettingsHeader">
|
||||
<button id="mySettingsCloseBtn" class="fas fa-times"></button>
|
||||
</header>
|
||||
<main>
|
||||
<br />
|
||||
<div class="tab">
|
||||
<button id="tabDevicesBtn" class="tablinks">Devices</button>
|
||||
<button id="tabBandwidthBtn" class="tablinks">Bandwidth</button>
|
||||
<button id="tabRoomBtn" class="tablinks">Room</button>
|
||||
<button id="tabStylingBtn" class="tablinks">Styling</button>
|
||||
</div>
|
||||
|
||||
<div id="tabDevices" class="tabcontent">
|
||||
<main>
|
||||
<br />
|
||||
<div>
|
||||
<label for="videoSource">Camera</label><br />
|
||||
<select id="videoSource"></select>
|
||||
<div class="tab">
|
||||
<button id="tabDevicesBtn" class="fas fa-cog tablinks"></button>
|
||||
<button id="tabBandwidthBtn" class="fas fa-wifi tablinks"></button>
|
||||
<button id="tabRoomBtn" class="fas fa-home tablinks"></button>
|
||||
<button id="tabStylingBtn" class="fas fa-palette tablinks"></button>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<label for="audioSource">Microphone</label><br />
|
||||
<select id="audioSource"></select>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<label for="audioOutput">Speaker</label><br />
|
||||
<select id="audioOutput"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tabBandwidth" class="tabcontent">
|
||||
<br />
|
||||
<label for="videoQuality">Video quality</label>
|
||||
<br />
|
||||
<select id="videoQuality">
|
||||
<div id="tabDevices" class="tabcontent">
|
||||
<br />
|
||||
<div>
|
||||
<label for="videoSource">Camera</label><br />
|
||||
<select id="videoSource"></select>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<label for="audioSource">Microphone</label><br />
|
||||
<select id="audioSource"></select>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<label for="audioOutput">Speaker</label><br />
|
||||
<select id="audioOutput"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tabBandwidth" class="tabcontent">
|
||||
<br />
|
||||
<label for="videoQuality">Video quality</label>
|
||||
<br />
|
||||
<select id="videoQuality">
|
||||
<option value="default">Default</option>
|
||||
<option value="qvgaVideo">QVGA</option>
|
||||
<option value="vgaVideo">VGA</option>
|
||||
@@ -218,153 +239,158 @@ access to use this app.
|
||||
<option value="fhdVideo">FULL HD</option>
|
||||
<option value="4kVideo">4K</option>
|
||||
</select>
|
||||
<br /><br />
|
||||
<label for="videoFps">Camera fps</label>
|
||||
<br />
|
||||
<select id="videoFps">
|
||||
<option value="60">60 fps</option>
|
||||
<option value="30">30 fps</option>
|
||||
<option value="25">25 fps</option>
|
||||
<option value="20">20 fps</option>
|
||||
<option value="15">15 fps</option>
|
||||
<option value="10">10 fps</option>
|
||||
<option value="5">5 fps</option>
|
||||
</select>
|
||||
<br /><br />
|
||||
<label for="screenFps">Screen fps</label>
|
||||
<br />
|
||||
<select id="screenFps">
|
||||
<option value="60">60 fps</option>
|
||||
<option value="30">30 fps</option>
|
||||
<option value="25">25 fps</option>
|
||||
<option value="20">20 fps</option>
|
||||
<option value="15">15 fps</option>
|
||||
<option value="10">10 fps</option>
|
||||
<option value="5">5 fps</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="tabRoom" class="tabcontent">
|
||||
<br />
|
||||
<div>
|
||||
<label>My name</label><br />
|
||||
<input id="myPeerNameSet" type="text" placeholder="Change name..." />
|
||||
<button id="myPeerNameSetBtn" class="fas fa-user-edit"> Change</button>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<label>Participants</label><br />
|
||||
<button id="muteEveryoneBtn" class="fas fa-microphone"> Mute everyone</button>
|
||||
<button id="hideEveryoneBtn" class="fas fa-video"> Hide everyone</button>
|
||||
<br /><br />
|
||||
<label>Security</label><br />
|
||||
<button id="lockUnlockRoomBtn" class="fas fa-lock-open"></button>
|
||||
<label for="videoFps">Camera fps</label>
|
||||
<br />
|
||||
<select id="videoFps">
|
||||
<option value="60">60 fps</option>
|
||||
<option value="30">30 fps</option>
|
||||
<option value="25">25 fps</option>
|
||||
<option value="20">20 fps</option>
|
||||
<option value="15">15 fps</option>
|
||||
<option value="10">10 fps</option>
|
||||
<option value="5">5 fps</option>
|
||||
</select>
|
||||
<br /><br />
|
||||
<label for="screenFps">Screen fps</label>
|
||||
<br />
|
||||
<select id="screenFps">
|
||||
<option value="60">60 fps</option>
|
||||
<option value="30">30 fps</option>
|
||||
<option value="25">25 fps</option>
|
||||
<option value="20">20 fps</option>
|
||||
<option value="15">15 fps</option>
|
||||
<option value="10">10 fps</option>
|
||||
<option value="5">5 fps</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tabStyling" class="tabcontent">
|
||||
<br />
|
||||
<label for="mirotalkTheme">Theme color</label>
|
||||
<br />
|
||||
<select id="mirotalkTheme">
|
||||
<div id="tabRoom" class="tabcontent">
|
||||
<br />
|
||||
<div>
|
||||
<label>My name</label><br />
|
||||
<input id="myPeerNameSet" type="text" placeholder="Change name..." />
|
||||
<button id="myPeerNameSetBtn" class="fas fa-user-edit"> Change</button>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<label>Participants</label><br />
|
||||
<button id="muteEveryoneBtn" class="fas fa-microphone"> Mute everyone</button>
|
||||
<button id="hideEveryoneBtn" class="fas fa-video"> Hide everyone</button>
|
||||
<br /><br />
|
||||
<label>Security</label><br />
|
||||
<button id="lockUnlockRoomBtn" class="fas fa-lock-open"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tabStyling" class="tabcontent">
|
||||
<br />
|
||||
<label for="mirotalkTheme">Theme color</label>
|
||||
<br />
|
||||
<select id="mirotalkTheme">
|
||||
<option value="neon">🟣 MiroTalk - neon</option>
|
||||
<option value="dark">⚫️ MiroTalk - dark</option>
|
||||
<option value="forest">🟢 MiroTalk - forest</option>
|
||||
<option value="sky">🔵 MiroTalk - sky</option>
|
||||
<option value="ghost">⚪️ MiroTalk - ghost</option>
|
||||
</select>
|
||||
<br /><br />
|
||||
<label for="mirotalkBtnsBar">Buttons bar</label>
|
||||
<br />
|
||||
<select id="mirotalkBtnsBar">
|
||||
<br /><br />
|
||||
<label for="mirotalkBtnsBar">Buttons bar</label>
|
||||
<br />
|
||||
<select id="mirotalkBtnsBar">
|
||||
<option value="vertical">🚦 Vertical</option>
|
||||
<option value="horizontal">🚥 Horizontal</option>
|
||||
</select>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<!-- End my settings -->
|
||||
<!-- End my settings -->
|
||||
|
||||
<!-- Start whiteboard -->
|
||||
<!-- Start whiteboard -->
|
||||
|
||||
<section id="whiteboard" class="hidden">
|
||||
<header id="whiteboardHeader" class="whiteboard-header">
|
||||
<div id="whiteboardTitle" class="whiteboard-header-title"></div>
|
||||
<div class="whiteboard-header-options">
|
||||
pencil
|
||||
<input id="wbDrawingColorEl" class="whiteboardColorPicker" type="color" value="#FFFFFF" /> background
|
||||
<input id="wbBackgroundColorEl" class="whiteboardColorPicker" type="color" value="#000000" />
|
||||
<button id="whiteboardPencilBtn" class="fas fa-pencil-alt"></button>
|
||||
<button id="whiteboardObjectBtn" class="fas fa-mouse-pointer"></button>
|
||||
<button id="whiteboardUndoBtn" class="fas fa-undo"></button>
|
||||
<button id="whiteboardRedoBtn" class="fas fa-redo"></button>
|
||||
<button id="whiteboardImgFileBtn" class="far fa-image"></button>
|
||||
<button id="whiteboardImgUrlBtn" class="fas fa-link"></button>
|
||||
<button id="whiteboardTextBtn" class="fas fa-spell-check"></button>
|
||||
<button id="whiteboardLineBtn" class="fas fa-slash"></button>
|
||||
<button id="whiteboardRectBtn" class="far fa-square"></button>
|
||||
<button id="whiteboardCircleBtn" class="far fa-circle"></button>
|
||||
<button id="whiteboardSaveBtn" class="fas fa-save"></button>
|
||||
<button id="whiteboardEraserBtn" class="fas fa-eraser"></button>
|
||||
<button id="whiteboardCleanBtn" class="fas fa-trash"></button>
|
||||
<button id="whiteboardCloseBtn" class="fas fa-times"></button>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<canvas id="wbCanvas"></canvas>
|
||||
</main>
|
||||
</section>
|
||||
<section id="whiteboard" class="hidden">
|
||||
<header id="whiteboardHeader" class="whiteboard-header">
|
||||
<div id="whiteboardTitle" class="whiteboard-header-title"></div>
|
||||
<div class="whiteboard-header-options">
|
||||
pencil
|
||||
<input id="wbDrawingColorEl" class="whiteboardColorPicker" type="color" value="#FFFFFF" />
|
||||
background
|
||||
<input id="wbBackgroundColorEl" class="whiteboardColorPicker" type="color" value="#000000" />
|
||||
<button id="whiteboardPencilBtn" class="fas fa-pencil-alt"></button>
|
||||
<button id="whiteboardObjectBtn" class="fas fa-mouse-pointer"></button>
|
||||
<button id="whiteboardUndoBtn" class="fas fa-undo"></button>
|
||||
<button id="whiteboardRedoBtn" class="fas fa-redo"></button>
|
||||
<button id="whiteboardImgFileBtn" class="far fa-image"></button>
|
||||
<button id="whiteboardImgUrlBtn" class="fas fa-link"></button>
|
||||
<button id="whiteboardTextBtn" class="fas fa-spell-check"></button>
|
||||
<button id="whiteboardLineBtn" class="fas fa-slash"></button>
|
||||
<button id="whiteboardRectBtn" class="far fa-square"></button>
|
||||
<button id="whiteboardCircleBtn" class="far fa-circle"></button>
|
||||
<button id="whiteboardSaveBtn" class="fas fa-save"></button>
|
||||
<button id="whiteboardEraserBtn" class="fas fa-eraser"></button>
|
||||
<button id="whiteboardCleanBtn" class="fas fa-trash"></button>
|
||||
<button id="whiteboardCloseBtn" class="fas fa-times"></button>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<canvas id="wbCanvas"></canvas>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<!-- End whiteboard -->
|
||||
<!-- End whiteboard -->
|
||||
|
||||
<!-- Start File Send -->
|
||||
<!-- Start File Send -->
|
||||
|
||||
<div id="sendFileDiv">
|
||||
<img id="imgShare" src="../images/share.png" alt="mirotalk-share" class="center" /><br />
|
||||
<div id="sendFileInfo"></div>
|
||||
<div id="sendFilePercentage"></div>
|
||||
<progress id="sendProgress" max="0" value="0"></progress>
|
||||
<button id="sendAbortBtn" class="fas fa-stop-circle"> Abort</button>
|
||||
</div>
|
||||
|
||||
<!-- End File Send -->
|
||||
|
||||
<!-- Start video URL iframe -->
|
||||
|
||||
<div id="videoUrlCont">
|
||||
<div id="videoUrlHeader">
|
||||
<button id="videoUrlCloseBtn" class="fas fa-times"></button>
|
||||
<div id="sendFileDiv">
|
||||
<img id="imgShare" src="../images/share.png" alt="mirotalk-share" class="center" /><br />
|
||||
<div id="sendFileInfo"></div>
|
||||
<div id="sendFilePercentage"></div>
|
||||
<progress id="sendProgress" max="0" value="0"></progress>
|
||||
<button id="sendAbortBtn" class="fas fa-stop-circle"> Abort</button>
|
||||
</div>
|
||||
<br />
|
||||
<iframe id="videoUrlIframe" title="Video Url Player" src="https://www.youtube.com/embed/RT6_Id5-7-s" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<!-- End Youtube Iframe -->
|
||||
<!-- End File Send -->
|
||||
|
||||
<!-- Js scripts -->
|
||||
<!-- Start video URL iframe -->
|
||||
|
||||
<script defer src="https://kit.fontawesome.com/d2f1016e6f.js" crossorigin="anonymous"></script>
|
||||
<script defer src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
|
||||
<script defer src="https://cdn.rawgit.com/muaz-khan/DetectRTC/master/DetectRTC.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.20"></script>
|
||||
<script defer type="module" src="https://unpkg.com/emoji-picker-element@1"></script>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/460/fabric.min.js"></script>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
|
||||
<script defer src="https://unpkg.com/@popperjs/core@2"></script>
|
||||
<script defer src="https://unpkg.com/tippy.js@6"></script>
|
||||
<script defer src="/socket.io/socket.io.js"></script>
|
||||
<script defer src="../js/client.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="../js/volume_meter.js"></script>
|
||||
<script src="../js/speech_recognition.js"></script>
|
||||
<div id="videoUrlCont">
|
||||
<div id="videoUrlHeader">
|
||||
<button id="videoUrlCloseBtn" class="fas fa-times"></button>
|
||||
</div>
|
||||
<br />
|
||||
<iframe
|
||||
id="videoUrlIframe"
|
||||
title="Video Url Player"
|
||||
src="https://www.youtube.com/embed/RT6_Id5-7-s"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
<!-- end of Js scripts -->
|
||||
<!-- End Youtube Iframe -->
|
||||
|
||||
<!--
|
||||
<!-- Js scripts -->
|
||||
|
||||
<script defer src="https://kit.fontawesome.com/d2f1016e6f.js" crossorigin="anonymous"></script>
|
||||
<script defer src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
|
||||
<script defer src="https://cdn.rawgit.com/muaz-khan/DetectRTC/master/DetectRTC.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.20"></script>
|
||||
<script defer type="module" src="https://unpkg.com/emoji-picker-element@1"></script>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/460/fabric.min.js"></script>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
|
||||
<script defer src="https://unpkg.com/@popperjs/core@2"></script>
|
||||
<script defer src="https://unpkg.com/tippy.js@6"></script>
|
||||
<script defer src="/socket.io/socket.io.js"></script>
|
||||
<script defer src="../js/client.js"></script>
|
||||
<script defer src="../js/speechRecognition.js"></script>
|
||||
|
||||
<!-- end of Js scripts -->
|
||||
|
||||
<!--
|
||||
the <video> and <audio> tags are all added and removed dynamically
|
||||
in 'onAddStream', 'setupLocalMedia', and 'removePeer'/'disconnect'
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user