diff options
author | metamuffin <metamuffin@disroot.org> | 2022-10-03 11:28:16 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-10-03 11:28:16 +0200 |
commit | 4e99a3325318c902cd78ea9f760f46d79acde5c0 (patch) | |
tree | cc2bc54f4a0eb27db2b5d38dfbb785c1e9b84bd6 /client-web/source/user/remote.ts | |
parent | fa44b02da29a0bd1b60026d4f6ffd6c9748a09da (diff) | |
download | keks-meet-4e99a3325318c902cd78ea9f760f46d79acde5c0.tar keks-meet-4e99a3325318c902cd78ea9f760f46d79acde5c0.tar.bz2 keks-meet-4e99a3325318c902cd78ea9f760f46d79acde5c0.tar.zst |
riesencommit (part 1)
Diffstat (limited to 'client-web/source/user/remote.ts')
-rw-r--r-- | client-web/source/user/remote.ts | 133 |
1 files changed, 68 insertions, 65 deletions
diff --git a/client-web/source/user/remote.ts b/client-web/source/user/remote.ts index fbab9c4..677d362 100644 --- a/client-web/source/user/remote.ts +++ b/client-web/source/user/remote.ts @@ -6,72 +6,72 @@ /// <reference lib="dom" /> import { RelayMessage } from "../../../common/packets.d.ts"; -import { Resource } from "../resource/mod.ts"; import { notify } from "../helper.ts"; import { ROOM_CONTAINER, RTC_CONFIG } from "../index.ts" import { log } from "../logger.ts" import { PREFS } from "../preferences/mod.ts"; +import { new_remote_resource, RemoteResource } from "../resource/mod.ts"; import { Room } from "../room.ts" import { TrackHandle } from "../track_handle.ts"; import { User } from "./mod.ts"; -import { TrackResource } from "../resource/track.ts"; export class RemoteUser extends User { - peer: RTCPeerConnection + pc: RTCPeerConnection senders: Map<string, RTCRtpSender> = new Map() data_channels: Map<string, RTCDataChannel> = new Map() + resources: Map<string, RemoteResource> = new Map() negotiation_busy = false constructor(room: Room, id: number) { super(room, id) - room.remote_users.set(this.id, this) + room.remote_users.set(id, this) log("usermodel", `added remote user: ${this.display_name}`) - this.peer = new RTCPeerConnection(RTC_CONFIG) - this.peer.onicecandidate = ev => { + this.pc = new RTCPeerConnection(RTC_CONFIG) + this.pc.onicecandidate = ev => { if (!ev.candidate) return room.signaling.send_relay({ ice_candidate: ev.candidate.toJSON() }, this.id) log("webrtc", `ICE candidate set`, ev.candidate) this.update_stats() } - this.peer.ontrack = ev => { + this.pc.ontrack = ev => { console.log(ev) const t = ev.track const id = ev.streams[0]?.id if (!id) { ev.transceiver.stop(); return log({ scope: "media", warn: true }, "got a track without stream") } const r = this.resources.get(id) if (!r) { ev.transceiver.stop(); return log({ scope: "media", warn: true }, "got an unassociated track") } - if (r instanceof TrackResource) r.track = new TrackHandle(t); - else { ev.transceiver.stop(); return log({ scope: "media", warn: true }, "got a track for a resource that should use data channel") } + r.on_enable(new TrackHandle(t), () => { + this.request_resource_stop(r) + }) + // else { ev.transceiver.stop(); return log({ scope: "media", warn: true }, "got a track for a resource that should use data channel") } log("media", `remote track: ${this.display_name}`, t) this.update_stats() } - this.peer.onnegotiationneeded = () => { + this.pc.onnegotiationneeded = () => { log("webrtc", `negotiation needed: ${this.display_name}`) - if (this.negotiation_busy && this.peer.signalingState == "stable") return + if (this.negotiation_busy && this.pc.signalingState == "stable") return this.offer() this.update_stats() } - this.peer.onicecandidateerror = () => { + this.pc.onicecandidateerror = () => { log({ scope: "webrtc", warn: true }, "ICE error") this.update_stats() } - this.peer.oniceconnectionstatechange = () => { this.update_stats() } - this.peer.onicegatheringstatechange = () => { this.update_stats() } - this.peer.onsignalingstatechange = () => { this.update_stats() } - this.peer.onconnectionstatechange = () => { this.update_stats() } + this.pc.oniceconnectionstatechange = () => { this.update_stats() } + this.pc.onicegatheringstatechange = () => { this.update_stats() } + this.pc.onsignalingstatechange = () => { this.update_stats() } + this.pc.onconnectionstatechange = () => { this.update_stats() } this.update_stats() } leave() { log("usermodel", `remove remote user: ${this.display_name}`) - this.peer.close() + this.pc.close() this.room.remote_users.delete(this.id) - super.leave() ROOM_CONTAINER.removeChild(this.el) if (PREFS.notify_leave) notify(`${this.display_name} left`) } - on_relay(message: RelayMessage) { if (message.chat) this.room.chat.add_message(this, message.chat) if (message.ice_candidate) this.add_ice_candidate(message.ice_candidate) @@ -83,12 +83,10 @@ export class RemoteUser extends User { } if (message.provide) { console.log(message.provide.id); - const d = Resource.create(this, message.provide) + const d = new_remote_resource(this, message.provide) if (!d) return - if (d instanceof TrackResource) { - if (d.info.kind == "video" && PREFS.optional_video_default_enable) d.request() - if (d.info.kind == "audio" && PREFS.optional_audio_default_enable) d.request() - } + if (d.info.kind == "track" && d.info.track_kind == "audio" && PREFS.optional_audio_default_enable) this.request_resource(d) + if (d.info.kind == "track" && d.info.track_kind == "video" && PREFS.optional_video_default_enable) this.request_resource(d) this.el.append(d.el) this.resources.set(message.provide.id, d) } @@ -99,53 +97,36 @@ export class RemoteUser extends User { if (message.request) { const r = this.room.local_user.resources.get(message.request.id) if (!r) return log({ scope: "*", warn: true }, "somebody requested an unknown resource") - if (r instanceof TrackResource) { - if (!r.track) throw new Error("local resources not avail"); - const sender = this.peer.addTrack(r.track.track, r.track.stream) - this.senders.set(r.track.id, sender) - r.track.addEventListener("end", () => { this.senders.delete(r.track?.id ?? "") }) - } + const channel = r.on_request(this, label => this.pc.createDataChannel(label)) + if (channel instanceof TrackHandle) { + const sender = this.pc.addTrack(channel.track, channel.stream) + this.senders.set(channel.id, sender) + channel.addEventListener("end", () => { this.senders.delete(r.info.id) }) + } else if (channel instanceof RTCDataChannel) { + this.data_channels.set(r.info.id, channel) + channel.addEventListener("close", () => this.data_channels.delete(r.info.id)) + } else throw new Error("unreachable"); } if (message.request_stop) { const sender = this.senders.get(message.request_stop.id) if (!sender) return log({ scope: "*", warn: true }, "somebody requested us to stop transmitting an unknown resource") - this.peer.removeTrack(sender) + this.pc.removeTrack(sender) } } send_to(message: RelayMessage) { this.room.signaling.send_relay(message, this.id) } + request_resource(r: RemoteResource) { this.send_to({ request: { id: r.info.id } }) } + request_resource_stop(r: RemoteResource) { this.send_to({ request_stop: { id: r.info.id } }) } - async update_stats() { - if (!PREFS.webrtc_debug) return - try { - const stats = await this.peer.getStats() - let stuff = ""; - stuff += `ice-conn=${this.peer.iceConnectionState}; ice-gathering=${this.peer.iceGatheringState}; ice-trickle=${this.peer.canTrickleIceCandidates}; signaling=${this.peer.signalingState};\n` - stats.forEach(s => { - console.log("stat", s); - if (s.type == "candidate-pair" && s.selected) { - //@ts-ignore spec is weird.... - if (!stats.get) return console.warn("no RTCStatsReport.get"); - //@ts-ignore spec is weird.... - const cpstat = stats.get(s.localCandidateId) - if (!cpstat) return console.warn("no stats"); - console.log("cp", cpstat); - stuff += `via ${cpstat.candidateType}:${cpstat.protocol}:${cpstat.address}\n` - } else if (s.type == "codec") { - stuff += `using ${s.codecType ?? "dec/enc"}:${s.mimeType}(${s.sdpFmtpLine})\n` - } - }) - this.stats_el.textContent = stuff - } catch (e) { - console.warn(e); - } + add_ice_candidate(candidate: RTCIceCandidateInit) { + this.pc.addIceCandidate(new RTCIceCandidate(candidate)) + this.update_stats() } - async offer() { this.negotiation_busy = true - const offer_description = await this.peer.createOffer() - await this.peer.setLocalDescription(offer_description) + const offer_description = await this.pc.createOffer() + await this.pc.setLocalDescription(offer_description) log("webrtc", `sent offer: ${this.display_name}`, { offer: offer_description.sdp }) this.send_to({ offer: offer_description.sdp }) } @@ -153,12 +134,12 @@ export class RemoteUser extends User { this.negotiation_busy = true log("webrtc", `got offer: ${this.display_name}`, { offer }) const offer_description = new RTCSessionDescription({ sdp: offer, type: "offer" }) - await this.peer.setRemoteDescription(offer_description) + await this.pc.setRemoteDescription(offer_description) this.answer() } async answer() { - const answer_description = await this.peer.createAnswer() - await this.peer.setLocalDescription(answer_description) + const answer_description = await this.pc.createAnswer() + await this.pc.setLocalDescription(answer_description) log("webrtc", `sent answer: ${this.display_name}`, { answer: answer_description.sdp }) this.send_to({ answer: answer_description.sdp }) this.negotiation_busy = false @@ -166,12 +147,34 @@ export class RemoteUser extends User { async on_answer(answer: string) { log("webrtc", `got answer: ${this.display_name}`, { answer }) const answer_description = new RTCSessionDescription({ sdp: answer, type: "answer" }) - await this.peer.setRemoteDescription(answer_description) + await this.pc.setRemoteDescription(answer_description) this.negotiation_busy = false } - add_ice_candidate(candidate: RTCIceCandidateInit) { - this.peer.addIceCandidate(new RTCIceCandidate(candidate)) - this.update_stats() + async update_stats() { + if (!PREFS.webrtc_debug) return + try { + const stats = await this.pc.getStats() + let stuff = ""; + stuff += `ice-conn=${this.pc.iceConnectionState}; ice-gathering=${this.pc.iceGatheringState}; ice-trickle=${this.pc.canTrickleIceCandidates}; signaling=${this.pc.signalingState};\n` + stats.forEach(s => { + console.log("stat", s); + if (s.type == "candidate-pair" && s.selected) { + //@ts-ignore trust me, this works + if (!stats.get) return console.warn("no RTCStatsReport.get"); + //@ts-ignore trust me, this works + const cpstat = stats.get(s.localCandidateId) + if (!cpstat) return console.warn("no stats"); + console.log("cp", cpstat); + stuff += `via ${cpstat.candidateType}:${cpstat.protocol}:${cpstat.address}\n` + } else if (s.type == "codec") { + stuff += `using ${s.codecType ?? "dec/enc"}:${s.mimeType}(${s.sdpFmtpLine})\n` + } + }) + this.stats_el.textContent = stuff + } catch (e) { + console.warn(e); + } } + }
\ No newline at end of file |