diff --git a/config.example.json b/config.example.json
index 990e2a7..7b869b3 100644
--- a/config.example.json
+++ b/config.example.json
@@ -34,11 +34,6 @@
"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 c9dfb42..3669d09 100644
--- a/config.example.jsonc
+++ b/config.example.jsonc
@@ -65,12 +65,6 @@
"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 44b170d..54e4fc5 100644
--- a/src/app/channel/activeChannel.js
+++ b/src/app/channel/activeChannel.js
@@ -19,8 +19,7 @@ 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 webRTCHandler = require('./media/webRTCHandler');
+const playlistHandler = require('./media/playlistHandler')
/**
* Class representing a single active channel
@@ -68,11 +67,6 @@ class activeChannel{
*/
this.playlistHandler = new playlistHandler(server, this);
- /**
- * Child WebRTC Handler Object
- */
- this.webRTCHandler = new webRTCHandler(server, this);
-
/**
* Child Chat Buffer Object
*/
@@ -114,7 +108,6 @@ 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/media/queue.js b/src/app/channel/media/queue.js
index e6d9c2c..ac2eb75 100644
--- a/src/app/channel/media/queue.js
+++ b/src/app/channel/media/queue.js
@@ -329,11 +329,7 @@ class queue{
*/
async goLive(socket, data){
try{
- //Define and/or declare required variables
let title = "Livestream";
- let filename = '/';
- let streamURL = '/';
- let rawLink = {combo: [['default', config.iceServers]]};
if(data != null && data.title != null){
//If the title is too long
@@ -369,6 +365,11 @@ class queue{
return;
}
+ if(chanDB.settings.streamType == "webrtc"){
+ console.log("WEBRTC ENABLED, BAILING!");
+ return;
+ }
+
//If something is playing
if(this.nowPlaying != null){
//Capture currently playing object
@@ -382,33 +383,24 @@ class queue{
//Kill schedule timers to prevent items from starting during the stream
await this.stopScheduleTimers();
- //If we're streaming via HLS
- if(chanDB.settings.streamType == "livehls"){
- //Syntatic sugar because I'm lazy :P
- streamURL = chanDB.settings.streamURL;
+ //Syntatic sugar because I'm lazy :P
+ const streamURL = chanDB.settings.streamURL;
- if(streamURL == ''){
- throw loggerUtils.exceptionSmith('This channel\'s HLS Livestream Source has not been set!', 'queue');
- }
+ if(streamURL == ''){
+ throw loggerUtils.exceptionSmith('This channel\'s HLS Livestream Source has not been set!', 'queue');
+ }
- //Pull filename from streamURL
- filename = streamURL.match(/^.+\..+\/(.+)$/);
+ //Pull filename from streamURL
+ let filename = streamURL.match(/^.+\..+\/(.+)$/);
- //If we're streaming from the root of the domain
- if(filename == null){
- //Set filename to root
- filename = '/';
- }else{
- //Otherwise, hand over the filename
- filename = filename[1];
- }
-
- rawLink = {combo:[['default',streamURL]]};
- //Otherwise if we're starting a web RTC Stream
- }else if(chanDB.settings.streamType == "webrtc"){
- //Let our webRTCHandler know
- this.channel.webRTCHandler.startStream(socket);
+ //If we're streaming from the root of the domain
+ if(filename == null){
+ //Set filename to root
+ filename = '/';
+ }else{
+ //Otherwise, hand over the filename
+ filename = filename[1];
}
//Create queued media object from stream URL and set it to nowPlaying
@@ -417,9 +409,9 @@ class queue{
filename,
streamURL,
streamURL,
- chanDB.settings.streamType,
+ "livehls",
0,
- rawLink,
+ streamURL,
new Date().getTime()
);
@@ -1269,7 +1261,7 @@ class queue{
}
//If we're ending an HLS Livestream
- if(wasPlaying.type == "livehls" || wasPlaying.type == "webrtc"){
+ if(wasPlaying.type == "livehls"){
//Redirect to the endLivestream function
return this.endLivestream(wasPlaying, chanDB)
}
@@ -1350,11 +1342,6 @@ class queue{
//Set duration from start and end time
wasPlaying.duration = (now - wasPlaying.startTime) / 1000;
- //If we're ending a webrtc stream
- if(wasPlaying.type == "webrtc"){
- this.channel.webRTCHandler.endStream();
- }
-
//If we're in pushback mode
if(this.liveMode == "pushback"){
await this.livestreamPushbackSchedule(wasPlaying, chanDB);
@@ -1582,7 +1569,7 @@ class queue{
const stoppedMedia = this.nowPlaying;
//Ignore early end for livestreams
- if(this.nowPlaying.type != 'livehls' && this.nowPlaying.type != 'webrtc'){
+ if(this.nowPlaying.type != 'livehls'){
//Get difference between current time and start time and set as early end
stoppedMedia.earlyEnd = (new Date().getTime() - stoppedMedia.startTime) / 1000;
}
@@ -1819,7 +1806,7 @@ class queue{
const now = new Date().getTime();
//If something was playing
- if(chanDB.media.nowPlaying != null && (chanDB.media.nowPlaying.type != 'livehls' && chanDB.media.nowPlaying.type != 'webrtc')){
+ if(chanDB.media.nowPlaying != null && chanDB.media.nowPlaying.type != 'livehls'){
//Rehydrate the currently playing item int oa queued media object
const wasPlaying = chanDB.media.nowPlaying.rehydrate();
diff --git a/src/app/channel/media/webRTCHandler.js b/src/app/channel/media/webRTCHandler.js
deleted file mode 100644
index 19f7c08..0000000
--- a/src/app/channel/media/webRTCHandler.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/*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)});
- socket.on("disconnect", (data) => {this.handleStreamerDisconnect(socket, data)});
- }
-
- handleStreamerDisconnect(socket){
- //If the disconnecting socket is the current streamer
- if(socket.id == this.currentStreamer){
- //Tell the queue to stop current stream
- this.channel.queue.stop();
- }
- }
-
- 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;
-
- //Create object to hold data being relayed to client
- let webRTCData = {
- type: data.type,
- body: data.body
- };
-
- //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;
- //Otherwise if the data is being relayed from a viewer to the streaming socket
- }else{
- //Add viewers socket id
- webRTCData.source = {
- user: socket.user.user,
- socket: socket.id
- };
- }
-
- //Get recipient socket
- const recipient = this.server.io.sockets.sockets.get(recipientID);
-
- //If we have a recipient
- if(recipient != null){
- //Relay RTC Data
- recipient.emit("RTCData", webRTCData);
- }
- }
-}
-
-module.exports = webRTCHandler;
\ No newline at end of file
diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js
index bd02fe0..8bfa484 100644
--- a/src/schemas/channel/channelSchema.js
+++ b/src/schemas/channel/channelSchema.js
@@ -38,7 +38,7 @@ const { exceptionHandler, errorHandler } = require('../../utils/loggerUtils');
/**
* "Enum" for emote type property
*/
-const streamMethodEnum = ["webrtc","livehls"];
+const streamMethodEnum = ["webrtc","hls"];
/**
* DB Schema for Documents containing de-hydrated representations of Canopy Stream/Chat Channels
diff --git a/src/validators/channelValidator.js b/src/validators/channelValidator.js
index 0e9be56..9c87f55 100644
--- a/src/validators/channelValidator.js
+++ b/src/validators/channelValidator.js
@@ -85,7 +85,7 @@ module.exports.settingsMap = function(){
optional: true,
errorMessage: "Invalid Stream Type",
matches: {
- options: [/\b(?:webrtc|livehls)\b/]
+ options: [/\b(?:webrtc|hls)\b/]
}
}
})
diff --git a/src/views/channel.ejs b/src/views/channel.ejs
index 30dbbd4..4dac445 100644
--- a/src/views/channel.ejs
+++ b/src/views/channel.ejs
@@ -48,7 +48,6 @@ along with this program. If not, see . %>
-
<%# panels %>
diff --git a/src/views/partial/channelSettings/settings.ejs b/src/views/partial/channelSettings/settings.ejs
index feb30c4..d8dd2ea 100644
--- a/src/views/partial/channelSettings/settings.ejs
+++ b/src/views/partial/channelSettings/settings.ejs
@@ -42,10 +42,10 @@ along with this program. If not, see . %>
- checked <% }%> >
+ checked <% }%> >
- disabled <%}%> id="channel-preference-list-stream-url" placeholder="Stream URL" value="<%= channel.settings["streamURL"] %>">
+ disabled <%}%> id="channel-preference-list-stream-url" placeholder="Stream URL" value="<%= channel.settings["streamURL"] %>">
diff --git a/www/js/channel/channel.js b/www/js/channel/channel.js
index bd6b181..840b939 100644
--- a/www/js/channel/channel.js
+++ b/www/js/channel/channel.js
@@ -56,8 +56,6 @@ class channel{
* Child PM Handler
*/
this.pmHandler = new pmHandler(this);
-
- this.webRTCHandler = new webRTCHandler(this);
/**
* Child Canopy Panel Object
diff --git a/www/js/channel/mediaHandler.js b/www/js/channel/mediaHandler.js
index 97708c5..0923876 100644
--- a/www/js/channel/mediaHandler.js
+++ b/www/js/channel/mediaHandler.js
@@ -926,74 +926,4 @@ class hlsLiveStreamHandler extends hlsBase{
}
}
}
-}
-
-/**
- * Wrapper handler for WebRTC Streams, calling back to webRTCHandler.js for heavy lifting
- * @extends rawFileBase
- */
-class WebRTCLivestreamHandler extends rawFileBase{
- /**
- /**
- * Instantiates a new WebRTCMediaHandler
- * @param {channel} client - Parent Client Management Object
- * @param {player} player - Parent Canopy Player Object
- * @param {Object} media - De-hydrated media object from server
- */
- constructor(client, player, media){
- //Call derived constructor
- super(client, player, media, "webrtc");
-
- this.defineListeners();
- }
-
- defineListeners(){
- //Run derived method
- super.defineListeners();
-
- //Disable right clicking
- this.video.addEventListener('contextmenu', (e)=>{e.preventDefault()});
- }
-
-
- async buildPlayer(){
- //Call derived buildPlayer function
- super.buildPlayer();
-
- /**
- * set Internet Connectivity Establishment configuration
- */
- this.client.webRTCHandler.iceConfig = {
- iceServers: new Map(this.nowPlaying.rawLink.combo).get('default')
- };
-
- //If we're not streaming
- if(!this.client.webRTCHandler.isStreaming){
- //Send stream request
- await this.client.webRTCHandler.requestStream();
- }
- }
-
- start(){
- //call derived start function
- super.start();
-
- //Lock the player
- this.setPlayerLock(true);
- }
-
- setVideoTitle(title){
- //Add title as text content for security :P
- this.player.title.innerText = `: ${utils.unescapeEntities(title)}`;
-
- //Create glow span
- const glowSpan = document.createElement('span');
- //Fill glow span content
- glowSpan.innerText = "🔴LIVE";
- //Set glowspan class
- glowSpan.classList.add('critical-danger-text');
-
- //Inject glowspan into title in a way that allows it to be easily replaced
- this.player.title.prepend(glowSpan);
- }
}
\ No newline at end of file
diff --git a/www/js/channel/panels/queuePanel/queuePanel.js b/www/js/channel/panels/queuePanel/queuePanel.js
index 4224c47..7f258e3 100644
--- a/www/js/channel/panels/queuePanel/queuePanel.js
+++ b/www/js/channel/panels/queuePanel/queuePanel.js
@@ -188,7 +188,7 @@ class queuePanel extends panelObj{
*/
handleStart(data){
//If we're starting an HLS Livestream
- if(data.media != null && (data.media.type == 'livehls' || data.media.type == 'webrtc' )){
+ if(data.media != null && data.media.type == 'livehls'){
//Hide the 'goLive' controls
this.goLiveDiv.style.display = 'none';
}
@@ -282,7 +282,7 @@ class queuePanel extends panelObj{
client.socket.emit('getStreamType');
//If we're not livestreaming
- if(client.player.mediaHandler.type != "livehls" && client.player.mediaHandler.type != "webrtc"){
+ if(client.player.mediaHandler.type != "livehls"){
//If the div is hidden
if(this.goLiveDiv.style.display == 'none'){
//Show the div
@@ -306,14 +306,7 @@ class queuePanel extends panelObj{
* Handles sending request to server to start a live stream
* @param {Event} event - Event passed down from Event Listener
*/
- async goLive(event){
- //If we're broadcastinv via webrtc
- if(this.client.streamType == "webrtc"){
- this.client.webRTCHandler.isBroadcasting = true;
-
- this.client.webRTCHandler.broadcastingStream = await navigator.mediaDevices.getDisplayMedia();
- }
-
+ goLive(event){
//Start a livestream
client.socket.emit('goLive',{title: this.goLiveNamePrompt.value, mode: event.target.dataset['mode']});
}
@@ -1195,7 +1188,7 @@ class queuePanel extends panelObj{
const staleEntry = this.queueContainer.querySelector('.queue-entry.live');
//If we're not livestreaming
- if(client.player.mediaHandler.type != "livehls" && client.player.mediaHandler.type != "webrtc"){
+ if(client.player.mediaHandler.type != "livehls"){
//If we have a stale entry
if(staleEntry != null){
//Remove stale entry since we're no longer streaming
diff --git a/www/js/channel/player.js b/www/js/channel/player.js
index a454e2e..26413d6 100644
--- a/www/js/channel/player.js
+++ b/www/js/channel/player.js
@@ -188,9 +188,6 @@ class player{
}else if(data.media.type == "livehls"){
//Create a new HLS Livestream Handler for it
this.mediaHandler = new hlsLiveStreamHandler(this.client, this, data.media);
- }else if(data.media.type == "webrtc"){
- //Create a new HLS Livestream Handler for it
- this.mediaHandler = new WebRTCLivestreamHandler(this.client, this, data.media);
}else if(data.media.type == 'dm'){
this.mediaHandler = new hlsDailymotionHandler(this.client, this, data.media);
//Otherwise, if we have a raw-file compatible source
diff --git a/www/js/channel/webRTCHandler.js b/www/js/channel/webRTCHandler.js
deleted file mode 100644
index d5a08f1..0000000
--- a/www/js/channel/webRTCHandler.js
+++ /dev/null
@@ -1,276 +0,0 @@
-/*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 .*/
-
-/**
- * Class for handling negotiation between peers during WebRTC Livestreams
- */
-class webRTCHandler{
- /**
- * Instantiates a new webRTCHandler object
- * @param {channel} client - Parent client mgmt object
- */
- constructor(client){
- /**
- * Parent Client Management object
- */
- this.client = client
-
- /**
- * Flag thrown when this device is broadcasting via webRTC
- */
- this.isBroadcasting = false;
-
- /**
- * Create variable to hold the peer connection object for the currently playing remote stream
- */
- this.currentStream;
-
- /**
- * Create variable to hold currently broadcasting stream
- */
- this.broadcastingStream;
-
- /**
- * Create map to hold objects representing viewers receiving our broadcasted stream, organized by username
- */
- this.currentViewers = new Map();
-
- /**
- * Create variable to hold Internet Connectivity Establishment configuration
- */
- this.iceConfig;
-
- //Call setup functions
- this.setupInput();
- this.defineListeners();
- }
-
- /**
- * Defines input-related event listeners
- */
- setupInput(){
- }
-
- /**
- * Defines network-related event listeners
- */
- defineListeners(){
- this.client.socket.on("RTCData", this.handleRTCData.bind(this));
- }
-
- /**
- * Handles and routes incoming RTC Messages
- * Normally I'd use dedicated socket.io message types, however throwing user input seems like bad security practice
- * I'll take ugly code over insecure code any day of the week
- */
- handleRTCData(data){
- //If we're brodcasting
- if(this.isBroadcasting){
- switch(data.type){
- case "request":
- this.handleViewer(data);
- break;
- case "candidate":
- this.handleIceCandidate(data);
- break;
- }
- //otherwise
- }else{
- switch(data.type){
- case "answer":
- this.handleAnswer(data);
- break;
- case "candidate":
- this.handleIceCandidate(data);
- break;
- }
- }
- }
-
- /**
- * Requests stream from streamer
- */
- async requestStream(){
- //If we're streaming
- if(this.client.webRTCHandler.isBroadcasting){
- //fack off and die
- return;
- }
-
- //Create new peer connection w/ provided ice config
- this.currentStream = new RTCPeerConnection(this.iceConfig)
-
- //Not really used atm but it's necissary for most browsers to need either a data channel or media track
- //addeed to the requesting peer before they start pulling ICE candidates...
- this.currentStream.createDataChannel("aux");
-
- this.currentStream.addEventListener('icecandidate', this.sendIceCandidate.bind(this));
-
- //Create offer from peerConnection
- const offer = await this.currentStream.createOffer();
-
- //Set offer as peerConnections local description
- await this.currentStream.setLocalDescription(offer);
-
- //Send RTC connection offer to server to be relayed to streamer's device
- this.client.socket.emit("relayRTCData", {type:"request",body:offer});
- }
-
- /**
- * Handles request to connect to streamer from channel viewer
- * @param {data} data - Data from requesting socket
- */
- async handleViewer(data){
- //Check if user is already viewing stream
- const viewer = this.currentViewers.get(data.source.user);
-
- //If not
- if(data.user == null){
- //Create a new connected viewer object from the received data, and store it in the currentViewers map by username
- this.currentViewers.set(data.source.user, new connectedViewer(
- data.source.user,
- data.source.socket,
- data.body,
- this.broadcastingStream,
- this.iceConfig,
- this.client));
- //Otherwise, if they're already watching elsewhere via the same account
- }else{
- //Hand over new socket ID and offer to the currentViewer object assigned to the current user
- await viewer.addSocket(data.source.socket, data.body);
-
- //Update the object within the currentViewers map
- this.currentViewers.set(data.source.user, viewer);
- }
- }
-
- async handleAnswer(data){
- //Get answer from received data
- const answer = new RTCSessionDescription(data.body);
-
- //Set remote desription
- this.currentStream.setRemoteDescription(answer);
- }
-
- sendIceCandidate(event){
- //If we have a candidate
- if(event.candidate != null){
- //Send that shit off!
- this.client.socket.emit('relayRTCData',{
- type: 'candidate',
- body: event.candidate
- });
- }
- }
-
- handleIceCandidate(data){
- //If we're broadcasting
- if(this.isBroadcasting){
- const user = this.currentViewers.get(data.source.user);
- user.handleIceCandidate(data);
- //If we're receiving a stream
- }else{
- this.currentStream.addIceCandidate(data.body);
- }
- }
-}
-
-/**
- * Class representing a single connected viewer
- */
-class connectedViewer{
- constructor(user, socket, offer, broadcastingStream, iceConfig, client){
- /**
- * Name of user
- */
- this.user = user;
-
- /**
- * Map of user's connected peers by socket
- */
- this.peers = new Map();
-
- /**
- * Broadcasting Stream
- */
- this.broadcastingStream = broadcastingStream;
-
- /**
- * ICE Config
- */
- this.iceConfig = iceConfig;
-
- /**
- * Client channe object
- */
- this.client = client;
-
- //Intake initial connection offer from user
- this.addSocket(socket, offer);
- }
-
- async addSocket(socket, offer){
- //Create peer from iceConfig
- const peer = new RTCPeerConnection(this.iceConfig);
-
- for(const track of this.broadcastingStream.getTracks()){
- peer.addTrack(track, this.broadcastingStream);
- }
-
- peer.addEventListener('icecandidate', this.sendIceCandidate.bind(this));
-
- //Set peer remote description to connection offer from viewer
- peer.setRemoteDescription(new RTCSessionDescription(offer));
-
- //Generate answer to connection offer
- const answer = await peer.createAnswer();
-
- //Set answer as local description
- await peer.setLocalDescription(answer);
-
- //Save peer by socket identifier
- this.peers.set(socket, peer);
-
- //Send answer to server to relay to peer
- this.client.socket.emit('relayRTCData',{
- type:'answer',
- body:answer,
- recipient: socket
- });
- }
-
- sendIceCandidate(event){
- //If we have a candidate
- if(event.candidate != null){
- //Send that shit off!
- this.client.socket.emit('relayRTCData',{
- type: 'candidate',
- body: event.candidate,
- recipient: this.socket
- });
- }
- }
-
- handleIceCandidate(data){
- console.log(this);
- const peer = this.peers.get(data.source.socket);
- console.log(peer);
- peer.addIceCandidate(data.body);
-
- //Save peer by socket identifier
- this.peers.set(data.source.socket, peer);
- }
-}
\ No newline at end of file
diff --git a/www/js/channelSettings.js b/www/js/channelSettings.js
index a048b76..74bbe49 100644
--- a/www/js/channelSettings.js
+++ b/www/js/channelSettings.js
@@ -412,7 +412,7 @@ class livestreamPreferences{
handleTypeUpdate(data){
//If the stream type is HLS
- if(data.streamType == "livehls" || data.streamType == "webrtc"){
+ if(data.streamType == "hls"){
//Ensure the hls button is checked
this.hlsButton.checked = true;
//Ensure the stream url input is enabled