diff --git a/public/index.css b/public/index.css index 39bd8dd..2017087 100644 --- a/public/index.css +++ b/public/index.css @@ -5,6 +5,7 @@ html,body{ body{ background-color: #141414; overflow: hidden; + font-family: system-ui; } *{ box-sizing: border-box; @@ -73,6 +74,7 @@ video{ top: 0; bottom: 0; display: flex; + flex-direction: column; } .tool-container > .tools{ margin: auto; @@ -98,3 +100,43 @@ video{ line-height: 2; } +.tool-container > .namer{ + flex: 0 0 auto; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 10px; + overflow: hidden; + color: white; + display: flex; + flex-direction: row; + gap: 10px; + line-height: 2; + margin: 10px; + width: max-content; + padding: 0 10px; + + .avatar { + display: flex; + & > *{ + margin: auto; + } + } +} + +.tool-container > .progress{ + margin-top: auto; + margin-bottom: 10px; + width: 250px; + margin-left: auto; + margin-right: auto; + height: 5px; + border-radius: 5px; + background-color: white; + overflow: auto; + + & .progress-box { + height: 5px; + width: 50%; + background-color: red; + transition: width 0.05s linear; + } +} \ No newline at end of file diff --git a/public/index.js b/public/index.js index a069928..d571d6b 100644 --- a/public/index.js +++ b/public/index.js @@ -1,3 +1,4 @@ +const url = new URL(window.location); /** * @type {import("./MWSE/index").default} */ @@ -6,6 +7,14 @@ let mwse; * @type {string} */ let mySocketId; +/** + * @type {string} + */ +let myIPAddress; +/** + * @type {string} + */ +let myNumber; /** * @type {string} */ @@ -33,19 +42,11 @@ function connect() mwse = new MWSE({ endpoint: "wss://ws.saqut.com" }); - - MWSE.rtc.defaultICEServers = [{ - urls: "turn:20.166.82.187:3478", - username: "turnserver", - credential: "turnserver" - },{ - urls: "stun:stun.l.google.com:19302" - }]; mwse.scope(beginEngine); } - +let peername = url.searchParams.get("user"); let interact = false; @@ -64,23 +65,31 @@ document.addEventListener("click",()=>{ */ let activeVideo; -function templateVideo(name, stream,infinitedMute) +function templateVideo(name, stream,infinitedMute, peername) { let t = new DOMParser().parseFromString(` -
-
`,"text/html"); @@ -93,14 +102,17 @@ function templateVideo(name, stream,infinitedMute) i.muted = 1; i.classList.add("soundon"); } - if(stream) i.srcObject = stream; + if(stream){ + i.srcObject = stream; + bindAudioLevel(stream, t.querySelector(".progress-box")); + } return t.querySelector("div"); } -function addVideoList(name, stream, peer, infinitedMute) +function addVideoList(name, stream, peer, infinitedMute, name) { if(!videoContainer.querySelector(`[name="${name}"]`)) { - let video = templateVideo(name, stream, infinitedMute); + let video = templateVideo(name, stream, infinitedMute, name); video.dataset.user = peer.socketId; videoContainer.appendChild(video); } @@ -111,10 +123,6 @@ function removeVideoList(name) if(videoContainer.querySelector(`[data-user="${name}"]`)) { let k = videoContainer.querySelector(`[data-user="${name}"]`); - if(k.dataset.user == activeVideo?.dataset.user || !activeVideo) - { - activePeer = null; - } k.remove(); } } @@ -124,8 +132,8 @@ async function beginEngine() let me = mwse.peer("me"); me.disablePairAuth(); mySocketId = me.socketId; - - let url = new URL(window.location); + myIPAddress = await mwse.virtualPressure.allocAPIPAddress(); + myNumber = await mwse.virtualPressure.allocAPNumber(); roomid = url.searchParams.get("room"); if(!!roomid == 0) @@ -178,7 +186,8 @@ async function startOutgoingWebcam() { width: { exact: 240 } } ], facingMode: "user" - } + }, + audio: true }); outgoingStream = mediaStream; } @@ -199,47 +208,62 @@ async function connectRoom() notifyActionInvite: false, notifyActionJoined: true }); + + await mwse.peer('me').info.set("name", peername); + await room.createRoom(); - room.on("join", peer => IncomingPeer(peer,true)); + room.on("join", peer => IncomingPeer(peer, true)); room.on("eject", peer => OutgoingPeer(peer)); for (const peer of await room.fetchPeers()) { - if(peer.socketId != mwse.peer('me').socketId){ - IncomingPeer(peer,false) - } + IncomingPeer(peer) } - addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true) + addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true, peername); }; /** * @param {import("./MWSE/Peer").default} peer */ -function IncomingPeer(peer,activeConnect) +async function IncomingPeer(peer,activeConnect) { + await peer.info.fetch(); + + peer.createRTC({ + iceCandidatePoolSize: 0 + },[{ + urls: "turn:20.166.82.187:3478", + username: "turnserver", + credential: "turnserver" + },{ + urls: "stun:stun.l.google.com:19302" + }]); + if(activeConnect) { peer.rtc.connect(); } peer.rtc.rtc.turboBitrate = 0; peer.rtc.on('connected',() => { - console.log("Connected"); if(!activeConnect) { peer.rtc.sendStream(outgoingStream, "Webcam", {}); - activePeers[peer.socketId] = peer.rtc.rtc; } }); peer.rtc.on('disconnected',() => { - console.log("Disconnected"); - removeVideoList(peer.streamY, peer); + removeVideoList(peer.socketId, peer); delete activePeers[peer.socketId]; }); peer.rtc.on("stream:added", ({stream,name}) => { - peer.streamY = peer.socketId + " | " + name + " - " + stream.id; - addVideoList(peer.socketId + " | " + name + " - " + stream.id,stream, peer); + addVideoList( + peer.socketId, + stream, + peer, + void 0, + peer.info.get("name") + ); if(activeConnect) { peer.rtc.sendStream(outgoingStream, "Webcam", {}); @@ -252,12 +276,11 @@ function IncomingPeer(peer,activeConnect) function OutgoingPeer(peer) { removeVideoList(peer.socketId, peer); + delete activePeers[peer.socketId]; } let relative; - - setInterval(() => { for(const [,peerRtc] of Object.entries(activePeers)) { @@ -275,4 +298,51 @@ setInterval(() => { } } } -},1000); \ No newline at end of file +},1000); + +function bindAudioLevel(stream, element, options = {}) { + const { + minPercent = 5, + maxPercent = 100, + decayRate = 0.97, // 0.9–0.99 arasında önerilir + volumeScale = 2.0 // gelen rms değerini büyütmek için (normalize daha geniş aralık) + } = options; + + const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + const source = audioCtx.createMediaStreamSource(stream); + const analyser = audioCtx.createAnalyser(); + + analyser.fftSize = 512; + analyser.smoothingTimeConstant = 0.1; + + const dataArray = new Uint8Array(analyser.frequencyBinCount); + source.connect(analyser); + + const track = stream.getAudioTracks()[0]; + const bufferLength = analyser.frequencyBinCount; + + function update() + { + if (track.readyState === 'ended' || !track.enabled) { + source.disconnect(); + analyser.disconnect(); + audioCtx.close(); + return; + } + analyser.getByteFrequencyData(dataArray); + + // Ortalama ses seviyesi hesapla + let sum = 0; + for (let i = 0; i < bufferLength; i++) { + sum += dataArray[i]; + } + const avg = sum / bufferLength; + + // Ortalama değeri % olarak hesapla (0-255 arası değer) + const volumePercent = Math.min(100, (avg / 255) * 100); + element.style.width = `${volumePercent * 2}%`; + requestAnimationFrame(update); + } + + requestAnimationFrame(update); +}