diff options
Diffstat (limited to 'src/webrtc')
-rw-r--r-- | src/webrtc/Server.ts | 12 | ||||
-rw-r--r-- | src/webrtc/events/Close.ts | 2 | ||||
-rw-r--r-- | src/webrtc/events/Connection.ts | 17 | ||||
-rw-r--r-- | src/webrtc/events/Message.ts | 13 | ||||
-rw-r--r-- | src/webrtc/index.ts | 2 | ||||
-rw-r--r-- | src/webrtc/opcodes/BackendVersion.ts | 7 | ||||
-rw-r--r-- | src/webrtc/opcodes/Heartbeat.ts | 10 | ||||
-rw-r--r-- | src/webrtc/opcodes/Identify.ts | 35 | ||||
-rw-r--r-- | src/webrtc/opcodes/SelectProtocol.ts | 27 | ||||
-rw-r--r-- | src/webrtc/opcodes/Speaking.ts | 6 | ||||
-rw-r--r-- | src/webrtc/opcodes/Video.ts | 39 | ||||
-rw-r--r-- | src/webrtc/opcodes/index.ts | 4 | ||||
-rw-r--r-- | src/webrtc/opcodes/sdp.json | 2 | ||||
-rw-r--r-- | src/webrtc/start.ts | 4 | ||||
-rw-r--r-- | src/webrtc/util/Constants.ts | 6 | ||||
-rw-r--r-- | src/webrtc/util/MediaServer.ts | 14 | ||||
-rw-r--r-- | src/webrtc/util/index.ts | 2 |
17 files changed, 134 insertions, 68 deletions
diff --git a/src/webrtc/Server.ts b/src/webrtc/Server.ts index 32b795ea..d9a892a3 100644 --- a/src/webrtc/Server.ts +++ b/src/webrtc/Server.ts @@ -11,7 +11,15 @@ export class Server { public server: http.Server; public production: boolean; - constructor({ port, server, production }: { port: number; server?: http.Server; production?: boolean }) { + constructor({ + port, + server, + production, + }: { + port: number; + server?: http.Server; + production?: boolean; + }) { this.port = port; this.production = production || false; @@ -53,4 +61,4 @@ export class Server { closeDatabase(); this.server.close(); } -} \ No newline at end of file +} diff --git a/src/webrtc/events/Close.ts b/src/webrtc/events/Close.ts index 1c203653..4cf80bb2 100644 --- a/src/webrtc/events/Close.ts +++ b/src/webrtc/events/Close.ts @@ -6,4 +6,4 @@ export async function onClose(this: WebSocket, code: number, reason: string) { if (this.session_id) await Session.delete({ session_id: this.session_id }); this.removeAllListeners(); -} \ No newline at end of file +} diff --git a/src/webrtc/events/Connection.ts b/src/webrtc/events/Connection.ts index bf228d64..9300b6b2 100644 --- a/src/webrtc/events/Connection.ts +++ b/src/webrtc/events/Connection.ts @@ -14,7 +14,11 @@ try { // TODO: specify rate limit in config // TODO: check msg max size -export async function Connection(this: WS.Server, socket: WebSocket, request: IncomingMessage) { +export async function Connection( + this: WS.Server, + socket: WebSocket, + request: IncomingMessage, +) { try { socket.on("close", onClose.bind(socket)); socket.on("message", onMessage.bind(socket)); @@ -29,7 +33,7 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In "open", "ping", "pong", - "unexpected-response" + "unexpected-response", ].forEach((x) => { socket.on(x, (y) => console.log("[WebRTC]", x, y)); }); @@ -39,7 +43,8 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In socket.encoding = "json"; socket.version = Number(searchParams.get("v")) || 5; - if (socket.version < 3) return socket.close(CLOSECODES.Unknown_error, "invalid version"); + if (socket.version < 3) + return socket.close(CLOSECODES.Unknown_error, "invalid version"); setHeartbeat(socket); @@ -50,11 +55,11 @@ export async function Connection(this: WS.Server, socket: WebSocket, request: In await Send(socket, { op: VoiceOPCodes.HELLO, d: { - heartbeat_interval: 1000 * 30 - } + heartbeat_interval: 1000 * 30, + }, }); } catch (error) { console.error("[WebRTC]", error); return socket.close(CLOSECODES.Unknown_error); } -} \ No newline at end of file +} diff --git a/src/webrtc/events/Message.ts b/src/webrtc/events/Message.ts index 8f75a815..38676f6c 100644 --- a/src/webrtc/events/Message.ts +++ b/src/webrtc/events/Message.ts @@ -7,13 +7,14 @@ const PayloadSchema = { op: Number, $d: new Tuple(Object, Number), // or number for heartbeat sequence $s: Number, - $t: String + $t: String, }; export async function onMessage(this: WebSocket, buffer: Buffer) { try { var data: Payload = JSON.parse(buffer.toString()); - if (data.op !== VoiceOPCodes.IDENTIFY && !this.user_id) return this.close(CLOSECODES.Not_authenticated); + if (data.op !== VoiceOPCodes.IDENTIFY && !this.user_id) + return this.close(CLOSECODES.Not_authenticated); // @ts-ignore const OPCodeHandler = OPCodeHandlers[data.op]; @@ -25,7 +26,11 @@ export async function onMessage(this: WebSocket, buffer: Buffer) { return; } - if (![VoiceOPCodes.HEARTBEAT, VoiceOPCodes.SPEAKING].includes(data.op as VoiceOPCodes)) { + if ( + ![VoiceOPCodes.HEARTBEAT, VoiceOPCodes.SPEAKING].includes( + data.op as VoiceOPCodes, + ) + ) { // @ts-ignore console.log("[WebRTC] Opcode " + VoiceOPCodes[data.op]); } @@ -35,4 +40,4 @@ export async function onMessage(this: WebSocket, buffer: Buffer) { console.error("[WebRTC] error", error); // if (!this.CLOSED && this.CLOSING) return this.close(CloseCodes.Unknown_error); } -} \ No newline at end of file +} diff --git a/src/webrtc/index.ts b/src/webrtc/index.ts index 7cecc9b6..ccb088ac 100644 --- a/src/webrtc/index.ts +++ b/src/webrtc/index.ts @@ -1,2 +1,2 @@ export * from "./Server"; -export * from "./util/index"; \ No newline at end of file +export * from "./util/index"; diff --git a/src/webrtc/opcodes/BackendVersion.ts b/src/webrtc/opcodes/BackendVersion.ts index b4b61c7d..375dd0cc 100644 --- a/src/webrtc/opcodes/BackendVersion.ts +++ b/src/webrtc/opcodes/BackendVersion.ts @@ -2,5 +2,8 @@ import { Payload, Send, WebSocket } from "@fosscord/gateway"; import { VoiceOPCodes } from "../util"; export async function onBackendVersion(this: WebSocket, data: Payload) { - await Send(this, { op: VoiceOPCodes.VOICE_BACKEND_VERSION, d: { voice: "0.8.43", rtc_worker: "0.3.26" } }); -} \ No newline at end of file + await Send(this, { + op: VoiceOPCodes.VOICE_BACKEND_VERSION, + d: { voice: "0.8.43", rtc_worker: "0.3.26" }, + }); +} diff --git a/src/webrtc/opcodes/Heartbeat.ts b/src/webrtc/opcodes/Heartbeat.ts index 1b6c5bcd..932cd458 100644 --- a/src/webrtc/opcodes/Heartbeat.ts +++ b/src/webrtc/opcodes/Heartbeat.ts @@ -1,4 +1,10 @@ -import { CLOSECODES, Payload, Send, setHeartbeat, WebSocket } from "@fosscord/gateway"; +import { + CLOSECODES, + Payload, + Send, + setHeartbeat, + WebSocket, +} from "@fosscord/gateway"; import { VoiceOPCodes } from "../util"; export async function onHeartbeat(this: WebSocket, data: Payload) { @@ -6,4 +12,4 @@ export async function onHeartbeat(this: WebSocket, data: Payload) { if (isNaN(data.d)) return this.close(CLOSECODES.Decode_error); await Send(this, { op: VoiceOPCodes.HEARTBEAT_ACK, d: data.d }); -} \ No newline at end of file +} diff --git a/src/webrtc/opcodes/Identify.ts b/src/webrtc/opcodes/Identify.ts index 19a575ab..45ad6c0a 100644 --- a/src/webrtc/opcodes/Identify.ts +++ b/src/webrtc/opcodes/Identify.ts @@ -1,33 +1,46 @@ import { CLOSECODES, Payload, Send, WebSocket } from "@fosscord/gateway"; -import { validateSchema, VoiceIdentifySchema, VoiceState } from "@fosscord/util"; +import { + validateSchema, + VoiceIdentifySchema, + VoiceState, +} from "@fosscord/util"; import { endpoint, getClients, VoiceOPCodes, PublicIP } from "@fosscord/webrtc"; import SemanticSDP from "semantic-sdp"; const defaultSDP = require("./sdp.json"); export async function onIdentify(this: WebSocket, data: Payload) { clearTimeout(this.readyTimeout); - const { server_id, user_id, session_id, token, streams, video } = validateSchema("VoiceIdentifySchema", data.d) as VoiceIdentifySchema; + const { server_id, user_id, session_id, token, streams, video } = + validateSchema("VoiceIdentifySchema", data.d) as VoiceIdentifySchema; - const voiceState = await VoiceState.findOne({ where: { guild_id: server_id, user_id, token, session_id } }); + const voiceState = await VoiceState.findOne({ + where: { guild_id: server_id, user_id, token, session_id }, + }); if (!voiceState) return this.close(CLOSECODES.Authentication_failed); this.user_id = user_id; this.session_id = session_id; const sdp = SemanticSDP.SDPInfo.expand(defaultSDP); - sdp.setDTLS(SemanticSDP.DTLSInfo.expand({ setup: "actpass", hash: "sha-256", fingerprint: endpoint.getDTLSFingerprint() })); + sdp.setDTLS( + SemanticSDP.DTLSInfo.expand({ + setup: "actpass", + hash: "sha-256", + fingerprint: endpoint.getDTLSFingerprint(), + }), + ); this.client = { websocket: this, out: { - tracks: new Map() + tracks: new Map(), }, in: { audio_ssrc: 0, video_ssrc: 0, - rtx_ssrc: 0 + rtx_ssrc: 0, }, sdp, - channel_id: voiceState.channel_id + channel_id: voiceState.channel_id, }; const clients = getClients(voiceState.channel_id)!; @@ -51,10 +64,10 @@ export async function onIdentify(this: WebSocket, data: Payload) { "xsalsa20_poly1305_lite_rtpsize", "xsalsa20_poly1305_lite", "xsalsa20_poly1305_suffix", - "xsalsa20_poly1305" + "xsalsa20_poly1305", ], ip: PublicIP, - experiments: [] - } + experiments: [], + }, }); -} \ No newline at end of file +} diff --git a/src/webrtc/opcodes/SelectProtocol.ts b/src/webrtc/opcodes/SelectProtocol.ts index a3579b34..eadba283 100644 --- a/src/webrtc/opcodes/SelectProtocol.ts +++ b/src/webrtc/opcodes/SelectProtocol.ts @@ -6,7 +6,10 @@ import SemanticSDP, { MediaInfo, SDPInfo } from "semantic-sdp"; export async function onSelectProtocol(this: WebSocket, payload: Payload) { if (!this.client) return; - const data = validateSchema("SelectProtocolSchema", payload.d) as SelectProtocolSchema; + const data = validateSchema( + "SelectProtocolSchema", + payload.d, + ) as SelectProtocolSchema; const offer = SemanticSDP.SDPInfo.parse("m=audio\n" + data.sdp!); this.client.sdp!.setICE(offer.getICE()); @@ -25,14 +28,14 @@ export async function onSelectProtocol(this: WebSocket, payload: Payload) { const candidate = candidates[0]; const answer = - `m=audio ${port} ICE/SDP` - + `a=fingerprint:${fingerprint}` - + `c=IN IP4 ${PublicIP}` - + `a=rtcp:${port}` - + `a=ice-ufrag:${ice.getUfrag()}` - + `a=ice-pwd:${ice.getPwd()}` - + `a=fingerprint:${fingerprint}` - + `a=candidate:1 1 ${candidate.getTransport()} ${candidate.getFoundation()} ${candidate.getAddress()} ${candidate.getPort()} typ host`; + `m=audio ${port} ICE/SDP` + + `a=fingerprint:${fingerprint}` + + `c=IN IP4 ${PublicIP}` + + `a=rtcp:${port}` + + `a=ice-ufrag:${ice.getUfrag()}` + + `a=ice-pwd:${ice.getPwd()}` + + `a=fingerprint:${fingerprint}` + + `a=candidate:1 1 ${candidate.getTransport()} ${candidate.getFoundation()} ${candidate.getAddress()} ${candidate.getPort()} typ host`; await Send(this, { op: VoiceOPCodes.SELECT_PROTOCOL_ACK, @@ -40,7 +43,7 @@ export async function onSelectProtocol(this: WebSocket, payload: Payload) { video_codec: "H264", sdp: answer, media_session_id: this.session_id, - audio_codec: "opus" - } + audio_codec: "opus", + }, }); -} \ No newline at end of file +} diff --git a/src/webrtc/opcodes/Speaking.ts b/src/webrtc/opcodes/Speaking.ts index e2227040..8488acf8 100644 --- a/src/webrtc/opcodes/Speaking.ts +++ b/src/webrtc/opcodes/Speaking.ts @@ -15,8 +15,8 @@ export async function onSpeaking(this: WebSocket, data: Payload) { d: { user_id: client.websocket.user_id, speaking: data.d.speaking, - ssrc: ssrc?.audio_ssrc || 0 - } + ssrc: ssrc?.audio_ssrc || 0, + }, }); }); -} \ No newline at end of file +} diff --git a/src/webrtc/opcodes/Video.ts b/src/webrtc/opcodes/Video.ts index ff20d5a9..dcbc9aa0 100644 --- a/src/webrtc/opcodes/Video.ts +++ b/src/webrtc/opcodes/Video.ts @@ -21,8 +21,8 @@ export async function onVideo(this: WebSocket, payload: Payload) { SemanticSDP.StreamInfo.expand({ id, // @ts-ignore - tracks: [] - }) + tracks: [], + }), ); this.client.in.stream = stream; @@ -46,8 +46,8 @@ export async function onVideo(this: WebSocket, payload: Payload) { SemanticSDP.StreamInfo.expand({ id: "out" + this.user_id, // @ts-ignore - tracks: [] - }) + tracks: [], + }), ); this.client.out.stream = out; @@ -64,20 +64,35 @@ export async function onVideo(this: WebSocket, payload: Payload) { } if (d.audio_ssrc) { - handleSSRC.call(this, "audio", { media: d.audio_ssrc, rtx: d.audio_ssrc + 1 }); + handleSSRC.call(this, "audio", { + media: d.audio_ssrc, + rtx: d.audio_ssrc + 1, + }); } if (d.video_ssrc && d.rtx_ssrc) { - handleSSRC.call(this, "video", { media: d.video_ssrc, rtx: d.rtx_ssrc }); + handleSSRC.call(this, "video", { + media: d.video_ssrc, + rtx: d.rtx_ssrc, + }); } } -function attachTrack(this: WebSocket, track: IncomingStreamTrack, user_id: string) { +function attachTrack( + this: WebSocket, + track: IncomingStreamTrack, + user_id: string, +) { if (!this.client) return; - const outTrack = this.client.transport!.createOutgoingStreamTrack(track.getMedia()); + const outTrack = this.client.transport!.createOutgoingStreamTrack( + track.getMedia(), + ); outTrack.attachTo(track); this.client.out.stream!.addTrack(outTrack); var ssrcs = this.client.out.tracks.get(user_id)!; - if (!ssrcs) ssrcs = this.client.out.tracks.set(user_id, { audio_ssrc: 0, rtx_ssrc: 0, video_ssrc: 0 }).get(user_id)!; + if (!ssrcs) + ssrcs = this.client.out.tracks + .set(user_id, { audio_ssrc: 0, rtx_ssrc: 0, video_ssrc: 0 }) + .get(user_id)!; if (track.getMedia() === "audio") { ssrcs.audio_ssrc = outTrack.getSSRCs().media!; @@ -90,8 +105,8 @@ function attachTrack(this: WebSocket, track: IncomingStreamTrack, user_id: strin op: VoiceOPCodes.VIDEO, d: { user_id: user_id, - ...ssrcs - } as VoiceVideoSchema + ...ssrcs, + } as VoiceVideoSchema, }); } @@ -115,4 +130,4 @@ function handleSSRC(this: WebSocket, type: "audio" | "video", ssrcs: SSRCs) { attachTrack.call(this, track, client.websocket.user_id); }); } -} \ No newline at end of file +} diff --git a/src/webrtc/opcodes/index.ts b/src/webrtc/opcodes/index.ts index 8c664cce..86e39687 100644 --- a/src/webrtc/opcodes/index.ts +++ b/src/webrtc/opcodes/index.ts @@ -15,5 +15,5 @@ export default { [VoiceOPCodes.VOICE_BACKEND_VERSION]: onBackendVersion, [VoiceOPCodes.VIDEO]: onVideo, [VoiceOPCodes.SPEAKING]: onSpeaking, - [VoiceOPCodes.SELECT_PROTOCOL]: onSelectProtocol -}; \ No newline at end of file + [VoiceOPCodes.SELECT_PROTOCOL]: onSelectProtocol, +}; diff --git a/src/webrtc/opcodes/sdp.json b/src/webrtc/opcodes/sdp.json index 4867b9c7..5f7eba38 100644 --- a/src/webrtc/opcodes/sdp.json +++ b/src/webrtc/opcodes/sdp.json @@ -417,4 +417,4 @@ } ], "candidates": [] -} \ No newline at end of file +} diff --git a/src/webrtc/start.ts b/src/webrtc/start.ts index 9a5f38ee..57361909 100644 --- a/src/webrtc/start.ts +++ b/src/webrtc/start.ts @@ -8,6 +8,6 @@ config(); const port = Number(process.env.PORT) || 3004; const server = new Server({ - port + port, }); -server.start(); \ No newline at end of file +server.start(); diff --git a/src/webrtc/util/Constants.ts b/src/webrtc/util/Constants.ts index 64d78e22..d9f1ff60 100644 --- a/src/webrtc/util/Constants.ts +++ b/src/webrtc/util/Constants.ts @@ -3,7 +3,7 @@ export enum VoiceStatus { CONNECTING = 1, AUTHENTICATING = 2, RECONNECTING = 3, - DISCONNECTED = 4 + DISCONNECTED = 4, } export enum VoiceOPCodes { @@ -22,5 +22,5 @@ export enum VoiceOPCodes { SESSION_UPDATE = 14, MEDIA_SINK_WANTS = 15, VOICE_BACKEND_VERSION = 16, - CHANNEL_OPTIONS_UPDATE = 17 -} \ No newline at end of file + CHANNEL_OPTIONS_UPDATE = 17, +} diff --git a/src/webrtc/util/MediaServer.ts b/src/webrtc/util/MediaServer.ts index 93230c91..520b8682 100644 --- a/src/webrtc/util/MediaServer.ts +++ b/src/webrtc/util/MediaServer.ts @@ -1,5 +1,9 @@ import { WebSocket } from "@fosscord/gateway"; -import MediaServer, { IncomingStream, OutgoingStream, Transport } from "medooze-media-server"; +import MediaServer, { + IncomingStream, + OutgoingStream, + Transport, +} from "medooze-media-server"; import SemanticSDP from "semantic-sdp"; MediaServer.enableLog(true); @@ -13,7 +17,11 @@ try { MediaServer.setPortRange(min, max); } catch (error) { - console.error("Invalid env var: WEBRTC_PORT_RANGE", process.env.WEBRTC_PORT_RANGE, error); + console.error( + "Invalid env var: WEBRTC_PORT_RANGE", + process.env.WEBRTC_PORT_RANGE, + error, + ); process.exit(1); } @@ -48,4 +56,4 @@ export interface Client { export function getClients(channel_id: string) { if (!channels.has(channel_id)) channels.set(channel_id, new Set()); return channels.get(channel_id)!; -} \ No newline at end of file +} diff --git a/src/webrtc/util/index.ts b/src/webrtc/util/index.ts index 2e09bc48..f0d49049 100644 --- a/src/webrtc/util/index.ts +++ b/src/webrtc/util/index.ts @@ -1,2 +1,2 @@ export * from "./Constants"; -export * from "./MediaServer"; \ No newline at end of file +export * from "./MediaServer"; |