aboutsummaryrefslogtreecommitdiff
path: root/source
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 /source
parent2387d8910d80b86a95e8c3242bdb6809dddda1aa (diff)
downloadkeks-meet-a8f89036b5788a3f6ddb053824650b913a0c98a3.tar
keks-meet-a8f89036b5788a3f6ddb053824650b913a0c98a3.tar.bz2
keks-meet-a8f89036b5788a3f6ddb053824650b913a0c98a3.tar.zst
idk
Diffstat (limited to 'source')
-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
6 files changed, 157 insertions, 30 deletions
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)