Example streaming

This commit is contained in:
Yasin İLKAYA 2023-05-16 15:47:16 +03:00
parent 356b5341b2
commit 70cf3a03e4
4 changed files with 398 additions and 5 deletions

View File

@ -30,12 +30,11 @@ app.get("/test",(request, response)=>{
app.get("/index.js.map",(request, response)=>{
response.sendFile(resolve("./script/index.js.map"))
});
app.get("/webrtc.js",(request, response)=>{
response.sendFile(resolve("./script/webrtc.js"))
});
app.get("/webrtc.adapter.js",(request, response)=>{
response.sendFile(resolve("./script/webrtc.adapter.js"))
app.get("/stream",(request, response)=>{
response.sendFile(resolve("./public/index.html"))
});
app.use("/stream",express.static(resolve("./public")));
app.get("/",(request, response)=>{
response.sendFile(resolve("./script/index.html"))
});

93
public/index.css Normal file
View File

@ -0,0 +1,93 @@
html,body{
margin: 0;
height: 100%;
}
body{
background-color: #141414;
}
.root{
gap: 10px;
padding: 10px;
height: 100%;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
box-sizing: border-box;
}
.dialoque{
flex: 1;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
position: relative;
}
.videolist{
flex: 0 0 200px;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
gap: 10px;
overflow: auto;
padding-right: 10px;
cursor: pointer;
}
.dialoque #primaryVideo{
width: 100%;
height: 100%;
box-sizing: border-box;
object-fit: contain;
background-color: transparent/*#282828*/;
border-radius: 10px;
z-index: 2;
}
.dialoque #primaryVideoShadow{
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 10px;
position: absolute;
z-index: 1;
left: 0;
top: 0;
}
.dialoque #secondaryVideo{
width: 300px;
height: 200px;
min-width: 300px;
max-width: 30%;
min-height: 200px;
max-height: 35%;
position: absolute;
right: 10px;
bottom: 10px;
background-color: #383838;
border-radius: 10px;
z-index: 3;
outline-offset: 0px;
outline-style: solid;
outline-width: 5px;
outline-color: rgba(0,0,0,.5);
}
.videolist .frame{
max-width: 200px;
object-fit: cover;
border-radius: 10px;
border: solid 3px transparent;
}
.videolist .frame.active{
border: solid 3px green;
box-shadow: 0px 0px 20px -10px green;
}
video{
image-rendering: pixelated;
}
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-thumb {
background: white;
border-radius: 10px;
}
::-webkit-scrollbar-track {
background-color: #ffffff1f;
}

42
public/index.html Normal file
View File

@ -0,0 +1,42 @@
<html lang="tr">
<head>
<base href="/stream/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>saQüt Video Streaming</title>
<script src="https://ws.saqut.com/script"></script>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div class="root">
<div class="dialoque">
<video
id="primaryVideo"
muted
playsinline
autoplay
>
</video>
<video
id="primaryVideoShadow"
muted
playsinline
autoplay
>
</video>
<video
id="secondaryVideo"
muted
playsinline
autoplay
>
</video>
</div>
<div class="videolist">
</div>
</div>
<script src="index.js"></script>
</body>
</html>

259
public/index.js Normal file
View File

@ -0,0 +1,259 @@
/**
* @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 primaryVideoContent;
/**
* @type {HTMLVideoElement}
*/
let primaryVideo;
/**
* @type {HTMLVideoElement}
*/
let primaryVideoShadow;
/**
* @type {HTMLVideoElement}
*/
let secondaryVideo;
/**
* @type {MediaStream}
*/
let outgoingStream;
/**
* @type {MediaStream}
*/
let outgoingStreamOnlyVideo;
/**
* @type {HTMLDivElement}
*/
let videoContainer = document.querySelector(".videolist");
function connect()
{
mwse = new MWSE({
endpoint: "wss://ws.saqut.com"
});
mwse.scope(beginEngine);
}
/**
* @type {HTMLVideoElement}
*/
let activeVideo;
function setPrimaryVideo(video, soundOn)
{
primaryVideo.srcObject = video;
primaryVideoShadow.srcObject = video;
if(soundOn == undefined)
{
primaryVideo.muted = 1;
primaryVideo.volume = 0;
}else if(soundOn){
primaryVideo.muted = 0;
primaryVideo.volume = 1;
}else{
primaryVideo.muted = 0;
primaryVideo.volume = 0;
}
}
function setSecondaryVideo(video)
{
secondaryVideo.srcObject = video;
}
function templateVideo(name, stream)
{
let i = document.createElement("video");
i.muted = 1;
i.classList.add("frame")
i.playsInline = 1;
i.autoplay = 1;
i.dataset.name = name;
if(stream) i.srcObject = stream;
return i;
}
function addVideoList(name, stream, peer)
{
if(!videoContainer.querySelector(`[name="${name}"]`))
{
let video = templateVideo(name, stream);
video.dataset.user = peer.socketId;
video.onclick = function(){
if(activeVideo)
{
activeVideo.classList.remove("active");
};
video.classList.add("active");
activeVideo = video;
setPrimaryVideo(stream, true);
};
videoContainer.appendChild(video);
}
}
function removeVideoList(name)
{
if(videoContainer.querySelector(`[data-name="${name}"]`))
{
let k = videoContainer.querySelector(`[data-name="${name}"]`);
let user = k.dataset.user;
if(k.dataset.user == activeVideo.dataset.user)
{
setPrimaryVideo(outgoingStreamOnlyVideo, false);
}
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();
let url = new URL(window.location);
roomid = url.searchParams.get("room");
if(!!roomid == 0)
{
let hash = window.crypto.randomUUID();
url.searchParams.set("room", hash);
window.location = url.href;
};
connectRoom(roomid);
};
window.addEventListener("load", () => {
primaryVideo = document.querySelector("#primaryVideo");
secondaryVideo = document.querySelector("#secondaryVideo");
primaryVideoShadow = document.querySelector("#primaryVideoShadow");
connect()
});
async function startOutgoingWebcam()
{
outgoingStream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
outgoingStreamOnlyVideo = new MediaStream(outgoingStream);
outgoingStreamOnlyVideo.removeTrack(outgoingStreamOnlyVideo.getAudioTracks()[0])
}
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 room.createRoom();
room.on("join", peer => IncomingPeer(peer, true));
room.on("eject", peer => OutgoingPeer(peer));
for (const peer of await room.fetchPeers()) {
IncomingPeer(peer)
}
if(!primaryVideoContent)
{
setPrimaryVideo(outgoingStreamOnlyVideo);
}
setSecondaryVideo(outgoingStreamOnlyVideo);
addVideoList("My Webcam",outgoingStreamOnlyVideo, mwse.peer("me"))
}
/**
* @param {import("./MWSE/Peer").default} peer
*/
function IncomingPeer(peer,activeConnect)
{
let sendedOTP = false;
peer.createRTC({
iceServers:[{
urls: "turn:161.97.136.175:3478",
username: "argist-eu-east-25",
credential: "ee7df17eed35f4cf5a207777f3c0cd7d3b1901a5de7aff52ea55742289d7fee2"
},{
urls: "stun:stun.l.google.com:19302"
},{
urls: "stun:stun1.l.google.com:19302"
},{
urls: "stun:stun2.l.google.com:19302"
},{
urls: "stun:stun3.l.google.com:19302"
},{
urls: "stun:stun4.l.google.com:19302"
}],
bundlePolicy: "max-compat",
iceCandidatePoolSize: 0,
iceTransportPolicy: "all"
});
if(activeConnect)
{
peer.rtc.connect();
}
peer.rtc.on('connected',() => {
if(!activeConnect && !sendedOTP)
{
sendedOTP = true;
peer.rtc.sendStream(outgoingStream, "Webcam", {});
}
});
peer.rtc.on('disconnected',() => {
removeVideoList(peer.streamY, peer);
});
peer.rtc.on("stream:added", ({stream,name}) => {
peer.streamY = peer.socketId + " | " + name + " - " + stream.id;
addVideoList(peer.socketId + " | " + name + " - " + stream.id,stream, peer);
if(!primaryVideoContent)
{
primaryVideoContent = stream;
setPrimaryVideo(primaryVideoContent, true);
}
if(activeConnect && !sendedOTP)
{
sendedOTP = true;
peer.rtc.sendStream(outgoingStream, "Webcam", {});
}
})
}
/**
* @param {import("./MWSE/Peer").default} peer
*/
function OutgoingPeer(peer)
{
removeVideoList(peer.streamY, peer);
}