[mirotalk] - implement chat-room

This commit is contained in:
Miroslav Pejic
2021-01-23 22:27:59 +01:00
parent 49b8548138
commit 15e2bd1377
7 changed files with 470 additions and 49 deletions
+3
View File
@@ -34,6 +34,9 @@ Open the app in one of following **supported browser**
- Audio
- Screen Sharing
- Send Message
- Chat Room
- Full Screen Mode
- Right click on Video elements for more options
- No download required, entirely browser based
- Direct peer to peer connection ensures lowest latency
+5
View File
@@ -229,15 +229,20 @@ io.sockets.on("connect", (socket) => {
// =====================================================
socket.on("msg", (config) => {
let peers = config.peers;
let name = config.name;
let msg = config.msg;
let type = config.type;
console.log("[" + socket.id + "] emit onMessage", {
name: name,
msg: msg,
});
for (peer_id in peers) {
sockets[peer_id].emit("onMessage", {
name: name,
msg: msg,
type: type,
});
}
});
+203 -32
View File
@@ -10,7 +10,10 @@
// config var
// =====================================================
const loaderGif = "/images/loader.gif";
const myChatAvatar = "/images/programmer.png";
const friendChatAvatar = "/images/friend.png";
const notifyBySound = true; // turn on-off sound notifications
var myChatName = null;
var signalingServerPort = 80;
var signalingServer = getserverURL();
var roomId = getRoomId();
@@ -20,6 +23,7 @@ var useAudio = true;
var useVideo = true;
var camera = "user";
var isScreenStreaming = false;
var isChatBoxVisible = false;
var signalingSocket = null; // socket.io connection to our webserver
var localMediaStream = null; // my microphone / webcam
var remoteMediaStream = null; // friends microphone / webcam
@@ -317,9 +321,23 @@ function initPeer() {
playSound("removePeer");
});
// show messages
// show messages simple - chat
signalingSocket.on("onMessage", function (config) {
showMessage(config.msg);
console.log("Receive msg", { msg: config.msg });
switch (config.type) {
case "simple":
playSound("newMessage");
showMessage(config.msg);
break;
case "chat":
if (!isChatBoxVisible) {
showChatRoom();
get("chatRoomBtn").className = "fas fa-comment-slash";
}
playSound("newMessage");
appendMessage(config.name, friendChatAvatar, "left", config.msg);
break;
}
});
} // end [initPeer]
@@ -420,6 +438,7 @@ function manageButtons() {
setScreenShareBtn();
setFullScreenBtn();
setSendMsgBtn();
setChatRoomBtn();
setAboutBtn();
setLeaveRoomBtn();
setButtonsOpacity();
@@ -429,7 +448,7 @@ function manageButtons() {
// copy Room URL button click event
// =====================================================
function setCopyRoomBtn() {
document.getElementById("copyRoomBtn").addEventListener("click", (e) => {
get("copyRoomBtn").addEventListener("click", (e) => {
copyRoomURL();
});
}
@@ -438,7 +457,7 @@ function setCopyRoomBtn() {
// audio mute-unmute button click event
// =====================================================
function setAudioBtn() {
document.getElementById("audioBtn").addEventListener("click", (e) => {
get("audioBtn").addEventListener("click", (e) => {
localMediaStream.getAudioTracks()[0].enabled = !localMediaStream.getAudioTracks()[0]
.enabled;
e.target.className =
@@ -451,7 +470,7 @@ function setAudioBtn() {
// video hide-show button click event
// =====================================================
function setVideoBtn() {
document.getElementById("videoBtn").addEventListener("click", (e) => {
get("videoBtn").addEventListener("click", (e) => {
// https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/getVideoTracks
localMediaStream.getVideoTracks()[0].enabled = !localMediaStream.getVideoTracks()[0]
.enabled;
@@ -475,7 +494,7 @@ function setSwapCameraBtn() {
swapCamera();
});
} else {
document.getElementById("swapCameraBtn").style.display = "none";
get("swapCameraBtn").style.display = "none";
}
});
}
@@ -486,11 +505,11 @@ function setSwapCameraBtn() {
function setScreenShareBtn() {
if (navigator.getDisplayMedia || navigator.mediaDevices.getDisplayMedia) {
// share-screen on-off button click event
document.getElementById("screenShareBtn").addEventListener("click", (e) => {
get("screenShareBtn").addEventListener("click", (e) => {
toggleScreenSharing();
});
} else {
document.getElementById("screenShareBtn").style.display = "none";
get("screenShareBtn").style.display = "none";
}
}
@@ -503,16 +522,15 @@ function setFullScreenBtn() {
document.addEventListener("fullscreenchange", function (e) {
var fullscreenElement = document.fullscreenElement;
if (!fullscreenElement) {
document.getElementById("fullScreenBtn").className =
"fas fa-expand-alt";
get("fullScreenBtn").className = "fas fa-expand-alt";
}
});
document.getElementById("fullScreenBtn").addEventListener("click", (e) => {
get("fullScreenBtn").addEventListener("click", (e) => {
toggleFullScreen();
});
} else {
document.getElementById("fullScreenBtn").style.display = "none";
get("fullScreenBtn").style.display = "none";
}
}
@@ -520,16 +538,55 @@ function setFullScreenBtn() {
// send message button click event
// =====================================================
function setSendMsgBtn() {
document.getElementById("sendMsgBtn").addEventListener("click", (e) => {
get("sendMsgBtn").addEventListener("click", (e) => {
sendMessage();
});
}
// =====================================================
// chat room button click event
// =====================================================
function setChatRoomBtn() {
// Make chat room draggable
dragElement(get("msgerDraggable"));
get("chatRoomBtn").addEventListener("click", (e) => {
if (noPeers()) {
userLog("info", "Can't Open Chat Room, no peer connection detected");
return;
}
e.target.className = "fas fa-comment" + (isChatBoxVisible ? "" : "-slash");
if (!isChatBoxVisible) {
showChatRoom();
} else {
get("msgerDraggable").style.display = "none";
isChatBoxVisible = false;
}
});
get("msgerSendBtn").addEventListener("click", (e) => {
e.preventDefault(); // prevent refresh page
const msg = get("msgerInput").value;
if (!msg) return; // empity msg
emitMsg(myChatName, msg, "chat");
appendMessage(myChatName, myChatAvatar, "right", msg);
get("msgerInput").value = "";
});
get("msgerHeaderHide").addEventListener("click", (e) => {
get("msgerDraggable").style.display = "none";
get("chatRoomBtn").className = "fas fa-comment";
isChatBoxVisible = false;
});
}
// =====================================================
// about button click event
// =====================================================
function setAboutBtn() {
document.getElementById("aboutBtn").addEventListener("click", (e) => {
get("aboutBtn").addEventListener("click", (e) => {
about();
});
}
@@ -538,7 +595,7 @@ function setAboutBtn() {
// end call button click event
// =====================================================
function setLeaveRoomBtn() {
document.getElementById("leaveRoomBtn").addEventListener("click", (e) => {
get("leaveRoomBtn").addEventListener("click", (e) => {
leaveRoom();
});
}
@@ -547,7 +604,7 @@ function setLeaveRoomBtn() {
// set button opacity 1 means no opacity, you can change if like (0.5) ..
// =====================================================
function setButtonsOpacity() {
document.getElementById("buttons").style.opacity = "1";
get("buttons").style.opacity = "1";
}
// =====================================================
@@ -590,7 +647,7 @@ function sendMessage() {
}).then((result) => {
if (result.isConfirmed) {
let msg = result.value;
emitMsg(msg);
emitMsg("simple", msg, "simple");
}
});
}
@@ -599,9 +656,6 @@ function sendMessage() {
// Called when a message is recieved over the dataChannel
// =====================================================
function showMessage(msg) {
playSound("newMessage");
console.log("Receive msg", { msg: msg });
Swal.fire({
background: "black",
position: "center",
@@ -625,21 +679,127 @@ function showMessage(msg) {
}).then((result) => {
if (result.isConfirmed) {
let msg = result.value;
emitMsg(msg);
emitMsg("simple", msg, "simple");
}
});
}
// =====================================================
// chat room form
// =====================================================
function showChatRoom() {
if (!myChatName) {
Swal.fire({
background: "black",
position: "center",
icon: "info",
title: "Enter your chat name",
input: "text",
showClass: {
popup: "animate__animated animate__fadeInDown",
},
hideClass: {
popup: "animate__animated animate__fadeOutUp",
},
inputValidator: (value) => {
if (!value) {
return "Please write your chat name.";
}
myChatName = value;
get("msgerDraggable").style.display = "flex";
isChatBoxVisible = true;
},
});
} else {
// chat name already set just open chat room
get("msgerDraggable").style.display = "flex";
isChatBoxVisible = true;
}
}
// =====================================================
// drag char room element
// =====================================================
function dragElement(elmnt) {
// https://www.w3schools.com/howto/howto_js_draggable.asp
var pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
if (get("msgerHeader")) {
/* if present, the header is where you move the DIV from:*/
get("msgerHeader").onmousedown = dragMouseDown;
} else {
/* otherwise, move the DIV from anywhere inside the DIV:*/
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = elmnt.offsetTop - pos2 + "px";
elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
}
function closeDragElement() {
/* stop moving when mouse button is released:*/
document.onmouseup = null;
document.onmousemove = null;
}
}
// =====================================================
// append Message to msger chat room
// =====================================================
function appendMessage(name, img, side, text) {
const msgHTML = `
<div class="msg ${side}-msg">
<div class="msg-img" style="background-image: url(${img})"></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">${name}</div>
<div class="msg-info-time">${formatDate(new Date())}</div>
</div>
<div class="msg-text">${text}</div>
</div>
</div>
`;
get("msgerChat").insertAdjacentHTML("beforeend", msgHTML);
get("msgerChat").scrollTop += 500;
}
// =====================================================
// Send message over signaling server
// =====================================================
function emitMsg(msg) {
function emitMsg(name, msg, type) {
if (msg) {
signalingSocket.emit("msg", {
peers: peers,
name: name,
msg: msg,
type: type,
});
console.log("Send msg", {
name: name,
msg: msg,
});
console.log("Send msg", { msg: msg });
}
}
@@ -674,7 +834,7 @@ function toggleScreenSharing() {
}
} else {
screenMediaPromise = navigator.mediaDevices.getUserMedia(constraints);
document.getElementById("videoBtn").className = "fas fa-video"; // make sure to enable video
get("videoBtn").className = "fas fa-video"; // make sure to enable video
}
screenMediaPromise
.then((screenStream) => {
@@ -698,11 +858,11 @@ function toggleScreenSharing() {
localMediaStream = newStream;
// attachMediaStream is a part of the adapter.js library
attachMediaStream(document.getElementById("myVideo"), localMediaStream); // newstream
attachMediaStream(get("myVideo"), localMediaStream); // newstream
document.getElementById("myVideo").classList.toggle("mirror");
document.getElementById("screenShareBtn").classList.toggle("active");
document.getElementById("screenShareBtn").className = isScreenStreaming
get("myVideo").classList.toggle("mirror");
get("screenShareBtn").classList.toggle("active");
get("screenShareBtn").className = isScreenStreaming
? "fas fa-stop-circle"
: "fas fa-desktop";
@@ -723,11 +883,11 @@ function toggleFullScreen() {
// https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
document.getElementById("fullScreenBtn").className = "fas fa-compress-alt";
get("fullScreenBtn").className = "fas fa-compress-alt";
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
document.getElementById("fullScreenBtn").className = "fas fa-expand-alt";
get("fullScreenBtn").className = "fas fa-expand-alt";
}
}
}
@@ -767,9 +927,9 @@ function swapCamera() {
localMediaStream = newStream;
// attachMediaStream is a part of the adapter.js library
attachMediaStream(document.getElementById("myVideo"), localMediaStream);
attachMediaStream(get("myVideo"), localMediaStream);
document.getElementById("myVideo").classList.toggle("mirror");
get("myVideo").classList.toggle("mirror");
})
.catch((e) => {
console.log("[Error] to swaping camera", e);
@@ -928,3 +1088,14 @@ async function playSound(state) {
}
}
}
// utils
function get(id) {
return document.getElementById(id);
}
// date now
function formatDate(date) {
const h = "0" + date.getHours();
const m = "0" + date.getMinutes();
return `${h.slice(-2)}:${m.slice(-2)}`;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

+72 -1
View File
@@ -80,7 +80,16 @@
id="fullScreenBtn"
class="fas fa-expand-alt"
></button>
<button title="send msg" id="sendMsgBtn" class="fas fa-comment"></button>
<button
title="send msg"
id="sendMsgBtn"
class="fas fa-paper-plane"
></button>
<button
title="chat room"
id="chatRoomBtn"
class="fas fa-comment"
></button>
<button title="about" id="aboutBtn" class="fas fa-question"></button>
<button
title="leave room"
@@ -88,6 +97,68 @@
class="fas fa-phone-slash"
></button>
</div>
<!-- Start chat room -->
<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> mirotalkChat
</div>
<div id="msgerHeaderHide" class="msger-header-hide">
<span><i class="fas fa-times"></i></span>
</div>
</header>
<main id="msgerChat" class="msger-chat">
<div class="msg left-msg">
<div
class="msg-img"
style="background-image: url('/images/friend.png')"
></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">Friends Name</div>
<div class="msg-info-time">00:00</div>
</div>
<!-- https://getemoji.com -->
<div class="msg-text">Hi, welcome to mirotalkChat! 😄</div>
</div>
</div>
<div class="msg right-msg">
<div
class="msg-img"
style="background-image: url('/images/programmer.png')"
></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name">Your Name</div>
<div class="msg-info-time">00:00</div>
</div>
<div class="msg-text">Your message example</div>
</div>
</div>
</main>
<form class="msger-inputarea">
<input
id="msgerInput"
class="msger-input"
type="text"
placeholder="Enter your message..."
/>
<button id="msgerSendBtn" type="submit" class="msger-send-btn">
Send
</button>
</form>
</section>
</section>
<!-- End chat room -->
<!--
the <video> and <audio> tags are all added and removed dynamically
in 'onAddStream', 'setupLocalMedia', and 'removePeer'/'disconnect'
+187 -16
View File
@@ -27,8 +27,18 @@
opacity: 1;
}
}
:root {
--msger-bg: rgb(0, 0, 0);
/* --msger-bg: transparent; */
--border: 0px solid #ddd;
--left-msg-bg: #da05f3;
--right-msg-bg: #579ffb;
}
* {
outline: none;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
body {
@@ -39,6 +49,9 @@ body {
background-position: center;
margin: 0;
padding: 0;
justify-content: center;
align-items: center;
height: 100vh;
opacity: 0; /* make things invisible upon start */
-webkit-animation: fadeIn ease-in 1;
-moz-animation: fadeIn ease-in 1;
@@ -51,6 +64,162 @@ body {
animation-duration: 0.3s;
overflow: hidden;
}
.msger-draggable {
display: none;
position: absolute;
z-index: 9;
background-color: #000000;
/* background: var(--msger-bg); */
text-align: center;
-webkit-animation: fadeIn ease-in 1;
-moz-animation: fadeIn ease-in 1;
animation: fadeIn ease-in 1;
-webkit-animation-fill-mode: forwards;
-moz-animation-fill-mode: forwards;
animation-fill-mode: forwards;
-webkit-animation-duration: 1s;
-moz-animation-duration: 1s;
animation-duration: 1s;
overflow: hidden;
border-radius: 5px;
box-shadow: 5px 5px 10px #0500ff, -5px -5px 10px #da05f3;
}
/* https://mediag.com/blog/popular-screen-resolutions-designing-for-all/ */
.msger {
display: flex;
flex-flow: column wrap;
justify-content: space-between;
width: 412px;
height: 732px;
border: var(--border);
background: var(--msger-bg);
}
.msger-header {
display: flex;
justify-content: space-between;
padding: 10px;
border-bottom: var(--border);
background: rgb(0, 0, 0);
color: #666;
cursor: move;
}
.msger-chat {
flex: 1;
overflow-y: auto;
padding: 10px;
}
.msger-chat::-webkit-scrollbar {
width: 6px;
}
.msger-chat::-webkit-scrollbar-track {
background: #ddd;
}
.msger-chat::-webkit-scrollbar-thumb {
background: #bdbdbd;
}
.msg {
display: flex;
align-items: flex-end;
margin-bottom: 10px;
}
.msg:last-of-type {
margin: 0;
}
.msg-img {
width: 50px;
height: 50px;
margin-right: 10px;
background: rgb(0, 0, 0);
background-repeat: no-repeat;
background-position: center;
background-size: cover;
border-radius: 50%;
}
.msg-bubble {
max-width: 450px;
padding: 15px;
border-radius: 15px;
background: var(--left-msg-bg);
}
.msg-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.msg-info-name {
margin-right: 10px;
font-weight: bold;
}
.msg-info-time {
font-size: 0.85em;
}
.left-msg .msg-bubble {
border-bottom-left-radius: 0;
}
.right-msg {
flex-direction: row-reverse;
}
.right-msg .msg-bubble {
background: var(--right-msg-bg);
color: #fff;
border-bottom-right-radius: 0;
}
.right-msg .msg-img {
margin: 0 0 0 10px;
}
.msger-inputarea {
display: flex;
padding: 10px;
border-top: var(--border);
background: rgb(2, 2, 2);
/* background: var(--msger-bg); */
}
.msger-inputarea * {
padding: 10px;
border: none;
border-radius: 3px;
font-size: 1em;
color: white;
}
.msger-input {
flex: 1;
background: rgb(0, 0, 0);
}
.msger-send-btn {
margin-left: 10px;
background: rgb(0, 0, 0);
color: #fff;
font-weight: bold;
cursor: pointer;
transition: background 0.23s;
}
.msger-send-btn:hover {
background: rgb(0, 180, 50);
color: white;
}
.msger-chat {
background-color: black;
/* background: var(--msger-bg); */
}
.msger-header-hide:hover {
color: rgb(8, 189, 89);
cursor: pointer;
}
video {
width: 100%;
height: auto;
@@ -105,22 +274,6 @@ video:fullscreen {
#logo svg {
width: 100%;
}
#buttons button {
border: none;
font-size: 1.5rem;
transition: all 0.3s ease-in-out;
background: white;
/*background: transparent;*/
padding: 4px;
border-radius: 5px;
}
button:focus {
outline: none;
}
button:hover {
color: rgb(8, 189, 89);
}
#buttons {
position: absolute;
@@ -141,6 +294,23 @@ button:hover {
width: 40px;
}
#buttons button {
border: none;
font-size: 1.5rem;
transition: all 0.3s ease-in-out;
background: white;
/*background: transparent;*/
padding: 4px;
border-radius: 5px;
}
button:focus {
outline: none;
}
button:hover {
color: rgb(8, 189, 89);
}
#copyRoomBtn,
#audioBtn,
#videoBtn,
@@ -148,6 +318,7 @@ button:hover {
#screenShareBtn,
#fullScreenBtn,
#sendMsgBtn,
#chatRoomBtn,
#aboutBtn,
#leaveRoomBtn {
font-size: 2rem;