MWSE/public/index.js

349 lines
8.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const url = new URL(window.location);
/**
* @type {import("./MWSE/index").default}
*/
let mwse;
/**
* @type {string}
*/
let mySocketId;
/**
* @type {string}
*/
let myIPAddress;
/**
* @type {string}
*/
let myNumber;
/**
* @type {string}
*/
let roomid;
/**
* @type {import("./MWSE/Room").default}
*/
let room;
/**
* @type {MediaStream}
*/
let outgoingStream;
/**
* @type {HTMLDivElement}
*/
let videoContainer = document.querySelector(".videolist");
let maxbitrate;
let resulation;
let activePeers = {}
let ofscreencanvas = document.createElement("canvas");
function connect()
{
mwse = new MWSE({
endpoint: "wss://ws.saqut.com"
});
mwse.scope(beginEngine);
}
let peername = url.searchParams.get("user");
let interact = false;
setInterval(()=>{
document.querySelectorAll(".soundon").forEach(e => (e.muted = 0,e.play()));
},1000)
document.addEventListener("click",()=>{
interact = true;
document.querySelectorAll(".soundon").forEach(e => (e.muted = 0,e.play()));
})
/**
* @type {HTMLVideoElement}
*/
let activeVideo;
function templateVideo(name, stream,infinitedMute, peername)
{
let t = new DOMParser().parseFromString(`
<div class="frame" data-name="${name}">
<video autoplay playsinline muted>
</video>
<div class="tool-container">
<div class="namer">
<div class="avatar">
<i class="material-icons">account_circle</i>
</div>
<div class="name">
${peername ?? "User"}
</div>
</div>
<div class="tools">
</div>
<div class="progress">
<div class="progress-box">
</div>
</div>
</div>
</div>
`,"text/html");
let i = t.querySelector("video");
if(infinitedMute == true)
{
i.muted = 1;
}else if(interact == false)
{
i.muted = 1;
i.classList.add("soundon");
}
if(stream){
i.srcObject = stream;
bindAudioLevel(stream, t.querySelector(".progress-box"));
}
return t.querySelector("div");
}
function addVideoList(name, stream, peer, infinitedMute, name)
{
if(!videoContainer.querySelector(`[name="${name}"]`))
{
let video = templateVideo(name, stream, infinitedMute, name);
video.dataset.user = peer.socketId;
videoContainer.appendChild(video);
}
}
function removeVideoList(name)
{
if(videoContainer.querySelector(`[data-user="${name}"]`))
{
let k = videoContainer.querySelector(`[data-user="${name}"]`);
k.remove();
}
}
async function beginEngine()
{
let me = mwse.peer("me");
me.disablePairAuth();
mySocketId = me.socketId;
myIPAddress = await mwse.virtualPressure.allocAPIPAddress();
myNumber = await mwse.virtualPressure.allocAPNumber();
roomid = url.searchParams.get("room");
if(!!roomid == 0)
{
let hash = window.crypto.randomUUID();
url.searchParams.set("room", hash);
window.location = url.href;
};
connectRoom(roomid);
if(url.searchParams.get("maxbitrate"))
{
let n = Number(url.searchParams.get("maxbitrate"));
if(Number.isFinite(n) && !Number.isNaN(n))
{
maxbitrate = n;
}else maxbitrate = 2500_000;
}else maxbitrate = 2500_000;
if(url.searchParams.get("resulation"))
{
let n = Number(url.searchParams.get("resulation"));
if(Number.isFinite(n) && !Number.isNaN(n))
{
resulation = n;
}else resulation = 1.2;
}else resulation = 1.2;
};
window.addEventListener("load", () => {
connect()
});
async function startOutgoingWebcam()
{
let mediaStream = await navigator.mediaDevices.getUserMedia({
video: /*true*/{
advanced: [
{ width: { exact: 1920 } },
{ width: { exact: 1600 } },
{ width: { exact: 1366 } },
{ width: { exact: 1280 } },
{ width: { exact: 1024 } },
{ width: { exact: 900 } },
{ width: { exact: 800 } },
{ width: { exact: 640 } },
{ width: { exact: 320 } },
{ width: { exact: 240 } }
],
facingMode: "user"
},
audio: true
});
outgoingStream = mediaStream;
}
async function connectRoom()
{
await startOutgoingWebcam();
room = mwse.room({
name: roomid,
joinType: "free",
accessType: "private",
description: "Private free joined room",
ifexistsJoin: true,
notifyActionEjected: true,
notifyActionInvite: false,
notifyActionJoined: true
});
await mwse.peer('me').info.set("name", peername);
await room.createRoom();
room.on("join", peer => IncomingPeer(peer, true));
room.on("eject", peer => OutgoingPeer(peer));
for (const peer of await room.fetchPeers()) {
IncomingPeer(peer)
}
addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true, peername);
};
/**
* @param {import("./MWSE/Peer").default} peer
*/
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',() => {
if(!activeConnect)
{
peer.rtc.sendStream(outgoingStream, "Webcam", {});
}
});
peer.rtc.on('disconnected',() => {
removeVideoList(peer.socketId, peer);
delete activePeers[peer.socketId];
});
peer.rtc.on("stream:added", ({stream,name}) => {
addVideoList(
peer.socketId,
stream,
peer,
void 0,
peer.info.get("name")
);
if(activeConnect)
{
peer.rtc.sendStream(outgoingStream, "Webcam", {});
}
})
}
/**
* @param {import("./MWSE/Peer").default} peer
*/
function OutgoingPeer(peer)
{
removeVideoList(peer.socketId, peer);
delete activePeers[peer.socketId];
}
let relative;
setInterval(() => {
for(const [,peerRtc] of Object.entries(activePeers))
{
if(peerRtc?.turboBitrate !== 1)
{
const senders = peerRtc.getSenders();
const videoSender = senders.find(sender => sender.track?.kind === 'video');
if(videoSender){
const parameters = videoSender.getParameters();
parameters.encodings[0].maxBitrate = maxbitrate;
parameters.encodings[0].scaleResolutionDownBy = resulation;
videoSender.setParameters(parameters).then(() => {
peerRtc.turboBitrate = 1;
});
}
}
}
},1000);
function bindAudioLevel(stream, element, options = {}) {
const {
minPercent = 5,
maxPercent = 100,
decayRate = 0.97, // 0.90.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);
}