mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-17 00:28:33 +00:00
Merge branch 'master' into v20.0-beta
This commit is contained in:
commit
38ee1f0f58
11
LICENCE.md
11
LICENCE.md
@ -1,15 +1,14 @@
|
||||
The OBS.Ninja source repository is governed by the GNU AFFERO GENERAL PUBLIC LICENSE. (AGPL-3.0)
|
||||
That AGPL-3.0 licence can be found here: [AGPLv3.md](https://github.com/steveseguin/obsninja/blob/master/AGPLv3.md)
|
||||
The VDO.Ninja source repository is governed by the GNU AFFERO GENERAL PUBLIC LICENSE. (AGPL-3.0)
|
||||
That AGPL-3.0 licence can be found here: [AGPLv3.md](https://github.com/steveseguin/vdo.ninja/blob/master/AGPLv3.md)
|
||||
|
||||
In essence, OBS.Ninja is open-source and free to use, both for commercial and non-commercial use.
|
||||
In essence, VDO.Ninja is open-source and free to use, both for commercial and non-commercial use.
|
||||
Modifications of AGPL-3.0 licenced code must be made publicly accessible. Please refer to that licence.
|
||||
|
||||
Some individual source files may contain different licencing term and perhaps different copyright holders.
|
||||
Such licencing and copyright information will be contained in the file's header and be limited to those files.
|
||||
If no such header is present in a file, the default AGPL-3.0 licence applies.
|
||||
Alternative licencing options can be made available on request, if AGPL-3.0 is not appropriate.
|
||||
|
||||
Unless stated otherwise, all code is copyright 2020 Stephen Seguin. All rights reserved.
|
||||
Contributors to the OBS.Ninja project must first agree to the Contributor License Agreement (CLA).
|
||||
Unless stated otherwise, all code is copyright 2021 Stephen Seguin. All rights reserved.
|
||||
Contributors to the VDO.Ninja project must first agree to the Contributor License Agreement (CLA).
|
||||
|
||||
Thank you for your understanding.
|
||||
|
||||
@ -773,7 +773,7 @@
|
||||
Some devices that use hardware encoding can experience video glitching; switching to VP8 or VP9 as a <a target='_blank' title='Jump to the documentation' href='https://docs.vdo.ninja/viewers-settings/codec'>codec</a> may help.
|
||||
</li>
|
||||
<li>
|
||||
Video glitching and random audio-loss can occur when using the OBS browser source. The <a href='https://github.com/steveseguin/electroncapture/blob/master/README.md' target="_blank">Electron Capture app</a> avoids these issues.
|
||||
Video glitching and random audio-loss can occur when using the OBS browser source. The <a href='https://github.com/steveseguin/electroncapture/blob/master/README.md'>Electron Capture app</a> avoids these issues.
|
||||
</li>
|
||||
<li>
|
||||
Samsung smartphones (A-series) may fail to publish video with some mobile browsers; try using Firefox or the native <a href='https://docs.vdo.ninja/getting-started/native-mobile-app-versions#android-download-link'>VDO.Ninja Android app</a> in these cases.
|
||||
@ -784,7 +784,6 @@
|
||||
</h4>
|
||||
<br />
|
||||
🎁 Welcome to v20, updated December 24th. 🎄 <a target="_blank" href="https://docs.vdo.ninja/release-notes/v20">Release notes are here</a>. The previous version is <a href="https://vdo.ninja/v19/">available here</a> if you have new issues.
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<h3>
|
||||
@ -1865,10 +1864,9 @@
|
||||
|
||||
// session.configuration.iceTransportPolicy = "relay"; // uncomment to enable "&privacy" and force the TURN server
|
||||
|
||||
// session.wss = "wss://api.vdo.ninja:443"; // US-East (Default)
|
||||
|
||||
/// If wanting to fully-self-host, uncomment the following and deploy your own websocket server; good for air-gapped deployments
|
||||
// session.wss = "wss://wss.yourdomainhere.com:443"; // https://github.com/steveseguin/websocket_server
|
||||
// session.wss = "wss://wss.contribute.cam:443"; // https://github.com/steveseguin/websocket_server
|
||||
// session.customWSS = true;
|
||||
//////
|
||||
|
||||
@ -1906,6 +1904,7 @@
|
||||
</script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=246"></script>
|
||||
|
||||
<!--
|
||||
// If you wish to change branding, blank offers a good clean start.
|
||||
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
||||
|
||||
38
install.md
38
install.md
@ -4,20 +4,15 @@ Deploying this code. A guide.
|
||||
|
||||
The code is obvious enough already that someone experienced with NGINX webservers or with basic site deployments should have no problem getting things running.
|
||||
|
||||
I'm concerned at times that less experienced users will be deploying the code without really understanding why or properly how to. There are few cases a person needs to deploy any code. Those reasons are: wanting custom branding; contributing as a developer to the codebase; or deploying a private TURN server.
|
||||
I'm concerned at times that less experienced users will be deploying the code without really understanding why or properly how to. There are few cases a person needs to deploy any code. Those reasons are: wanting custom branding; contributing as a developer to the codebase; deploying a private TURN server; or running VDO.Ninja without internet on a private LAN.
|
||||
|
||||
There may be misconceptions that deploying the website code will make the service faster; it will not. The service is video peer-to-peer based, so deploying webservers servers will not make it faster. Deploying a TURN server may help in some cases, although using a VPN, a cloud VM (for OBS), or disabling any symmetrical firewall will often provide a better end result than a private TURN server.
|
||||
|
||||
For those looking for a brand-free experience already with a different domain name, I offer https://rtc.ninja, and as well as other alternate domain names, such as:
|
||||
|
||||
- https://invite.cam (via URL obfuscation option)
|
||||
- https://ltt.ninja
|
||||
- https://rtc.ninja
|
||||
- https://vmix.ninja
|
||||
- https://auxiliary.live (backup hosted)
|
||||
- https://backup.vdo.ninja (fully backup hosted)
|
||||
|
||||
There is also an isolated version specificly designed for use in mainland China, hosted at https://insecure.cam in Hong Kong AWS.
|
||||
- https://rtc.ninja (de-branded version of vdo.ninja)
|
||||
|
||||
You can also point your domain to the VDO.Ninja IP address (provided on request), which will also rebrand the site automatically to match your domain name. (Requires Cloudflare as DNS server and proxy, Flexible SSL cert on, and HTTPs always on - all free.)
|
||||
|
||||
@ -25,7 +20,7 @@ For those wanting a private TURN server setup, you can load the settings for tho
|
||||
|
||||
VDO.Ninja also supports IFRAMES, so you can embed VDO.Ninja into your website and customize it via both URL parameters, but also via the IFRAME API. You can insert custom CSS styles with this method, giving VDO.Ninja quite a bit of flare.
|
||||
|
||||
See more on IFRAMES here: https://github.com/steveseguin/vdo.ninja/blob/master/IFRAME.md
|
||||
See more on IFRAMES here: https://docs.vdo.ninja/guides/iframe-api-documentation
|
||||
|
||||
Understanding clearly why you need to deploy any code or server is important. Maintaining updated deployed code can be quite hard, as VDO.Ninja updates frequently, so there are good reasons to consider an IFRAME approach instead. Feature requests there are welcomed.
|
||||
|
||||
@ -35,7 +30,7 @@ That all aside, please continue:
|
||||
|
||||
There's a community-created video tutorial on setting up here; https://youtu.be/8sDMwBIlgwE Otherwise, read on.
|
||||
|
||||
I use Cloudflare with Flexible SSL enabled and HTTP Rewrites. If you do not use Cloudflare, you will need to deploy SSL certificates onto your website. You will also have to have Cloudflare or whatever DNS provider you have, point your domain name to the IP address of your webserver. VDO.Ninja REQUIRES a domain name and SSL.
|
||||
I use Cloudflare with Flexible SSL enabled and HTTP Rewrites. If you do not use Cloudflare, you will need to deploy SSL certificates onto your website. You will also have to have Cloudflare or whatever DNS provider you have, point your domain name to the IP address of your webserver. VDO.Ninja REQUIRES a domain name and SSL, unless you modify all browsers being used to support otherwise. (More on this in the [Internet-free section](#internet-free-deployments) below)
|
||||
|
||||
For webservers, I use NGINX on a Ubuntu server; smaller the better. I rely on Cloudflare to provide caching and SSL, so my installation of NGINX is pretty simple.
|
||||
```
|
||||
@ -92,15 +87,30 @@ My suggestion? Limit changes to images and perhaps the translation files (maybe
|
||||
|
||||
### Internet-free deployments
|
||||
|
||||
For those looking to deploy a completely Internet-free or fully-isolated option, you'll need to deploy your own STUN services and a handshake server as well.
|
||||
For those looking to deploy a completely Internet-free or fully-isolated hosting option, you'll need to deploy your own handshake server, and you may also need to deploy your own STUN/TURN service. STUN/TURN might not be needed on a Local Area Network, and TURN might not be needed at all if you have control over each participant connecting, but adding one isn't too hard and can help with firewall and mobile network issues.
|
||||
|
||||
Details on how to deploy your own private STUN server can be Googled online; it's rather out of the scope of this guide's goals though. As of this writing, VDO.Ninja uses Google's public STUN servers, but most TURN-servers offers STUN server functionality as well; just takes some added configuration.
|
||||
As of this writing, VDO.Ninja uses Google's public STUN servers, but most TURN-servers also offer optional STUN server functionality as well. Details on deploying a TURN server are mentioned previously in this article, so following those instructions should suffice if you wish to have a combined STUN/TURN service.
|
||||
|
||||
Internet-free deployments will also need to deal with private SSL certificates and any DNS secure context issues that may arise. VDO.Ninja relies on SSL for security, but if you can't figure out how to do private SSL issuance, these SSL restrictions can be disabled via the Chrome browser's command-line. VDO.Ninja may complain about the lack of security if you take this approach though.
|
||||
Internet-free deployments will also need to deal with private SSL certificates and any DNS secure context issues that may arise. VDO.Ninja relies on SSL for security, but if you can't figure out how to do private SSL issuance, these SSL restrictions can be somewhat disabled at the browser's command-line or for localhost via the Chrome://flags settings. VDO.Ninja may complain about the lack of security if you take this approach though, but you can edit out those lines of code which trigger those warnings as needed. You may still need to issue an SSL certificate, self-signed or what not, but with these flags enabled it doesn't at least need to be valid.
|
||||
|
||||
Finally, there is an experimental handshake server option that lets advanced users use a basic/generic websocket service as a personal handshake server; useful for air-gapped private deployments of the service. A simple socket server has been developed that can be used as a personal handshake server. Documentation with installation instructions are included here: https://github.com/steveseguin/websocket_server
|
||||
Setting it via command line on Windows,
|
||||
```
|
||||
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --ignore-certificate-errors
|
||||
```
|
||||
and on macOS
|
||||
```
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --ignore-certificate-errors --ignore-urlfetcher-cert-requests &> /dev/null
|
||||
```
|
||||
and if you intend to only access it as a localhost,
|
||||
```
|
||||
chrome://flags/#allow-insecure-localhost
|
||||
```
|
||||
|
||||
Just on a side note, support for piesocket.com has also been added as a third-party handshake-server service option, which demonstrates and offers a cheap alternative to a managed hosted alternative of the official handshake service. If using piesocket, you can just do &pie=APKKEY to use that service, without deploying any code or servers yourself. The free tier is quite generous and I have no affiliation with them, but you'll need the Internet to make use of their service.
|
||||
Finally, there is a handshake server hosting option available; advanced users can host their own personal handshake server, which is useful for air-gapped private deployments of the service. Some basic documentation with instructions on setting it up are included here: https://github.com/steveseguin/websocket_server. Just be sure that your SSL-certifcates are valid or that you modify your browser to support invalid SSL certificates, else it will not work. From there, you just need to modify a couple ilnes in the index.html file of VDO.Ninja to configure things.
|
||||
|
||||
Please note that despite how simple the provided handshake server appears, it does work quite well. VDO.Ninja was designed to be as serverless and agnostic as possible, so it will work with 3rd-party signaling services as well, such as piesocket.com, and even certain blockchain networks, IRC, and more (with a bit of added tweaking at course).
|
||||
|
||||
WebRTC is very prickly about security, so if you run into issues with things not working, double check your SSL settings first.
|
||||
|
||||
Regards,
|
||||
Steve
|
||||
|
||||
27
lib.js
27
lib.js
@ -7725,7 +7725,7 @@ function outboundAudioPipeline() {
|
||||
|
||||
if (session.disableWebAudio) {
|
||||
//if (session.mobile){return session.streamSrc;} // iOS devices can't remap video tracks, else KABOOM. Might as well do this for android also.
|
||||
|
||||
|
||||
var newStream = createMediaStream();
|
||||
session.streamSrc.getAudioTracks().forEach(function(track) { // this seems to fix a bug with macbooks.
|
||||
newStream.addTrack(track, session.streamSrc);
|
||||
@ -12566,8 +12566,7 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
|
||||
});
|
||||
|
||||
updateRenderOutpipe();
|
||||
// senderAudioUpdate
|
||||
|
||||
|
||||
if (wasDisabled && !session.videoMuted){
|
||||
var msg = {};
|
||||
@ -12622,6 +12621,7 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
if (getUserMediaRequestID !== gumid) { // new camera selected in this time.
|
||||
return;
|
||||
}
|
||||
|
||||
makeImages(true);
|
||||
|
||||
if (getById("popupSelector_constraints_loading")) {
|
||||
@ -17255,22 +17255,11 @@ Promise.wait = function(ms) {
|
||||
Promise.prototype.timeout = function(ms) {
|
||||
return Promise.race([
|
||||
this, Promise.wait(ms).then(function() {
|
||||
if (iOS || iPad){
|
||||
var errormsg = new Error("Time Out\nDid you accept camera permissions in time? Please do so first.\n\nIf using an iPhone or iPad, try fully closing your browser and open it again; Safari sometimes jams up the camera.");
|
||||
errormsg.name = "timedOut";
|
||||
errormsg.message = "Time Out\nDid you accept camera permissions in time? Please do so first.\n\nIf using an iPhone or iPad, try fully closing your browser and open it again; Safari sometimes jams up the camera."
|
||||
throw errormsg;
|
||||
} else if (session.mobile){
|
||||
var errormsg = new Error("Time Out\nDid you accept camera permissions in time? Please do so first.\n\nMake sure no other application is using the camera already and that you are using a compatible browser. If issues persist, maybe try the official native mobile app.");
|
||||
errormsg.name = "timedOut";
|
||||
errormsg.message = "Time Out\nDid you accept camera permissions in time? Please do so first.\n\nMake sure no other application is using the camera already and that you are using a compatible browser. If issues persist, maybe try the official native mobile app."
|
||||
throw errormsg;
|
||||
} else {
|
||||
var errormsg = new Error("Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page.");
|
||||
errormsg.name = "timedOut";
|
||||
errormsg.message = "Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page."
|
||||
throw errormsg;
|
||||
}
|
||||
var errormsg = new Error("Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page.");
|
||||
errormsg.name = "timedOut";
|
||||
errormsg.message = "Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page."
|
||||
throw errormsg;
|
||||
|
||||
})
|
||||
])
|
||||
};
|
||||
|
||||
5
main.css
5
main.css
@ -15,8 +15,7 @@
|
||||
--color-mode: light;
|
||||
--button-radius: 2px;
|
||||
--myvideo-max-width: min(800px,100vw);
|
||||
--myvideo-width:unset;
|
||||
--myvideo-height:auto;
|
||||
--myvideo-width:800px;
|
||||
}
|
||||
|
||||
* {
|
||||
@ -1732,7 +1731,7 @@ img {
|
||||
width: var(--myvideo-width);
|
||||
max-width: 800px !important;
|
||||
max-height: 100% !important;
|
||||
height: var(--myvideo-height) !important;
|
||||
height: auto !important;
|
||||
display: block !important;
|
||||
margin: auto auto !important;
|
||||
position: relative !important;
|
||||
|
||||
20
main.js
20
main.js
@ -141,10 +141,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (urlParams.has('cleanoutput') || urlParams.has('clean') || urlParams.has('cleanish')) {
|
||||
session.cleanOutput = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('cleanviewer') || urlParams.has('cv')) {
|
||||
session.cleanViewer = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('retrytimeout')) {
|
||||
session.retryTimeout = parseInt(urlParams.get('retrytimeout'));
|
||||
@ -636,7 +632,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
document.documentElement.style.setProperty('--fit-style', 'cover');
|
||||
document.documentElement.style.setProperty('--myvideo-max-width', '100vw');
|
||||
document.documentElement.style.setProperty('--myvideo-width', '100vw');
|
||||
document.documentElement.style.setProperty('--myvideo-height', '100vh');
|
||||
}
|
||||
|
||||
if (urlParams.has('record')) {
|
||||
@ -874,10 +869,6 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
|
||||
if (urlParams.has('transparent') || urlParams.has('transparency')) { // sets the window to be transparent - useful for IFRAMES?
|
||||
session.transparent=true;
|
||||
}
|
||||
|
||||
if (session.transparent){
|
||||
getById("main").style.backgroundColor = "rgba(0,0,0,0)";
|
||||
document.documentElement.style.setProperty('--container-color', '#0000');
|
||||
document.documentElement.style.setProperty('--background-color', '#0000');
|
||||
@ -1300,6 +1291,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.micDelay = parseInt(session.micDelay) || 0;
|
||||
session.disableWebAudio = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (urlParams.has('tips')){
|
||||
getById("guestTips").style.display="flex";
|
||||
@ -1400,9 +1393,9 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
|
||||
//if (navigator.userAgent.indexOf('Mac OS X') != -1) {
|
||||
// session.codec = "h264"; // default the codec to h264 if OBS is on macOS (that's all it supports with hardware) // oct 2021, OBS now supports vp8 and actually breaks with h264 android devices.
|
||||
//}
|
||||
if (navigator.userAgent.indexOf('Mac OS X') != -1) {
|
||||
session.codec = "h264"; // default the codec to h264 if OBS is on macOS (that's all it supports with hardware)
|
||||
}
|
||||
|
||||
if (session.disableOBS===false){
|
||||
window.addEventListener("obsSourceVisibleChanged", obsSourceVisibleChanged);
|
||||
@ -2547,6 +2540,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((session.roomid) || (urlParams.has('roomid')) || (urlParams.has('r')) || (urlParams.has('room')) || (filename) || (session.permaid !== false)) {
|
||||
|
||||
var roomid = "";
|
||||
@ -3478,6 +3472,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
getById("gridlayout").appendChild(session.rpcs[i].videoElement);
|
||||
} catch(e){warnlog(e);}
|
||||
|
||||
|
||||
} else if ("remove" in e.data) {
|
||||
try {
|
||||
session.rpcs[i].videoElement.parentNode.removeChild(session.rpcs[i].videoElement);
|
||||
@ -3601,6 +3596,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
midiHotkeysNote(note,velocity);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}).catch(errorlog);
|
||||
};
|
||||
|
||||
@ -440,4 +440,4 @@
|
||||
"transferred": "Transferred",
|
||||
"room-changed": "Your room has changed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user