From b68d55b7ef778c0ce1e6754412c482a1ece63f17 Mon Sep 17 00:00:00 2001 From: rainbow napkin Date: Sat, 11 Jul 2026 03:07:17 -0400 Subject: [PATCH] Started work on WebRTC Negotation Relay Backend --- config.example.json | 5 ++ config.example.jsonc | 6 ++ src/app/channel/activeChannel.js | 9 ++- src/app/channel/connectedUser.js | 2 +- src/app/channel/media/queue.js | 8 +-- src/app/channel/media/webRTCHandler.js | 81 ++++++++++++++++++++++++++ www/js/channel/channel.js | 3 + 7 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 src/app/channel/media/webRTCHandler.js diff --git a/config.example.json b/config.example.json index 7b869b3..990e2a7 100644 --- a/config.example.json +++ b/config.example.json @@ -34,6 +34,11 @@ "address": "toke@42069.weed", "pass": "CHANGE_ME" }, + "iceServers":[ + { + "url":"stun:stun.moonlight-stream.org:3478" + } + ], "links":{ "About": "/about", "Code": "https://git.ourfore.st/rainbownapkin/canopy", diff --git a/config.example.jsonc b/config.example.jsonc index 3669d09..c9dfb42 100644 --- a/config.example.jsonc +++ b/config.example.jsonc @@ -65,6 +65,12 @@ "address": "toke@42069.weed", "pass": "CHANGE_ME" }, + //Privdes STUN/TURN servers for WebRTC functionality + "iceServers":[ + { + "url":"stun:stun.moonlight-stream.org:3478" + } + ], //Provides customizable links for navbar "links":{ "About": "/about", diff --git a/src/app/channel/activeChannel.js b/src/app/channel/activeChannel.js index 54e4fc5..44b170d 100644 --- a/src/app/channel/activeChannel.js +++ b/src/app/channel/activeChannel.js @@ -19,7 +19,8 @@ const connectedUser = require('./connectedUser'); const chatBuffer = require('./chatBuffer'); const queue = require('./media/queue'); const channelModel = require('../../schemas/channel/channelSchema'); -const playlistHandler = require('./media/playlistHandler') +const playlistHandler = require('./media/playlistHandler'); +const webRTCHandler = require('./media/webRTCHandler'); /** * Class representing a single active channel @@ -67,6 +68,11 @@ class activeChannel{ */ this.playlistHandler = new playlistHandler(server, this); + /** + * Child WebRTC Handler Object + */ + this.webRTCHandler = new webRTCHandler(server, this); + /** * Child Chat Buffer Object */ @@ -108,6 +114,7 @@ class activeChannel{ //Define per-channel event listeners this.queue.defineListeners(socket); this.playlistHandler.defineListeners(socket); + this.webRTCHandler.defineListeners(socket); //Hand off the connection initiation to it's user object const activeUser = await userObj.handleConnection(userDB, chanDB, socket) diff --git a/src/app/channel/connectedUser.js b/src/app/channel/connectedUser.js index 5347cb4..54839ef 100644 --- a/src/app/channel/connectedUser.js +++ b/src/app/channel/connectedUser.js @@ -236,7 +236,7 @@ class connectedUser{ const chatBuffer = this.channel.chatBuffer.buffer; //Send off the metadata to our user's clients - this.emit("clientMetadata", {user: userObj, flairList, queueLock, chatBuffer, streamType: chanDB.settings.streamType}); + this.emit("clientMetadata", {user: userObj, flairList, queueLock, chatBuffer, streamType: chanDB.settings.streamType, iceServers: config.iceServers}); } /** diff --git a/src/app/channel/media/queue.js b/src/app/channel/media/queue.js index de77df4..8dbe0f6 100644 --- a/src/app/channel/media/queue.js +++ b/src/app/channel/media/queue.js @@ -331,8 +331,8 @@ class queue{ try{ //Define and/or declare required variables let title = "Livestream"; - let filename; - let streamURL; + let filename = '/'; + let streamURL = '/'; if(data != null && data.title != null){ //If the title is too long @@ -368,10 +368,10 @@ class queue{ return; } - if(chanDB.settings.streamType == "webrtc"){ + /*if(chanDB.settings.streamType == "webrtc"){ console.log("WEBRTC ENABLED, BAILING!"); return; - } + }*/ //If something is playing if(this.nowPlaying != null){ diff --git a/src/app/channel/media/webRTCHandler.js b/src/app/channel/media/webRTCHandler.js new file mode 100644 index 0000000..e091e22 --- /dev/null +++ b/src/app/channel/media/webRTCHandler.js @@ -0,0 +1,81 @@ +/*Canopy - The next generation of stoner streaming software +Copyright (C) 2024-2026 Rainbownapkin and the TTN Community + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see .*/ + +/** + * Object to relay WebRTC Negotiation data for a single channel + */ +class webRTCHandler{ + /** + * Instantiates a new object to relay WebRTC Negotiation data for a single channel + * @param {channelManager} server - Parent server object + * @param {activeChannel} channel - Parent Channel object + */ + constructor(server, channel){ + /** + * Parent Server Object + */ + this.server = server + + /** + * Parent Channel Object + */ + this.channel = channel; + + /** + * Declare class property to hold socked it of the current device/browser-tab we're streaming from + */ + this.currentStreamer; + } + + /** + * Defines server-side socket.io listeners for newly connected sockets + * @param {Socket} socket - Newly connected socket to define listeners against + */ + defineListeners(socket){ + //Queueing Functions + socket.on("relayRTCData", (data) => {this.relayRTCData(socket, data)}); + } + + startStream(socket){ + this.currentStreamer = socket.id; + } + + endStream(){ + this.currentStreamer = null; + } + + relayRTCData(socket, data){ + //Set the recipient to the current streamer by default, assuming that this isn't coming from the streaming socket + let recipientID = this.currentStreamer; + + //if data is being relayed from streaming socket to a viewer + if(socket.id == this.currentStreamer){ + //Change recipient to reflect streaming socket's request + recipientID = data.recipient; + } + + //Get recipient socket + const recipient = this.server.io.sockets.sockets.get(recipientID); + + //Relay RTC Data + recipient.emit("RTCData", { + type: data.type, + body: data.body + }); + } +} + +module.exports = webRTCHandler; \ No newline at end of file diff --git a/www/js/channel/channel.js b/www/js/channel/channel.js index 840b939..96c85f0 100644 --- a/www/js/channel/channel.js +++ b/www/js/channel/channel.js @@ -153,6 +153,9 @@ class channel{ //Store streamType this.streamType = data.streamType; + + //Store URLs to known Internet Connectivitey Establishment servers. + this.iceServer = data.iceServers; } /**