added pitch level detection to indicate speaking peers

This commit is contained in:
Anshuman Nayak
2022-01-14 17:22:50 +05:30
parent 1423b86623
commit fd9fefacae
4 changed files with 184 additions and 25 deletions
+69 -24
View File
@@ -38,30 +38,23 @@
:root {
/* common */
--bg: linear-gradient(to left, #363434, #000000);
--msger-top: 50%;
--msger-left: 50%;
--msger-height: 680px;
--msger-width: 420px;
/* video iframe */
--iframe-width: 640px;
--iframe-height: 480px;
/* whiteboard resize */
--wb-width: 800px;
--wb-height: 600px;
--wb-bg: linear-gradient(to left, #1f1e1e, #000000);
/* my settings */
--mySettings-select-w: 100%;
/* btns hover scale 110% zoom */
--btns-hover-scale: scale(1.1);
/* video elem border color */
--elem-border-color: grey 1px solid;
/* left buttons bar vertical default */
--btns-top: 50%;
--btns-right: 0%;
@@ -69,7 +62,6 @@
--btns-margin-left: 0px;
--btns-width: 40px;
--btns-flex-direction: column;
/* left buttons bar horizontal
--btns-top: 95%;
--btns-right: 25%;
@@ -78,7 +70,6 @@
--btns-width: 600px;
--btns-flex-direction: row;
*/
/* neon theme default */
--body-bg: black;
--msger-bg: linear-gradient(to left, #383838, #000000);
@@ -93,8 +84,8 @@
--wb-bg: linear-gradient(to left, #1f1e1e, #000000);
--wb-hbg: #000000;
--my-settings-label-color: white;
--hover-color: grey; /* rgb(8, 189, 89); */
--hover-color: grey;
/* rgb(8, 189, 89); */
/* dark theme
--body-bg: #16171b;
--msger-bg: linear-gradient(to left, #383838, #000000);
@@ -110,7 +101,6 @@
--wb-hbg: #000000;
--my-settings-label-color: white;
*/
/* forest theme
--body-bg: black;
--msger-bg: linear-gradient(to left, #383838, #000000);
@@ -126,7 +116,6 @@
--wb-hbg: #000000;
--my-settings-label-color: white;
*/
/* sky theme
--body-bg: black;
--msger-bg: linear-gradient(to left, #383838, #000000);
@@ -142,7 +131,6 @@
--wb-hbg: #000000;
--my-settings-label-color: white;
*/
/* ghost theme
--body-bg: black;
--msger-bg: linear-gradient(to left, transparent, rgba(0, 0, 0, 0.7));
@@ -158,7 +146,6 @@
--wb-hbg: #000000;
--my-settings-label-color: white;
*/
/* https://developer.mozilla.org/it/docs/Web/CSS/object-fit */
--video-object-fit: cover;
}
@@ -187,7 +174,8 @@ body {
justify-content: center;
align-items: center;
height: 100vh;
opacity: 0; /* make things invisible upon start */
opacity: 0;
/* make things invisible upon start */
-webkit-animation: fadeIn ease-in 1;
-moz-animation: fadeIn ease-in 1;
animation: fadeIn ease-in 1;
@@ -211,9 +199,11 @@ body {
left: 60%;
transform: translate(-50%, -50%);
}
#loadingDiv h1 {
font-size: 70px;
}
#loadingDiv pre {
font-size: 15px;
}
@@ -241,6 +231,7 @@ body {
opacity: 0.5;
}
}
@keyframes pulsate {
0% {
opacity: 0.5;
@@ -252,6 +243,7 @@ body {
opacity: 0.5;
}
}
@-webkit-keyframes pulsate {
0% {
opacity: 0.5;
@@ -274,7 +266,8 @@ body {
position: absolute;
padding: 10px;
background: var(--bg);
font-size: small; /* 4 mobile */
font-size: small;
/* 4 mobile */
font-weight: bold;
text-align: center;
width: 100%;
@@ -297,6 +290,7 @@ body {
animation-duration: 1s;
overflow: hidden;
}
.statusMenu i,
.statusMenu p,
.statusMenu h4 {
@@ -305,6 +299,7 @@ body {
border: none;
margin-right: 10px;
}
.statusMenu button {
float: right;
margin-right: 3px;
@@ -313,6 +308,7 @@ body {
display: inline;
border: none;
}
.statusMenu p:hover,
.statusMenu h4:hover,
.statusMenu button:hover {
@@ -343,25 +339,20 @@ body {
display: none;
position: absolute;
padding: 15px;
top: var(--btns-top);
right: var(--btns-right);
left: var(--btns-left);
margin-left: var(--btns-margin-left);
width: var(--btns-width);
flex-direction: var(--btns-flex-direction);
justify-content: space-around;
grid-gap: 0.4rem;
-webkit-transform: translate(0%, -50%);
-ms-transform: translate(0%, -50%);
transform: translate(0%, -50%);
border-radius: 20px;
background: transparent;
box-shadow: var(--box-shadow);
-webkit-animation: fadeIn ease-in 1;
-moz-animation: fadeIn ease-in 1;
animation: fadeIn ease-in 1;
@@ -435,6 +426,7 @@ body {
color: var(--hover-color);
transform: var(--btns-hover-scale);
}
#leaveRoomBtn:hover {
color: red;
transform: var(--btns-hover-scale);
@@ -521,6 +513,7 @@ button {
border-radius: 5px;
transition: background 0.23s;
}
.msger-header-options button:hover {
color: var(--hover-color);
transform: var(--btns-hover-scale);
@@ -537,14 +530,18 @@ button {
padding: 10px;
background: var(--msger-bg);
}
.msger-chat::-webkit-scrollbar {
width: 5px;
}
.msger-chat::-webkit-scrollbar-track {
background: transparent;
}
.msger-chat::-webkit-scrollbar-thumb {
background: black; /*aqua;*/
background: black;
/*aqua;*/
}
.msg {
@@ -576,16 +573,19 @@ button {
.right-msg {
flex-direction: row-reverse;
}
.right-msg .msg-bubble {
background: var(--right-msg-bg);
border-bottom-right-radius: 0;
color: #fff;
}
.right-msg .private-msg-bubble {
background: var(--private-msg-bg);
border-bottom-right-radius: 0;
color: #fff;
}
.right-msg .msg-img {
margin: 0 0 0 10px;
}
@@ -806,10 +806,13 @@ video {
object-fit: var(--video-object-fit);
cursor: pointer;
}
video:fullscreen {
object-fit: contain; /* cover; */
object-fit: contain;
/* cover; */
border: var(--elem-border-color);
}
.video {
float: left;
width: 25vw;
@@ -817,10 +820,12 @@ video:fullscreen {
overflow: hidden;
position: relative;
}
.video.one {
width: 100vw;
height: 100vh;
}
.video.two {
width: 49.6vw;
height: 99vh;
@@ -828,6 +833,7 @@ video:fullscreen {
border: var(--elem-border-color);
/* --video-object-fit: contain; */
}
.video.three {
/* width: 33vw;
height: 99vh; */
@@ -835,18 +841,21 @@ video:fullscreen {
--video-object-fit: cover;
border: var(--elem-border-color);
}
.video.four {
width: 49.6vw;
height: 49vh;
--video-object-fit: cover;
border: var(--elem-border-color);
}
.video.five {
width: 33vw;
height: 49vh;
--video-object-fit: cover;
border: var(--elem-border-color);
}
.video.six {
width: 33vw;
height: 49vh;
@@ -1008,6 +1017,7 @@ video:fullscreen {
}
/* Style the tab */
.tab {
overflow: hidden;
border: 1px solid rgb(0, 0, 0);
@@ -1015,6 +1025,7 @@ video:fullscreen {
}
/* Style the buttons inside the tab */
.tab button {
background-color: inherit;
float: left;
@@ -1027,6 +1038,7 @@ video:fullscreen {
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: transparent;
color: var(--hover-color);
@@ -1034,11 +1046,13 @@ video:fullscreen {
}
/* Create an active/current tablink class */
.tab button.active {
background-color: rgb(30 29 29);
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
@@ -1047,6 +1061,7 @@ video:fullscreen {
}
/* on open display devices tab */
#tabDevices {
display: block;
}
@@ -1063,10 +1078,12 @@ video:fullscreen {
color: white !important;
background-color: transparent !important;
}
.swal2-file {
color: white !important;
background-color: transparent !important;
}
.swal2-html-container {
color: rgb(165, 165, 165) !important;
background-color: transparent !important;
@@ -1077,6 +1094,7 @@ video:fullscreen {
font-size: 0.8rem !important;
}
*/
.swal2-select {
background-color: black !important;
color: white !important;
@@ -1106,6 +1124,7 @@ video:fullscreen {
opacity: 0.5;
}
}
@keyframes pulsate {
0% {
opacity: 0.5;
@@ -1117,6 +1136,7 @@ video:fullscreen {
opacity: 0.5;
}
}
@-webkit-keyframes pulsate {
0% {
opacity: 0.5;
@@ -1171,6 +1191,7 @@ video:fullscreen {
background-color: transparent;
transition: background 0.23s;
}
#sendAbortBtn:hover {
color: rgb(255, 0, 0);
transform: var(--btns-hover-scale);
@@ -1213,6 +1234,7 @@ progress {
-moz-animation-duration: 1s;
animation-duration: 1s;
}
#videoUrlHeader {
position: absolute;
display: flex;
@@ -1223,6 +1245,7 @@ progress {
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.7);
}
#videoUrlHeader button {
height: 30px;
width: 30px;
@@ -1233,11 +1256,13 @@ progress {
color: white;
background: black;
}
#videoUrlHeader button:hover {
color: var(--hover-color);
transform: var(--btns-hover-scale);
transition: all 0.3s ease-in-out;
}
#videoUrlIframe {
width: var(--iframe-width);
height: var(--iframe-height);
@@ -1304,6 +1329,26 @@ progress {
width: 50%;
}
.speechbar {
width: 2%;
height: 20%;
position: absolute;
bottom: 0;
right: 0;
border-radius: 10%;
}
.bar {
width: 100%;
display: block;
font-family: arial;
font-size: 12px;
background-color: #19bb5c;
color: #fff;
position: absolute;
bottom: 0;
}
/*
z-index
7 statusMenu -----
+33
View File
@@ -170,6 +170,7 @@ let msgerCPList;
let msgerEmojiPicker;
let emojiPicker;
// my settings
let myPeerId;
let mySettings;
let mySettingsHeader;
let tabDevicesBtn;
@@ -997,6 +998,10 @@ function handleRTCDataChannels(peer_id) {
case 'speech':
handleDataChannelSpeechTranscript(dataMessage);
break;
case 'micVolume':
dataMessage.peer_id = peer_id; // to create animation on specific video element
handlePeerVolume(dataMessage);
break;
}
} catch (err) {
console.error('mirotalk_chat_channel', err);
@@ -1519,6 +1524,8 @@ function loadRemoteMediaStream(stream, peers, peer_id) {
const remotePrivateMsgBtn = document.createElement('button');
const remoteYoutubeBtnBtn = document.createElement('button');
const remotePeerKickOut = document.createElement('button');
const pitchMeter = document.createElement('div');
const pitchBar = document.createElement('div');
const remoteVideoFullScreenBtn = document.createElement('button');
const remoteVideoAvatarImage = document.createElement('img');
@@ -1583,6 +1590,13 @@ function loadRemoteMediaStream(stream, peers, peer_id) {
remoteVideoAvatarImage.setAttribute('id', peer_id + '_avatar');
remoteVideoAvatarImage.className = 'videoAvatarImage pulsate';
//for pitch meter
pitchMeter.setAttribute('id', peer_id + '_pitch');
pitchBar.setAttribute('id', peer_id + '_pitch_bar');
pitchMeter.className = 'speechbar';
pitchBar.className = 'bar';
pitchBar.style.height = '1%';
// add elements to remoteStatusMenu div
remoteStatusMenu.appendChild(remoteVideoParagraphImg);
remoteStatusMenu.appendChild(remoteVideoParagraph);
@@ -1607,6 +1621,8 @@ function loadRemoteMediaStream(stream, peers, peer_id) {
// add elements to videoWrap div
remoteVideoWrap.appendChild(remoteStatusMenu);
remoteVideoWrap.appendChild(remoteVideoAvatarImage);
pitchMeter.appendChild(pitchBar);
remoteVideoWrap.appendChild(pitchMeter);
remoteVideoWrap.appendChild(remoteMedia);
document.body.appendChild(remoteVideoWrap);
@@ -1886,6 +1902,7 @@ function setShareRoomBtn() {
function setAudioBtn() {
audioBtn.addEventListener('click', (e) => {
handleAudio(e, false);
startPitchDetection();
});
}
@@ -5536,3 +5553,19 @@ function getSl(selector) {
function getEcN(className) {
return document.getElementsByClassName(className);
}
// for detecting mic volume
function handlePeerVolume(data) {
let peer_id = data.peer_id;
let element = document.getElementById(peer_id + '_pitch_bar');
let volume = data.volume + 25; //for design purpose
if (volume > 50) {
element.style.backgroundColor = 'orange';
}
element.style.height = volume + '%';
setTimeout(function () {
element.style.backgroundColor = '#19bb5c';
element.style.height = '1%';
}, 700);
}
+81
View File
@@ -0,0 +1,81 @@
function startPitchDetection() {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
mediaStreamSource = audioContext.createMediaStreamSource(stream);
meter = createAudioMeter(audioContext);
mediaStreamSource.connect(meter);
});
}
}
function createAudioMeter(audioContext, clipLevel, averaging, clipLag) {
const 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) {
const buf = event.inputBuffer.getChannelData(0);
const bufLength = buf.length;
let sum = 0;
let 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.
const 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);
let final_volume = Math.round(this.volume * 100);
if (myAudioStatus && final_volume > 5) {
config = {
type: 'micVolume',
volume: final_volume,
};
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));
}
}
}
}
+1 -1
View File
@@ -96,7 +96,6 @@ access to use this app.
<button id="aboutBtn" class="fas fa-question"></button>
<button id="leaveRoomBtn" class="fas fa-phone-slash"></button>
</div>
<!-- End left buttons -->
<!-- Start chat room
@@ -384,6 +383,7 @@ access to use this app.
<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/detectSpeaking.js"></script>
<script defer src="../js/speechRecognition.js"></script>
<!-- end of Js scripts -->