aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMetaMuffin <metamuffin@yandex.com>2021-08-06 13:20:35 +0200
committerMetaMuffin <metamuffin@yandex.com>2021-08-06 13:20:35 +0200
commita8f89036b5788a3f6ddb053824650b913a0c98a3 (patch)
tree7bdd48b3d95b7e33fc59da046bedfe68129ad559
parent2387d8910d80b86a95e8c3242bdb6809dddda1aa (diff)
downloadkeks-meet-a8f89036b5788a3f6ddb053824650b913a0c98a3.tar
keks-meet-a8f89036b5788a3f6ddb053824650b913a0c98a3.tar.bz2
keks-meet-a8f89036b5788a3f6ddb053824650b913a0c98a3.tar.zst
idk
-rw-r--r--public/css/master.css125
-rw-r--r--public/favicon.icobin318 -> 0 bytes
-rw-r--r--public/index.html2
-rwxr-xr-xpublic/mkassets.sh7
-rw-r--r--source/client/helper.ts14
-rw-r--r--source/client/index.ts36
-rw-r--r--source/client/local_user.ts51
-rw-r--r--source/client/room.ts6
-rw-r--r--source/client/user.ts79
-rw-r--r--source/server/index.ts1
10 files changed, 283 insertions, 38 deletions
diff --git a/public/css/master.css b/public/css/master.css
index e69de29..794eb43 100644
--- a/public/css/master.css
+++ b/public/css/master.css
@@ -0,0 +1,125 @@
+@import url("https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;700&display=swap");
+
+* {
+ font-family: "Ubuntu", sans-serif;
+ font-weight: 300;
+ color: white;
+}
+
+:root {
+ --bg: #263238;
+ --bg-dark: #000a12;
+ --bg-light: #354b58;
+ --bg-lighter: #4f5b62;
+ --bg-disabled: #720000;
+ --bg-enabled: #097200;
+ --ac: #4a148c;
+ --ac-light: #7c43bd;
+ --ac-dark: #12005e;
+}
+
+body {
+ background-color: var(--bg-dark);
+}
+
+h2 {
+ font-weight: 700;
+ margin: 1em;
+}
+
+input[type="button"] {
+ padding: 0.5em;
+ margin: 0.25em;
+ background-color: var(--bg-light);
+ border: 0px solid transparent;
+ border-radius: 3px;
+}
+input[type="button"]:hover {
+ background-color: var(--bg-lighter);
+}
+input[type="button"].enabled {
+ background-color: var(--bg-enabled);
+}
+input[type="text"] {
+ background-color: var(--bg-dark);
+ border: 1px solid var(--ac-light);
+}
+
+.local-controls {
+ background-color: var(--bg);
+ padding: 0.5em;
+ position: absolute;
+ bottom: 0.5em;
+ border: 0px solid transparent;
+ border-radius: 5px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 100;
+}
+
+.room {
+ width: 100vw;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+}
+
+.user {
+ background-color: var(--bg);
+ border: 0px soly transparent;
+ border-radius: 5px;
+ padding: 1em;
+ vertical-align: baseline;
+ height: 15em;
+ min-width: 10em;
+ margin: 0.5em;
+}
+
+.user .info .name {
+ font-weight: 400;
+}
+.user.local .info .name {
+ text-decoration: underline;
+}
+
+.info .status {
+ background-color: var(--bg-disabled);
+ padding: 0.25em;
+ margin: 0.1em;
+ border: 0px solid transparent;
+ border-radius: 10px;
+}
+.info .status.enabled {
+ background-color: var(--bg-enabled);
+}
+
+.media {
+ height: 100%;
+ width: auto;
+ border: 0px solid transparent;
+ border-radius: 5px;
+}
+
+.media.maximized {
+ position: absolute;
+ top: 50vh;
+ left: 50vw;
+ width: 100vw;
+ height: 100vh;
+ z-index: 1000;
+ transform: translate(-50%, -50%);
+}
+
+.start-box {
+ position: absolute;
+ top: 50vh;
+ left: 50vw;
+ transform: translate(-50%, -50%);
+}
+.start-box p {
+ margin-bottom: 0.5em;
+}
+.start-box input[type="text"] {
+ margin: 0.5em;
+ font-size: 32px;
+}
diff --git a/public/favicon.ico b/public/favicon.ico
deleted file mode 100644
index 8426ab0..0000000
--- a/public/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/public/index.html b/public/index.html
index 0d12704..5d2112b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -7,7 +7,7 @@
<script src="/scripts/bundle.js"></script>
<link rel="stylesheet" href="/static/css/master.css" />
- <title>webrtc meeting</title>
+ <title>keks webrtc meeting</title>
<style>
* {
margin: 0px;
diff --git a/public/mkassets.sh b/public/mkassets.sh
deleted file mode 100755
index 2e89d3b..0000000
--- a/public/mkassets.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-pushd .
-cd $(dirname $0)
-convert -size 256x256 -define gradient:radii=64,64 radial-gradient:white-black assets/light.png
-convert -size 256x256 xc:white -fill black -stroke black -draw "rectangle 64,64 192,192" -rotate 45 -blur 40x40 assets/void.png
-
-popd \ No newline at end of file
diff --git a/source/client/helper.ts b/source/client/helper.ts
new file mode 100644
index 0000000..19c4f46
--- /dev/null
+++ b/source/client/helper.ts
@@ -0,0 +1,14 @@
+export function get_query_params(): { [key: string]: string } {
+ const q: { [key: string]: string } = {}
+ for (const kv of window.location.search.substr(1).split("&")) {
+ const [key, value] = kv.split("=")
+ q[decodeURIComponent(key)] = decodeURIComponent(value)
+ }
+ return q
+}
+
+export function hex_id(len: number = 8): string {
+ if (len > 8) return hex_id() + hex_id(len - 8)
+ return Math.floor(Math.random() * 16 ** len).toString(16).padStart(len, "0")
+}
+
diff --git a/source/client/index.ts b/source/client/index.ts
index ce3533f..313cd86 100644
--- a/source/client/index.ts
+++ b/source/client/index.ts
@@ -1,3 +1,4 @@
+import { get_query_params } from "./helper"
import { log } from "./logger"
import { Room } from "./room"
@@ -11,17 +12,46 @@ export interface User {
stream: MediaStream,
}
-export const users: Map<string, User> = new Map()
+export var parameters = get_query_params()
window.onload = () => main()
-export async function main() {
+export async function main() {
if (window.location.pathname.startsWith("/room/")) {
const room_name = window.location.pathname.substr("/room/".length)
let room = new Room(room_name)
document.body.append(room.el)
} else {
- //TODO show ui for joining rooms
+ document.body.append(create_start_screen())
}
}
+
+function create_start_screen() {
+ const el = document.createElement("div")
+ const header = document.createElement("h2")
+ header.textContent = "keks meet"
+ const para = document.createElement("p")
+ para.textContent = "Hier kann man dann irgendwann mal sinnvollen text hinschreiben..."
+
+ // const room_input_label = document.createElement("label")
+ // room_input_label.textContent = "Room ID: "
+ // room_input_label.htmlFor = "room-id-input"
+
+ const room_input = document.createElement("input")
+ room_input.type = "text"
+ room_input.id = "room-id-input"
+ room_input.placeholder = "room id "
+
+ const submit = document.createElement("input")
+ submit.type = "button"
+ submit.addEventListener("click", () => {
+ if (room_input.value.length == 0) room_input.value = Math.floor(Math.random() * 10000).toString(16).padStart(5, "0")
+ window.location.pathname = `/room/${encodeURIComponent(room_input.value)}`
+ })
+ submit.value = "Join room"
+
+ el.classList.add("start-box")
+ el.append(header, para, room_input, document.createElement("br"), submit)
+ return el
+}
diff --git a/source/client/local_user.ts b/source/client/local_user.ts
index 70a8618..3fe6216 100644
--- a/source/client/local_user.ts
+++ b/source/client/local_user.ts
@@ -1,3 +1,4 @@
+import { log } from "./logger";
import { RemoteUser } from "./remote_user";
import { Room } from "./room";
import { User } from "./user";
@@ -8,23 +9,37 @@ export class LocalUser extends User {
private audio_track?: MediaStreamTrack
private video_track?: MediaStreamTrack
+ controls: { audio?: HTMLElement, video?: HTMLElement } = {}
+
constructor(room: Room, name: string) {
super(room, name)
+ this.el.classList.add("local")
this.create_controls()
- //@ts-ignore
- window.ea = () => this.enable_audio()
- //@ts-ignore
- window.da = () => this.disable_audio()
- //@ts-ignore
- window.ev = () => this.enable_video()
- //@ts-ignore
- window.dv = () => this.disable_video()
}
create_controls() {
- setTimeout(() => {
- this.enable_video()
- }, 3000)
+ const audio_toggle = document.createElement("input")
+ const video_toggle = document.createElement("input")
+ audio_toggle.type = video_toggle.type = "button"
+ audio_toggle.value = "Audio"
+ video_toggle.value = "Video"
+ let audio = false, video = false
+
+ audio_toggle.addEventListener("click", () => {
+ audio = !audio
+ if (audio) this.enable_audio()
+ else this.disable_audio()
+ })
+ video_toggle.addEventListener("click", () => {
+ video = !video
+ if (video) this.enable_video()
+ else this.disable_video()
+ })
+
+ const el = document.createElement("div")
+ el.classList.add("local-controls")
+ el.append(audio_toggle, video_toggle)
+ document.body.append(el)
}
async add_initial_to_remote(ru: RemoteUser) {
@@ -34,25 +49,31 @@ export class LocalUser extends User {
async enable_video() {
if (this.video_track) return
+ log("media", "requesting user media (video)")
const user_media = await window.navigator.mediaDevices.getUserMedia({ video: true })
- console.log(user_media.getVideoTracks());
const t = this.video_track = user_media.getVideoTracks()[0]
this.room.remote_users.forEach(u => u.peer.addTrack(t))
+ this.stream.addTrack(t)
+ this.update_view()
}
async enable_audio() {
if (this.audio_track) return
+ log("media", "requesting user media (audio)")
const user_media = await window.navigator.mediaDevices.getUserMedia({ audio: true })
const t = this.audio_track = user_media.getAudioTracks()[0]
this.room.remote_users.forEach(u => u.peer.addTrack(t))
+ this.stream.addTrack(t)
+ this.update_view()
}
async disable_video() {
if (!this.video_track) return
this.room.remote_users.forEach(u => {
u.peer.getSenders().forEach(s => {
- console.log(u, s, this.video_track);
if (s.track == this.video_track) u.peer.removeTrack(s)
})
})
+ this.stream.removeTrack(this.video_track)
+ this.update_view()
this.video_track = undefined
}
async disable_audio() {
@@ -62,9 +83,9 @@ export class LocalUser extends User {
if (s.track == this.audio_track) u.peer.removeTrack(s)
})
})
+ this.stream.removeTrack(this.audio_track)
+ this.update_view()
this.audio_track = undefined
}
-
-
} \ No newline at end of file
diff --git a/source/client/room.ts b/source/client/room.ts
index 9d315ba..fd48eff 100644
--- a/source/client/room.ts
+++ b/source/client/room.ts
@@ -3,6 +3,8 @@ import { CSPacket, SCPacket } from "./types";
import { RemoteUser } from "./remote_user";
import { User } from "./user";
import { LocalUser } from "./local_user";
+import { parameters } from ".";
+import { hex_id } from "./helper";
export class Room {
@@ -16,14 +18,14 @@ export class Room {
constructor(name: string) {
this.name = name
this.el = document.createElement("div")
-
+ this.el.classList.add("room")
this.websocket = new WebSocket(`ws://${window.location.host}/room/${encodeURIComponent(name)}`)
this.websocket.onclose = () => this.websocket_close()
this.websocket.onopen = () => this.websocket_open()
this.websocket.onmessage = (ev) => {
this.websocket_message(JSON.parse(ev.data))
}
- this.local_user = new LocalUser(this, Math.random().toString())
+ this.local_user = new LocalUser(this, parameters.username ?? `guest-${hex_id()}`)
}
websocket_send(data: CSPacket) {
diff --git a/source/client/user.ts b/source/client/user.ts
index 7d6991a..579886f 100644
--- a/source/client/user.ts
+++ b/source/client/user.ts
@@ -7,7 +7,9 @@ export abstract class User {
room: Room
el: HTMLElement
- view_el?: HTMLElement
+ media_el?: HTMLElement
+
+ display?: { audio_status_el: HTMLElement, video_status_el: HTMLElement }
local: boolean = false
@@ -17,7 +19,9 @@ export abstract class User {
this.name = name
this.room = room
this.el = document.createElement("div")
+ this.el.classList.add("user")
this.room.el.append(this.el)
+ this.setup_view()
this.update_view()
}
@@ -41,19 +45,74 @@ export abstract class User {
}
}
+ setup_view() {
+ const info_el = document.createElement("div")
+ info_el.classList.add("info")
+ const name_el = document.createElement("span")
+ name_el.textContent = this.name
+ name_el.classList.add("name")
+ const audio_status_el = document.createElement("span")
+ const video_status_el = document.createElement("span")
+ video_status_el.classList.add("status", "video-status")
+ audio_status_el.classList.add("status", "audio-status")
+ audio_status_el.textContent = "A"
+ video_status_el.textContent = "V"
+ info_el.append(audio_status_el, video_status_el, name_el)
+ this.display = { video_status_el, audio_status_el }
+ this.el.append(info_el)
+ }
+
update_view() {
- if (this.view_el) this.el.removeChild(this.view_el)
- this.view_el = this.create_view()
- this.el.appendChild(this.view_el)
+ if (this.stream.getAudioTracks().length > 0)
+ this.display?.audio_status_el.classList.add("enabled")
+ else this.display?.audio_status_el.classList.remove("enabled")
+
+ if (this.stream.getVideoTracks().length > 0)
+ this.display?.video_status_el.classList.add("enabled")
+ else this.display?.video_status_el.classList.remove("enabled")
+
+ if (this.media_el) this.el.removeChild(this.media_el)
+ this.media_el = this.create_media_view()
+ this.el.appendChild(this.media_el)
}
- create_view() {
- const el = document.createElement("video")
- el.autoplay = true
- el.toggleAttribute("playsinline")
- el.srcObject = this.stream
- console.log(el);
+ create_media_view() {
+ const has_video = this.stream.getVideoTracks().length > 0
+ const has_audio = this.stream.getAudioTracks().length > 0
+ const media_el = has_video ? document.createElement("video") : document.createElement("audio")
+ media_el.classList.add("media")
+ media_el.autoplay = true
+ if (has_video) media_el.toggleAttribute("playsinline")
+ media_el.srcObject = this.stream
+ if (has_video) media_el.addEventListener("click", () => {
+ media_el.classList.remove("maximized")
+ })
+
+ const controls_el = document.createElement("div")
+ controls_el.classList.add("media-controls")
+ if (has_video) {
+ const pip_el = document.createElement("input")
+ pip_el.type = "button"
+ pip_el.addEventListener("click", () => {
+ //@ts-ignore
+ media_el.requestPictureInPicture()
+ })
+ pip_el.value = "Picture-in-Picture"
+ const max_el = document.createElement("input")
+ max_el.type = "button"
+ max_el.addEventListener("click", () => {
+ media_el.classList.add("maximized")
+ })
+ max_el.value = "Maximize"
+ controls_el.append(max_el, pip_el)
+ }
+ if (has_audio) {
+ // TODO volume controls
+ }
+ const el = document.createElement("div")
+ el.classList.add("media-container")
+ el.append(media_el, controls_el)
return el
}
} \ No newline at end of file
diff --git a/source/server/index.ts b/source/server/index.ts
index ef70492..470e289 100644
--- a/source/server/index.ts
+++ b/source/server/index.ts
@@ -51,6 +51,7 @@ async function main() {
let user_name = ""
const init = (n: string) => {
+ if (room.get(n)) return ws.close(1, "username already taken")
initialized = true
user_name = n
rooms.set(req.params.id, room)