Streaming server - intentions and ideas

@andrei_jay for a mega-global-feedback-loop I think Jitsi would be perfect! In another project we’re currently messing with the jitsi-meet application to allow us to manipulate streams with canvas / P5. To do feedback I think you would only need to add in the option to set one incoming video as full-screen with no UI overlays - and then make sure each person is locked into the next person in the chain and so on. There is also webcamoid for virtual webcams on mac, and OBS seems to have cross-platform virtual webcam support.

1 Like

thank you for all the input everyone!

i’m liking all of these ideas! it seems like we could use the simple cloud server as a relay to serve HTTP streams for embedding (since it has plenty of outgoing bandwidth available), and that would be a nice way to embed the stream without any third party players. as for setting things up with Jitsi or OBS, that could be done using servers or machines at one of our houses - then we would send the final output to the cloud server to serve publicly.
so basically, the cloud server would replace twitch or youtube, with the relay setup on there remaining as-is for all kinds of events, while the rest could happen on local machines and be re-configured as needed.

so, it seems like setting up the cloud machine with nginx as per Vedran’s instructions will be a good place to start our experiments. it seems like we will have some time this week to get things rolling, and we will definitely let you know if we get stuck @v3d, much appreciated! and i’d like to get the process documented as we go too.

i think it would be cool to use our embedding / HTTP stream output for show-and-tell style chat events as well, to allow more people to watch without them all needing to join the video conference. and more potential giant feedback loops as well!

2 Likes

This will help. It’s two frankenfiles from online tutorials. nginx.conf is the general nginx conf file and default is the site itself. It works on an 18.04 Ubuntu server. Mind the perms for the directory to store HLS in - it creates a bunch of little files and an m3u8 playlist for them. HLS is needed because HTML5 won’t work with regular rtmp (wihtout Flash).

It also has some stuff to transcode to lower quality video for mobile - I don+'t think we need this (or that it actually works for that matter) =D.

Also you need to install nginx, libnginx-mod-rtmp and nginx-extras on Ubuntu 18.04 (package names may differ, libnginx-mod-rtmp might requre compiling manually depending on distro used).

nginx.conf

user www-data;
worker_processes 1;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
	worker_connections 768;
	# multi_accept on;
}

http {
	sendfile off;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;

	gzip on;

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}


rtmp {
        server {
                listen 1935;
                chunk_size 8192;

                application live {
                        live on;
			interleave off;
			meta on;
			wait_key on;
			wait_video on;
			idle_streams off;
			sync 300ms;
			session_relay on;
			allow publish all;
			# deny publish all;
				# disable consuming the stream from nginx as rtmp #
				# deny play all;
			allow play all;
			#respawn on;
			#respawn_timeout 10s;
			# drop_idle_publisher 60s;
			
			## == RECORDING OPTIONS: OFF/ALL == ##
			# default recorder #
			record off;
			record_suffix all-%d-%b-%y-%T.flv;
			record_path /var/www/recordings;
			record_max_size 4096M;
			record_unique on;
			record_append off;
			record_lock on;

			## == FORWARD STREAM (OPTIONAL) == ##
			# == == TWITCH RE-STREAM == == #
			# push rtmp://live-ams.twitch.tv/app/LIVESTREAM_KEY;
			# == == YOUTUBE RE-STREAM == == #
			# push rtmp://a.rtmp.youtube.com/live2/LIVESTREAM_KEY;
			# == == MIXER.com RE-STREAM == == #
			# push rtmp://ingest-ams.mixer.com:1935/beam/LIVESTREAM_KEY;

			publish_notify off;
			# play_restart off;
			# on_publish http://your-website/on_publish.php;
			# on_play http://your-website/on_play.php;
			# on_record_done http://your-website/on_record_done.php;
			
			## == HLS == ##
			hls on;
			hls_nested on;
			hls_path /var/www/hls/live;
			# hls_base_url http://abc.de:1953/hls;
		#	hls_playlist_length 60s;
		#	hls_fragment 10s;
			hls_sync 100ms;
			hls_cleanup off;
			hls_fragment 10s;
	                hls_playlist_length 60s;

			## == DASH == ##
			dash on;
			dash_nested on;
			dash_path /var/www/dash;
			dash_fragment 10s;
			dash_playlist_length 60s;
			dash_cleanup on;

			# == creates the downsampled or "trans-rated" mobile video stream as a 400kbps, re-sized video == #
			# exec ffmpeg -i rtmp://localhost/$app/$name -acodec copy -c:v libx264 -preset veryfast -profile:v baseline -vsync cfr -vf scale=-2:360,setdar=16:9 -b:v 400k -bufsize 400k -threads 0 -r 30 -f flv rtmp://localhost/low/${name};

			# https://selimatmaca.com/index.php/live-streaming/165-adaptive-bitrate-streaming-with-nginx-and-videojs #
			}

#		application liveout {
#			live on;
#			hls on;
#			hls_path /var/www/hls/liveout;
#			hls_fragment 10s;
#			hls_playlist_length 60s;
#			allow play all;
#			allow publish 127.0.0.1;
#			allow publish 192.168.2.88;
#			allow publish 192.168.2.0/24;
#			deny publish all;

#			# hls_variant _240 BANDWIDTH=288000;            
#			hls_variant _360 BANDWIDTH=448000;
#			hls_variant _480 BANDWIDTH=1152000;
#			hls_variant _720  BANDWIDTH=2048000;
#			# hls_variant _1080 BANDWIDTH=4096000; 
#			}

		application hls {
			live on;
			allow play all;
			hls on;
			hls_path /var/www/hls;
			hls_fragment 10s;
			hls_playlist_length 60s;
			}

                # Creates "mobile" lower-res HLS videostream from ffmpeg-created stream and where to put the manifest and video fragments #
                application low {
			live on;
			allow play all;
			hls on;
			hls_nested on;
			hls_path /var/www/hls/low;
			hls_fragment 10s;
			hls_playlist_length 1s;
			}

		# application ipcam {
		#	live on;
		#	exec_pull ffmpeg -i rtsp://192.168.4.250:554/h264.sdp -c copy -f flv rtmp://localhost/ipcam/h264;
		#	exec_pull ffmpeg -i rtsp://192.168.4.250:554/mjpeg.sdp -c copy -f flv rtmp://localhost/ipcam/mjpeg;
		#	}

		# Allows playing earlier recorded files #
#		application vod {
#			play /var/www/recordings;
#			allow play all;
#			}
#		application vod_http {
#			play http://yourserver.ddns.net/recordings;
#			allow play all;
#			}
#		application vod_mirror {
#			# try local location first, then access remote location
#			play /var/www/recordings http://yourserver.ddns.net/vods;
#			}
	}
}

default site

##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 8080 ssl;
	# listen [::]:80 default_server;
	ssl_certificate /etc/letsencrypt/live/formatc.hr/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/formatc.hr/privkey.pem;

	# listen 4438 ssl default_server;
	# listen [::]:4438 ssl default_server;
	# include snippets/snakeoil.conf;

	# ssl_certificate /etc/letsencrypt/live/yourserver.ddns.net/fullchain.pem; # managed by Certbot
	# ssl_certificate_key /etc/letsencrypt/live/yourserver.ddns.net/privkey.pem; # managed by Certbot

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.nginx-debian.html index.html index.htm;

	server_name _;

	location / {
		root /var/www/html;
		index index.nginx-debian.html index.html index.htm;
		# First attempt to serve request as file, then as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
		#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass 127.0.0.1:9000;
	#}

	#error_page   500 502 503 504  /50x.html;
	#location = /50x.html {
	#	root   /var/www/html;
	#}

	location ~ /\.ht {
		deny all;
	}

#location ~	\.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv|mpd|m3u8)$ {
#	expires 7d;
#	access_log off;
#	log_not_found off;
#	}
#location ~ \.(?:svgz?|ttf|ttc|otf|eot|woff|woff2)$ {
#	add_header Access-Control-Allow-Origin "*";
#	expires 7d;
#	access_log off;
#	}

# This provides RTMP statistics in XML at http://your-server-address/stat
location /stat {
	rtmp_stat all;
	rtmp_stat_stylesheet stat.xsl;
	auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
	}
# XML stylesheet to view RTMP stats. Copy stat.xsl wherever you want and put the full directory path here
location /stat.xsl {
	root /var/www/html/;
	}
# Control interface (extremely useful, but can also boot people from streams so we put basic auth in front of it - see https://github.com/arut/nginx-rtmp-module/wiki/Control-module for more information)
# location /control {
#	# you'll need a htpasswd auth file, that's outside the scope of this doc but any apache one will work
#	auth_basic "stream";
#	auth_basic_user_file /etc/nginx/.htpasswd;
#	rtmp_control all;
#	}

# allows us to see how stats on viewers on our Nginx site using a URL like: "http://my-ip/stats" 
# location /stub_status {
#		stub_status;
#		allow 127.0.0.1;
#		deny all;
#                }
#creates the http-location for our full-resolution (desktop) HLS stream - "http://my-ip/live/my-stream-key/index.m3u8"

# ========================================== RTMP =================================== # 
location /live {
	# root /var/www/;
	alias /var/www/hls/live;
	expires -1;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header 'Cache-Control' 'no-cache';
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		}
	}

location /hls {
	root /var/www;
	# alias /var/www/hls;
	expires -1;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		}
	}
# mpeg-dash for HTML5, HTTP side. nginx stores DASH fragments here, so make sure it's writable by nginx
location /dash {
	# root /var/www;
	alias /var/www/dash;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/x-mpegURL m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		video/mp4 mp4;
		}
	}	
# creates the http-location for our mobile-device HLS stream - "http://my-ip/low/my-stream-key/index.m3u8"
location /low {
	# root /var/www/hls;
	alias /var/www/hls/low;
	expires -1;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		video/mp4 mp4;
		}
	}

location /recordings {
	alias /var/www/recordings/;
	# root /var/www/recordings;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		video/mp4 mp4;
		}
	}
}
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 8080 ssl;
	# listen [::]:80 default_server;
	ssl_certificate /etc/letsencrypt/live/formatc.hr/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/formatc.hr/privkey.pem;

	# listen 4438 ssl default_server;
	# listen [::]:4438 ssl default_server;
	# include snippets/snakeoil.conf;

	# ssl_certificate /etc/letsencrypt/live/yourserver.ddns.net/fullchain.pem; # managed by Certbot
	# ssl_certificate_key /etc/letsencrypt/live/yourserver.ddns.net/privkey.pem; # managed by Certbot

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.nginx-debian.html index.html index.htm;

	server_name _;

	location / {
		root /var/www/html;
		index index.nginx-debian.html index.html index.htm;
		# First attempt to serve request as file, then as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
		#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass 127.0.0.1:9000;
	#}

	#error_page   500 502 503 504  /50x.html;
	#location = /50x.html {
	#	root   /var/www/html;
	#}

	location ~ /\.ht {
		deny all;
	}

#location ~	\.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv|mpd|m3u8)$ {
#	expires 7d;
#	access_log off;
#	log_not_found off;
#	}
#location ~ \.(?:svgz?|ttf|ttc|otf|eot|woff|woff2)$ {
#	add_header Access-Control-Allow-Origin "*";
#	expires 7d;
#	access_log off;
#	}

# This provides RTMP statistics in XML at http://your-server-address/stat
location /stat {
	rtmp_stat all;
	rtmp_stat_stylesheet stat.xsl;
	auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
	}
# XML stylesheet to view RTMP stats. Copy stat.xsl wherever you want and put the full directory path here
location /stat.xsl {
	root /var/www/html/;
	}
# Control interface (extremely useful, but can also boot people from streams so we put basic auth in front of it - see https://github.com/arut/nginx-rtmp-module/wiki/Control-module for more information)
# location /control {
#	# you'll need a htpasswd auth file, that's outside the scope of this doc but any apache one will work
#	auth_basic "stream";
#	auth_basic_user_file /etc/nginx/.htpasswd;
#	rtmp_control all;
#	}

# allows us to see how stats on viewers on our Nginx site using a URL like: "http://my-ip/stats" 
# location /stub_status {
#		stub_status;
#		allow 127.0.0.1;
#		deny all;
#                }
#creates the http-location for our full-resolution (desktop) HLS stream - "http://my-ip/live/my-stream-key/index.m3u8"

# ========================================== RTMP =================================== # 
location /live {
	# root /var/www/;
	alias /var/www/hls/live;
	expires -1;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header 'Cache-Control' 'no-cache';
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		}
	}

location /hls {
	root /var/www;
	# alias /var/www/hls;
	expires -1;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		}
	}
# mpeg-dash for HTML5, HTTP side. nginx stores DASH fragments here, so make sure it's writable by nginx
location /dash {
	# root /var/www;
	alias /var/www/dash;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/x-mpegURL m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		video/mp4 mp4;
		}
	}	
# creates the http-location for our mobile-device HLS stream - "http://my-ip/low/my-stream-key/index.m3u8"
location /low {
	# root /var/www/hls;
	alias /var/www/hls/low;
	expires -1;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		video/mp4 mp4;
		}
	}

location /recordings {
	alias /var/www/recordings/;
	# root /var/www/recordings;
	autoindex on;
	autoindex_localtime on;
	# CORS setup #
		set $sent_http_accept_ranges bytes;
		add_header Cache-Control no-cache;
		add_header 'Access-Control-Allow-Origin' '*' always;
		add_header 'Access-Control-Expose-Headers' 'Content-Length';
	# allow CORS preflight requests #
		if ($request_method = 'OPTIONS') {
		add_header 'Access-Control-Allow-Origin' '*';
		add_header 'Access-Control-Max-Age' 1728000;
		add_header 'Content-Type' 'text/plain charset=UTF-8';
		add_header 'Content-Length' 0;
		return 204;
		}
	types {
		application/vnd.apple.mpegurl m3u8;
		application/dash+xml mpd;
		video/mp2t ts;
		video/mp4 mp4;
		}
	}
}
1 Like

streaming server setup is successfully underway! nginx with the RTMP module is serving an HLS stream over an https connection from the chat.scanlines.xyz server! next steps: testing with embedding & different quality levels, documenting, & finally, organizing some streams!

some historical inspiration:

and a fun glitch we encountered:

3 Likes

here is some documentation from the streaming setup @palomakop and i started last night.

it is just getting the basics working on our existing server. looks like there is a lot of interesting additional configuration/options in the file @v3d linked and elsewhere → looking forward to exploring these some more, but for now happy to have something working !

onwards…

2 Likes

thank you for putting together the doc! i’m also going to have to re watch this movie now …

Ooh amazing! I read through the technical doc and I was looking into how to display the stream … is the idea to display the stream inside the forum? Or somewhere else?

It seems like modern browsers support hls and MPEG-DASH natively with a video tag… would be fun to try that way:

that looks cool! right now, the somewhat tenuous plan is to create an embed for this site using video.js, though right now we are just testing by viewing the stream in VLC to experiment with quality settings.

@andrei_jay and i did some tests on the streaming server with good results. andrei sent a stream of 1280*720 at 30FPS, about 6Mb/s, and i was able to view it from my end with no problemo even on my crappy internet. 6Mb/s is the OBS default apparently but i think a safer baseline would be like 4Mb/s. sound also came though fine in both tests!

i started building a little player using video.js but haven’t gotten very far yet, will keep going on that when i have more time. i am very excited with how this is coming along so far!

oh yeah, and another question i had that @cyberboy666 might know more about. right now it seems like the stream key will determine where the stream gets sent out - there’s no chance of it being able to support more than one stream at a time with different keys right? just something i was wondering about.

2 Likes

ooh dope ! happy to help with the videoplayer stuff if i can, just hmu where you at.

i didnt come across any mention specifically of multiple streams but i cant really see why it wouldnt work. i think would be worth giving it a try !

1 Like

somethin else we should probably test at some point too is international effects on streaming, any cross continental streaming thing ive done before has run into some issues with bandwidth chokepoints between various countries and continents

1 Like

hello again! so i’ve created an embedded stream player with video.js. when you turn it on (in the admin settings), the player shows up at the top of the forum. with the help of andrei’s stream (again) we were able to test it out and it seems to be working on the desktop, and at least some mobile devices !

i was able to get the styling pretty close to how i wanted it, and it is able to go fullscreen. if there is no stream happening at the URL it’s pointing to, it displays an error message, so we probably only want to turn it on while we are actively streaming (and start streaming early with a “please wait” image or video loop displayed for people who open the page early).

the only sort of annoying thing about the theme component aspect is that, if someone already has the page open when you turn it on, they will need to refresh in order to see it. when you navigate around the forum it doesn’t actually refresh the page since it’s all in rails, so you need to literally refresh the browser. a simple workaround might be to create a pinned banner post announcing the stream, and a little info like the note to refresh if you don’t see it and a note about joining the chat, and a link to the event poster/info. banner posts show up right away without any refresh and they can be dismissed.
(it’s hard to decide how much of an issue this would really be, i welcome any advice)

very excited about this progress so far! i think a good next step would be to do a little informal stream sesh amongst ourselves to test more and try things out! let me know what you think about all this and if anyone has any more ideas or suggestions!

also here is the best CSS mistake i’ve made in a while - it was hard to fix because it messed up the CSS text editor itself :sweat_smile:

3 Likes

OH! also! i started talking to some of the people who have been involved with telepresence about doing telepresence virtually this year (the name is already appropriate). this would entail collaborative sets between musicians and visualists, and be streamed to twitch, so we would probably do something very similar to the Resonant Frequencies setup. this would probably be some time in the fall. just giving a heads up here as well because i feel there will likely be an overlap between these groups (beyond just myself!) and maybe we could use the same setup for events on here as well if we want. we can also open it up to a wider group geographically than we could with a physical event which is exciting.

:heart: :heart: :laughing: :laughing:

i think using a pinned banner post for a performance is a good idea anyway to have some info like you say , so dont see any problem there. looks super dope - love it! i will take a look into the css stuff to update my documentation of this process. is there any steps that are not obvious by poking around @palomakop ?

re telepresence, i would love to help with this , and to help w setting up the collaborative streams… before all the lockdowns started i was talking to a few people about the idea of doing some kind of event in the same vein as telepresence for people here in central europe - was interested in getting some insights from you guys anyway , so yah im keen

and re international stream tests… yah lemme know next you are testing @andrei_jay will see how it is from here. can also ask my brother to check it from new zealand too if you like :sweat_smile:

1 Like

thanks for your input and documentation! the only note that wasn’t obvious from the code is that discourse’s css has a max height of 500px for <video> tags, so it took me a while to figure out why the video wasn’t taking up the whole screen when it was in full screen mode, before i found that and overrode it.
also, not sure how much of a demand there is for such a thing, but i could make a templatized version of the theme component and put it up on github at some point. you can add components from github repos in discourse and include variables (like for the stream key and server address) which is nifty.

it would be awesome to have you on board for the télépresence/OBS server project! i will let you know when i am going to get started on that. will probably create it on separate architecture, but we could easily point its output to our existing server instead of twitch.

and i agree it would definitely be good to have some people stream from overseas in our next tests!

Hi! Recently I have been looking at this: GitHub - Novage/p2p-media-loader: An open-source engine for P2P streaming of live and on demand video directly in a web browser HTML page as a way to display live streams (HLS and Dash) in a p2p viewer. I am pretty sure this is the same player that PeerTube uses under the hood (based on WebTorrent), and it is compatible with a lot of frontend libraries like video.js and clappa.
My hope is that it could allow scaling of live streams to a large audience without extra server load. I am trying it out this week with an RTMP server and will post progress / repo if I get anywhere :slight_smile:

4 Likes

that sounds very cool!

sounds cool ! def keen to hear how it goes. my gut feeling was that p2p live streaming just wouldnt be that efficient (unless you introduce a super long lag) but happy to be proven wrong.

i will also be updating the videos.scanlines instance here shortly (stabler release with stream features is out in january) so we can try p2p streaming through that too :smiley:

2 Likes

So update, I followed @cyberboy666’s really great instructions at scanlines-technical-details/streaming-setup.md at master · cyberboy666/scanlines-technical-details · GitHub to set up nginx-rtmp on digital ocean, and then tried it with a basic video player and also a p2p player. It is amazingly easy to set up the p2p player, as it just uses client-side code and publicly hosted bit-torrent trackers. Here is the code for the p2p version: Glitch :・゚✧

and the regular hls player: Glitch :・゚✧

I noticed that the p2p version seems to have more stops and starts compared to the regular version, but I am also on a really terrible internet connection and have not yet played with any different parameters. It seems like what it does is for each chuck of stream, it tries to download it from a connected peer. If it cannot download by the time it is time to play that chunk, it downloads from the server. I want to learn more about how the chunking works, and also do more comparisons between the two versions.

1 Like

I think peerTube is using this same player for the streaming, but not 100% sure :slight_smile:

1 Like