-
Add Group Chat to OBS
+Add Group Chat to OBS
-
Rooms allow for simplified group-chat and the advanced management of multiple streams at once.
-
Rooms allow for simplified group-chat and the advanced management of multiple streams at once.
+
-
+
- +
Rooms allow for simplified group-chat and the advanced management of multiple streams at once.
-
Room Name:
Rooms allow for simplified group-chat and the advanced management of multiple streams at once.
+
Room Name:
-
+
- +
-
+
-
-
-
+
@@ -119,53 +123,54 @@
Add your Camera to OBS
+Add your Camera to OBS
-
Select the audio/video source below
- +Select the audio/video source below
+
-
Video source:
+
Video source:
@@ -119,53 +123,54 @@
-
+
-
Remote Screenshare into OBS
+Remote Screenshare into OBS
-
- - +
-
note: Do not forget to click "Share audio" in Chrome.
(Firefox does not support audio sharing.)

+ note: Do not forget to click "Share audio" in Chrome.
(Firefox does not support audio sharing.)

- - +
-
Audio Sources:
+
Audio Sources:
-
+
-
- Here you can pre-generate a reusable Browser Source link and a related guest invite link.
+ Here you can pre-generate a reusable Browser Source link and a related guest invite link.
+
@@ -174,26 +179,27 @@
@@ -208,27 +214,27 @@
-
+
diff --git a/main.js b/main.js
index 5423b8f..b0bf590 100644
--- a/main.js
+++ b/main.js
@@ -1,8 +1,11 @@
-/////////////
-
-// Some browsers partially implement mediaDevices. We can't just assign an object
-// with getUserMedia as it would overwrite existing properties.
-// Here, we will just add the getUserMedia property if it's missing.
+/*
+* Copyright (c) 2020 Steve Seguin. All Rights Reserved.
+*
+* Use of this source code is governed by the APGLv3 open-source license
+* that can be found in the LICENSE file in the root of the source
+* tree. Alternative licencing options can be made available on request.
+*
+*/
var VIS = vis;
var formSubmitting = true;
@@ -13,7 +16,6 @@ window.onload = function() { // This just keeps people from killing the live str
if (formSubmitting) {
return undefined;
}
-
var confirmationMessage = 'Leaving the page now will terminate your stream ';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
@@ -43,11 +45,10 @@ window.onpopstate = function() {
}
};
-
-var session = Ooblex.Media;
+var session = WebRTC.Media;
session.streamID = session.generateStreamID();
-(function (w) {
+(function (w) {
w.URLSearchParams = w.URLSearchParams || function (searchString) {
var self = this;
self.searchString = searchString;
@@ -60,9 +61,9 @@ session.streamID = session.generateStreamID();
return decodeURI(results[1]) || 0;
}
};
- }
+ };
-})(window)
+})(window);
var urlParams = new URLSearchParams(window.location.search);
var isMobile = false;
@@ -77,9 +78,18 @@ if ((urlParams.has('permaid')) || (urlParams.has('push'))){
document.getElementById("container-4").className = 'column columnfade advanced';
}
-if (urlParams.has('stereo')){
+if (urlParams.has('stereo')){ // both peers need this enabled for HD stereo to be on. If just pub, you get no echo/noise cancellation. if just viewer, you get high bitrate mono
log("STEREO ENABLED");
- session.stereo = true;
+ session.stereo = true;
+}
+
+if ((urlParams.has('streamid')) || (urlParams.has('view'))){ // the streams we want to view; if set, but let blank, we will request no streams to watch.
+ session.view = urlParams.get('streamid') || urlParams.get('view'); // this value can be comma seperated for multiple streams to pull
+}
+
+if (urlParams.has('remote')){
+ log("remote ENABLED");
+ session.remote = parseInt(urlParams.get('remote'));
}
if (urlParams.has('nocursor')){
@@ -104,6 +114,52 @@ if (urlParams.has('codec')){
session.codec = urlParams.get('codec');
}
+if (urlParams.has('ln')){ // checking if manual lanuage override enabled
+ try {
+ fetch("./translations/"+urlParams.get('ln')+'.json').then(function(response){
+ if (response.status !== 200) {
+ console.log('Looks like there was a problem. Status Code: ' +
+ response.status);
+ return;
+ }
+ response.json().then(function(data) {
+ log(data);
+ document.querySelectorAll('[data-translate]').forEach(function(ele){
+ //log(ele.dataset.translate);
+ //log(translations[ele.dataset.translate]);
+ ele.innerHTML = data[ele.dataset.translate];
+ });
+ });
+ }).catch(function(err){
+ errorlog(err);
+ });
+
+ } catch (error){
+ errorlog(error);
+ }
+} else { // check if automatic language translation is available
+
+ if (window.navigator.language.slice(0, 2) !== 'en'){
+ fetch("./translations/"+window.navigator.language.slice(0, 2)+'.json').then(function(response){
+ if (response.status !== 200) {
+ logerror('Language translation file not found.' + response.status);
+ return;
+ }
+ response.json().then(function(data) {
+ log(data);
+ document.querySelectorAll('[data-translate]').forEach(function(ele){
+ //log(ele.dataset.translate);
+ //log(translations[ele.dataset.translate]);
+ ele.innerHTML = data[ele.dataset.translate];
+ });
+ });
+ }).catch(function(err){
+ errorlog(err);
+ });
+ }
+
+}
+
if (urlParams.has('bitrate')){
session.bitrate = parseInt(urlParams.get('bitrate'));
log("BITRATE ENABLED");
@@ -118,6 +174,11 @@ if (urlParams.has('width')){
session.width = parseInt(urlParams.get('width'));
}
+if (urlParams.has('sink')){
+ session.sink = urlParams.get('sink');
+}
+
+
if (urlParams.has('secure')){
session.security = true;
setTimeout(function() {alert("Enhanced Security Mode Enabled.");}, 100);
@@ -164,8 +225,12 @@ if (urlParams.has('turn')){
turn.credential = "justtesting";
turn.urls = ["turn:turn.obs.ninja:443"]; // main TURN server. Do not abuse. I pay out of pocket.
session.configuration.iceServers.push(turn);
- turn.urls = ["turn:turn2.obs.ninja:443"]; // backup TURN server. Do not abuse. I pay out of pocket.
- session.configuration.iceServers.push(turn);
+
+ var turn = {};
+ turn.username = "steve";
+ turn.credential = "justtesting";
+ turn.urls = ["turn:turn2.obs.ninja:443"]; // main TURN server. Do not abuse. I pay out of pocket.
+ session.configuration.iceServers.push(turn);
}
function updateURL(param) {
@@ -188,7 +253,6 @@ function updateURL(param) {
}
function jumptoroom(){
- document.getElementById("joinroomID").value;
var arr = window.location.href.split('?');
if (arr.length > 1 && arr[1] !== '') {
window.location+="&room="+document.getElementById("joinroomID").value;
@@ -263,10 +327,12 @@ if ( (urlParams.has('roomid')) || (filename) || (urlParams.has('room')) ){
function checkConnection(){
- if (session.ws.readyState === WebSocket.OPEN) {
- document.getElementById("qos").style.color = "white";
- } else {
- document.getElementById("qos").style.color = "red";
+ if (document.getElementById("qos")){
+ if (session.ws.readyState === WebSocket.OPEN) {
+ document.getElementById("qos").style.color = "white";
+ } else {
+ document.getElementById("qos").style.color = "red";
+ }
}
}
setInterval(function(){checkConnection();},5000);
@@ -281,7 +347,7 @@ function updateStats(){
log(track.getSettings());
log(track.getSettings().frameRate);
//log(track.getSettings().frameRate);
- document.getElementById("webcamstats").innerHTML = "Current Video Settings: "+(track.getSettings().width|0) +"x"+(track.getSettings().height|0)+"@"+(parseInt(track.getSettings().frameRate*10)/10)+"fps";
+ document.getElementById("webcamstats").innerHTML = "Current Video Settings: "+(track.getSettings().width||0) +"x"+(track.getSettings().height||0)+"@"+(parseInt(track.getSettings().frameRate*10)/10)+"fps";
}
);
}
@@ -328,7 +394,7 @@ function directEnable(ele){ // A directing room only is controlled by the Direct
var msg = {};
msg.request = "sendroom";
msg.roomid = session.roomid;
- msg.director = "1" // scene
+ msg.director = "1"; // scene
msg.action = "display";
msg.value = ele.parentNode.parentNode.dataset.enable;
msg.target = ele.parentNode.parentNode.dataset.UUID;
@@ -414,7 +480,7 @@ function publishScreen(){
};
if (session.framerate){
- constraints.video.frameRate = {exact: session.framerate};
+ constraints.video.frameRate = session.framerate;
}
var audioSelect = document.querySelector('select#audioSourceScreenshare');
@@ -472,10 +538,10 @@ function joinRoom(roomname, maxbitrate=false){
session.joinRoom(roomname,maxbitrate).then(function(response){ // callback from server; we've joined the room
log("Members in Room");
log(response);
- for (i in response){
+ for (var i in response){
if ("UUID" in response[i]){
if ("streamID" in response[i]){
- if (response[i]['UUID'] in session.pcs){
+ if (response[i].UUID in session.pcs){
log("RTC already connected"); /// lets just say instead of Stream, we have
} else {
//var title = ""; // TODO: Assign labels
@@ -483,17 +549,17 @@ function joinRoom(roomname, maxbitrate=false){
// title = response[i]["title"];
//}
- if ((urlParams.has('streamid')) || (urlParams.has('view'))){
- play(response[i]['streamID']);
+ if (session.view){ // if they want to watch specific streams only; perhaps from a list even
+ play(response[i].streamID);
} else {
- session.watchStream(response[i]['streamID']); // How do I make sure they aren't requesting the same movie twice as a race condition?
+ session.watchStream(response[i].streamID); // How do I make sure they aren't requesting the same movie twice as a race condition?
}
}
}
}
}
- },function(error){return {}});
+ },function(error){return {};});
} else {
errorlog("Room name not long enough or contained all bad characaters");
}
@@ -513,12 +579,6 @@ function createRoom(){
var gridlayout = document.getElementById("gridlayout");
gridlayout.classList.add("directorsgrid");
- // var sheet = document.createElement('style');
- // sheet.innerHTML = ".tile{object-fit:contain }";
- // document.body.appendChild(sheet);
-
- var roomname = document.getElementById("videoname1").value;
- log(roomname);
session.roomid = roomname;
formSubmitting = false;
@@ -539,12 +599,12 @@ function createRoom(){
session.director = true;
document.getElementById("reshare").parentNode.removeChild(document.getElementById("reshare"));
- gridlayout.innerHTML = "
- Link to add a camera to the group. This source will not be able to see or hear any other guest in the group.
"; + gridlayout.innerHTML += "
- Link to Invite users to broadcast their feeds to the group. These users will not see or hear any feed from the group.
"; - gridlayout.innerHTML += " - This is a OBS Browser Source link that contains the group chat in just a single scene. Videos must be added to Group Scene.
"; + gridlayout.innerHTML += " - This is an OBS Browser Source link that contains the group chat in just a single scene. Videos must be added to Group Scene.
"; gridlayout.innerHTML += ''; @@ -557,7 +617,7 @@ function createRoom(){You can use it to record video streams independently \
\ As guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\ -
The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.
The Group Scene includes all audio sources by default, but they can be muted manually.
Apple mobile devices, such as iPhones and iPads, do not support Group Chat. This is a hardware constraint.
Create Reusable Invite
+Create Reusable Invite
- Here you can pre-generate a reusable Browser Source link and a related guest invite link.
+ Here you can pre-generate a reusable Browser Source link and a related guest invite link.
+
-
+
+
+
+100% free; no downloads; no personal data collection; no sign-in
+ Bring video from your smartphone, laptop, computer, or from your friends directly into your OBS video stream
+ We use cutting edge Peer-to-Peer forwarding technology that offers privacy and ultra-low latency
+
+Youtube video Demoing it here
+ Code is available here: https://github.com/steveseguin/obsninja
+ You can also check out my other video app designed for sharing video with friends and family
+
+ Known issues:
-
-100% free; no downloads; no personal data collection; no sign-in
- Bring video from your smartphone, laptop, computer, or from your friends directly into your OBS video stream
- We use cutting edge Peer-to-Peer forwarding technology that offers privacy and ultra-low latency
-
-Youtube video Demoing it here
- Code is available here: https://github.com/steveseguin/obsninja
- You can also check out my other video app designed for sharing video with friends and family
-
- Known issues:
+ MacOS users need to use OBS v23 or resort to Window Capturing a Chrome Browser with OBS v25
+ Some users will have "pixelation" problems with videos. Please add the URL parameter &codec=vp9 to the OBS Links to correct it.
+
+ + Site last updated: May 7th, 2020. The previous version can be found at https://obs.ninja/v3/ if you are having new issues. - MacOS users need to use OBS v23 or resort to Window Capturing a Chrome Browser with OBS v25
- Some users will have "pixelation" problems with videos. Please add the URL parameter &codec=vp9 to the OBS Links to correct it.
-
- - Site last updated: May 7th, 2020. The previous version can be found at https://obs.ninja/v3/ if you are having new issues. - -
-
+
What is OBS.Ninja
+
+
+ Known issues:
-
What is OBS.Ninja
-
-
- Known issues:
+
+ + Site last updated: May 7th, 2020. The previous version can be found at https://obs.ninja/v3/ if you are having new issues. -
- - Site last updated: May 7th, 2020. The previous version can be found at https://obs.ninja/v3/ if you are having new issues. - -
-
Check out the sub-reddit for help and advanced info. I'm also on Discord and you can email me at steve@seguin.email
++
Check out the sub-reddit for help and advanced info. I'm also on Discord and you can email me at steve@seguin.email
+ - Invite link to add guests to the group. These guests will see every camera feed, so more than 4 is not recommended.
";
+ gridlayout.innerHTML = " - Invites users to join the group and broadcast their feed to it. These users will see every feed, so a limit of 4 is recommended.
";
- gridlayout.innerHTML += "- Link to add a camera to the group. This source will not be able to see or hear any other guest in the group.
"; + gridlayout.innerHTML += "
- Link to Invite users to broadcast their feeds to the group. These users will not see or hear any feed from the group.
"; - gridlayout.innerHTML += " - This is a OBS Browser Source link that contains the group chat in just a single scene. Videos must be added to Group Scene.
"; + gridlayout.innerHTML += " - This is an OBS Browser Source link that contains the group chat in just a single scene. Videos must be added to Group Scene.
"; gridlayout.innerHTML += ''; @@ -557,7 +617,7 @@ function createRoom(){
\ As guests join, their videos will appear below. You can bring their video streams into OBS as solo-scenes or you can add them to the Group Scene.\ -
The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.
The Group Scene includes all audio sources by default, but they can be muted manually.
Apple mobile devices, such as iPhones and iPads, do not support Group Chat. This is a hardware constraint.
"; +
The Group Scene auto-mixes videos that have been added to the group scene. Please note that the Auto-Mixer requires guests be manually added to it for them to appear in it; they are not added automatically.
Apple mobile devices, such as iPhones and iPads, do not support Group Chat. This is a hardware constraint.