First test version
This commit is contained in:
commit
e3b8716a85
10
.editorconfig
Normal file
10
.editorconfig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{js,json,yml,mjs}]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 3
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/.yarn/*
|
||||||
|
!/.yarn/patches
|
||||||
|
!/.yarn/plugins
|
||||||
|
!/.yarn/releases
|
||||||
|
!/.yarn/sdks
|
||||||
|
|
||||||
|
# Swap the comments on the following lines if you don't wish to use zero-installs
|
||||||
|
# Documentation here: https://yarnpkg.com/features/zero-installs
|
||||||
|
/.yarn/cache
|
||||||
|
/.pnp.*
|
||||||
|
node_modules
|
768
.yarn/releases/yarn-3.1.1.cjs
vendored
Normal file
768
.yarn/releases/yarn-3.1.1.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
3
.yarnrc.yml
Normal file
3
.yarnrc.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
npmRegistryServer: "https://npm.hibas123.de"
|
||||||
|
nodeLinker: "node-modules"
|
||||||
|
yarnPath: .yarn/releases/yarn-3.1.1.cjs
|
11
package-lock.json
generated
Normal file
11
package-lock.json
generated
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"requires": true,
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"yarn": {
|
||||||
|
"version": "1.22.17",
|
||||||
|
"resolved": "https://npm.hibas123.de/yarn/-/yarn-1.22.17.tgz",
|
||||||
|
"integrity": "sha512-H0p241BXaH0UN9IeH//RT82tl5PfNraVpSpEoW+ET7lmopNC61eZ+A+IDvU8FM6Go5vx162SncDL8J1ZjRBriQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
package.json
Normal file
16
package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "ScreenSharingThing",
|
||||||
|
"packageManager": "yarn@3.1.1",
|
||||||
|
"scripts": {
|
||||||
|
"start": "ts-node src/index.ts"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^16.11.11",
|
||||||
|
"ts-node": "^10.4.0",
|
||||||
|
"typescript": "^4.5.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"peer": "^0.6.1"
|
||||||
|
}
|
||||||
|
}
|
45
public/index.html
Normal file
45
public/index.html
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>SimpleStream</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
|
||||||
|
integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://unpkg.com/peerjs@1.3.1"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h1>SimpleStream</h1>
|
||||||
|
<h2>Your ID: <span id="streamId"></span></h2>
|
||||||
|
<div id="streamURLCont">
|
||||||
|
<h2>Connect URL: <a id="streamURL"></a></h2>
|
||||||
|
</div>
|
||||||
|
<div id="connectToCont">
|
||||||
|
<h2>Connecting to: <span id="connectToID"></span></h2>
|
||||||
|
<button id="startStramBTN">Start Stream</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<video id="localVideo" style="width: 100%" controls></video>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script src="main.mjs" type="module">
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
162
public/main.mjs
Normal file
162
public/main.mjs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
function simpleFramwork() {
|
||||||
|
let obj = {};
|
||||||
|
|
||||||
|
return new Proxy(obj, {
|
||||||
|
get(_, prop) {
|
||||||
|
const [id, param] = prop.split("_");
|
||||||
|
let elm = document.getElementById(id);
|
||||||
|
if (!elm) {
|
||||||
|
console.log(`Element with id ${id} not found`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (param) {
|
||||||
|
case "value":
|
||||||
|
return elm.value;
|
||||||
|
case "href":
|
||||||
|
return elm.href;
|
||||||
|
case "style":
|
||||||
|
return elm.getAttribute("style");
|
||||||
|
case "text":
|
||||||
|
return elm.innerText;
|
||||||
|
case undefined:
|
||||||
|
return elm;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(_, prop, value) {
|
||||||
|
const [id, param] = prop.split("_");
|
||||||
|
let elm = document.getElementById(id);
|
||||||
|
if (!elm) {
|
||||||
|
console.log(`Element with id ${id} not found`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (param) {
|
||||||
|
case "value":
|
||||||
|
elm.value = value;
|
||||||
|
break;
|
||||||
|
case "href":
|
||||||
|
elm.href = value;
|
||||||
|
break;
|
||||||
|
case "click":
|
||||||
|
elm.addEventListener("click", value);
|
||||||
|
break;
|
||||||
|
case "style":
|
||||||
|
elm.setAttribute("style", value);
|
||||||
|
break;
|
||||||
|
case "text":
|
||||||
|
elm.innerText = value;
|
||||||
|
break;
|
||||||
|
case undefined:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sf = simpleFramwork();
|
||||||
|
|
||||||
|
sf.streamId_text = "Loading...";
|
||||||
|
sf.streamURL_text = "Loading...";
|
||||||
|
|
||||||
|
let connectToId = new URL(window.location.href).searchParams.get("id");
|
||||||
|
|
||||||
|
let bitrate = new URL(window.location.href).searchParams.get("br") || 10000;
|
||||||
|
|
||||||
|
if (connectToId) {
|
||||||
|
sf.streamURLCont_style = "display:none";
|
||||||
|
sf.connectToCont_style = "display:block";
|
||||||
|
sf.connectToID_text = connectToId;
|
||||||
|
} else {
|
||||||
|
sf.streamURLCont_style = "display:block";
|
||||||
|
sf.connectToCont_style = "display:none";
|
||||||
|
}
|
||||||
|
|
||||||
|
var peer = new Peer({
|
||||||
|
host: window.location.hostname,
|
||||||
|
port: window.location.port,
|
||||||
|
path: "/peerjs",
|
||||||
|
});
|
||||||
|
|
||||||
|
function bitrateTransform(sdp) {
|
||||||
|
var arr = sdp.split("\r\n");
|
||||||
|
arr.forEach((str, i) => {
|
||||||
|
if (/^a=fmtp:\d*/.test(str)) {
|
||||||
|
arr[i] =
|
||||||
|
str +
|
||||||
|
`;x-google-max-bitrate=${bitrate};x-google-min-bitrate=0;x-google-start-bitrate=6000`;
|
||||||
|
} else if (/^a=mid:(1|video)/.test(str)) {
|
||||||
|
arr[i] += "\r\nb=AS:" + bitrate;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return arr.join("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
peer.on("open", (id) => {
|
||||||
|
console.log("ID", id);
|
||||||
|
sf.streamId_text = id;
|
||||||
|
let url = new URL(window.location.href);
|
||||||
|
url.searchParams.set("id", id);
|
||||||
|
sf.streamURL_text = url.href;
|
||||||
|
sf.streamURL_href = url.href;
|
||||||
|
|
||||||
|
let con = peer.connect(connectToId);
|
||||||
|
con.on("data", console.log);
|
||||||
|
con.on("open", () => con.send("Hello"));
|
||||||
|
|
||||||
|
if (connectToId) {
|
||||||
|
sf.startStramBTN_click = () => {
|
||||||
|
navigator.mediaDevices
|
||||||
|
.getDisplayMedia({
|
||||||
|
video: true,
|
||||||
|
})
|
||||||
|
.then((stream) => {
|
||||||
|
let v = sf.localVideo;
|
||||||
|
v.srcObject = stream;
|
||||||
|
v.play();
|
||||||
|
const conn = peer.call(connectToId, stream, {
|
||||||
|
sdpTransform: bitrateTransform,
|
||||||
|
});
|
||||||
|
conn.on("stream", console.log);
|
||||||
|
conn.on("close", console.log);
|
||||||
|
conn.on("error", console.log);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
peer.on("connection", (conn) => {
|
||||||
|
console.log("connection", conn);
|
||||||
|
conn.on("data", console.log);
|
||||||
|
});
|
||||||
|
|
||||||
|
peer.on("error", console.error);
|
||||||
|
peer.on("close", console.log);
|
||||||
|
peer.on("disconnected", console.log);
|
||||||
|
peer.on("error", console.log);
|
||||||
|
|
||||||
|
peer.on("call", (call) => {
|
||||||
|
console.log("Call", call);
|
||||||
|
call.answer(undefined);
|
||||||
|
call.on("stream", console.log);
|
||||||
|
call.on("close", console.log);
|
||||||
|
call.on("error", console.log);
|
||||||
|
call.on("stream", (remoteStream) => {
|
||||||
|
console.log("stream", remoteStream);
|
||||||
|
let v = sf.localVideo;
|
||||||
|
v.srcObject = remoteStream;
|
||||||
|
v.play();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function createEmptyVideoTrack({ width, height }) {
|
||||||
|
const canvas = Object.assign(document.createElement("canvas"), {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
});
|
||||||
|
canvas.getContext("2d").fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
const stream = canvas.captureStream();
|
||||||
|
const track = stream.getVideoTracks()[0];
|
||||||
|
|
||||||
|
return Object.assign(track, { enabled: false });
|
||||||
|
}
|
11
src/index.ts
Normal file
11
src/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { ExpressPeerServer } from "peer";
|
||||||
|
import * as express from "express";
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const server = app.listen(3000);
|
||||||
|
const peerServer = ExpressPeerServer(server, {
|
||||||
|
path: "/",
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use("/peerjs", peerServer as any);
|
||||||
|
app.use("/", express.static("public"));
|
10
tsconfig.json
Normal file
10
tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||||
|
"module": "commonjs" /* Specify what module code is generated. */,
|
||||||
|
"moduleResolution": "node" /* Specify how the compiler resolves module names. */,
|
||||||
|
"esModuleInterop": false /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
||||||
|
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||||
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user