Streaming server - intentions and ideas

hello again scanlines humans ! i’ve finally had a bit of time to start thinking about ideas for how we can do some streams on here.

there’s been some talk about setting up a streaming server, in this previous thread: Streaming event? and in the chat i’ve passed along some info from our friends at Resonant Frequencies about their streaming server setup.

in order to move forward with setting up our own, i wanted to clarify what we actually want to use it for. my idea for the “streamlines” series is to have a once a month event where each month, 1 artist does a live a/v stream, that gets embedded in the header of this site. if the person who does the stream wants to involve multiple collaborators, they can handle all that on their end - they just send the final stream to our server via OBS.

i think that having just 1 artist per edition simplifies a lot of things. for each one, we can rotate between different community members who want to present things, or bring new people in, and for that edition, they are the spotlight. the alternative would be multi-person shows, which i can give a long list of reasons why i don’t really want to go there (at least for now). but again, if the person featured that month wants to bring more people in, they can totally coordinate that on their end. i also would like to keep to a flexible schedule, allowing individual people to decide the date and time each month.

for that purpose, i think the setup @v3d described would work just fine. basically just a simple streaming relay, running on its own digitalocean droplet. then each month we just give whoever’s doing it the info to set it up in OBS. i can create a theme component with the stream embedded so we can easily enable and disable it for an event. i haven’t worked with HTTP streams before but from what i’ve seen it seems pretty simple on the embedding side - i already made one with the embed from twitch, so i can probably just modify it. and then our normal chat can be a place for conversation during any streams - like the sidebar chat in twitch.

i also was planning to host a live stream event of my own at some point, probably next month, so it would be really cool if i could use the same server to do this and embed it on my own site. perhaps we could also offer the same to other community members if they want.

i also really enjoy making posters so i would love to do that for this series! then those could be shared around the web and hopefully bring more people in.

please let me know if anyone wants to help with the streaming server setup, or if you have any ideas or opinions about how it should work and what i’ve described above. also let me know if anyone wants to do a performance one month! i’d like to do one at some point, and i also have lots of friends who do awesome stuff that i could invite. very excited about this! :slight_smile:

cc: @cyberboy666 @autr

2 Likes

All of this sounds awesome. I want to help!

It looks like you know your way around setting up GNU/Linux so maybe the best way to do it is just ask if you get stuck somewhere. Maybe document the process here?

1 Like

id be down and try and set up another giant feedback stream chain again over here, would be dank to have a chat room that didnt crash for everyone constantly like the first time

2 Likes

@palomakop this all sounds great ! yes super keen to help set this up / document it.

:+1: for letting the artist decide / setup their show - also keeps things simpler from a technical side. and yeap if anone here want to also use the server for doing their own streaming shows sounds good to me.

(also yay for posters !)

it is kind of a different topic but maybe related - a few people have expressed interest in doing a more informal / intimate type event here too (i guess the hangs part from streams&hangs -> pending a catchy name like streamlines :sweat_smile: ) , something like a jitsi show&tell, where we agree on a time (recurring or just sporadically ), and spin something up maybe ? - same idea tho to embed on the homepage, and could run on the same server probably with some overlap in setup etc. anyway just mentioning in case it makes sense to consider this while experimenting with the tech stuff

1 Like

i can assure you our new chatroom is the pinnacle of performance and stability :sweat_smile: :sweat_smile:

1 Like

Ayo! I was going to suggest an ad-hoc Jitsi meet first if we want to plan this out (I find mouth noises more efficient at organising complicated things).

I would be up for doing a performance as Autr so count me in. I was also tentatively thinking another Video Circuits Berlin Global could be in order. The way we do this is just a timetable of talks and presentations, with questions at the end. So maybe we could start by doing this with just denizens of the board, then later organise a “proper” one (essentially the threshold between Jitsi and a organised live stream).

For tech stack, the Resonant Frequencies approach (link :link:) seems really sensible and most importantly, tried and tested.

A simplified explainer would be to not think of a server as any different to a computer, and that it is just like opening multiple video and audio inputs, compositing them together in a VJ program (in this case OBS), before sending the output to Youtube / Twitch for distribution (because too many people trying to grab this output would overwhelm the computer). They are also doing some smart things for sending music and video-only streams for reference by the performers (where as it’s private, also doesn’t overwhelm).

In terms of tools, I’m reminded that I checked the box to be hooked up as a static IP (my apartment is finally getting connected this Thursday :sparkles::globe_with_meridians::sparkles:). This means we might not need to pay for a cloud machine, and we use a machine here: either a desktop or Raspberry Pi. The 3B might be a push, but I reckon a 4 could definitely handle it. The only unknown would be: how well can a Berlin internet connection handle the incoming streams and the output streams at the same time? Something to test out, for sure.

For the embeddable stream, I’m guessing this is a Youtube / Twitch embed? The benefit here is that those services also handle automatic transcoding of the finished stream into video that can be played back, but also come with some logo-and-tracking caveats. Something we could look into is doing the distribution via an enterprise service (AWS, IBM etc) - the free credits they dole out for new customers might be enough to run a fair few streams (just be sure to cancel the account before they run out!). Bit more difficult though.

1 Like

@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