Skip to content

Commit

Permalink
Streaming control for recording locally and streaming to LAN (#149)
Browse files Browse the repository at this point in the history
* First commit for streaming to LAN

Some considerations
- This will need SLS installed. Will provide our own configuration.
- Currently uses FFmpeg with hardcoded values as explained in #44
discussion.

To test from the repo, copy `./config/sls.conf` to
`~/.local/share/steam-buddy/settings/sls.conf` and start steam-buddy:
```
$ ./steam-buddy

```
Then after logging in into steam-buddy got to the url:
`[steam-buddy-url]/streaming/net/start` to start streaming, and
`[steam-buddy-url]/streaming/net/stop` to stop.

To consume the stream you can do:
```
$ ffplay -fflags nobuffer -i "srt://[steam-buddy-url]:8080?streamid=live.gameros/live/stream"

```

* Allow for local recording

To start: `[steam-buddy-ip]/record/start`
To stop: `[steam-buddy-ip]/record/stop`

* FFmpeg command change to array for readability

Still need the join/split dance so we can work with ACODEC_OPTIONS and
VCODEC_OPTIONS

Co-authored-by: alkazar <[email protected]>
  • Loading branch information
Samsagax and alkazar authored May 19, 2021
1 parent afd168b commit eafb185
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 1 deletion.
26 changes: 26 additions & 0 deletions config/sls.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
srt { #SRT
worker_threads 1;
worker_connections 300 ;

log_file logs/error.log ;
log_level info;

record_hls_path_prefix /tmp/mov/sls;

server {
listen 8080;
latency 20; #ms

domain_player live.gameros ;
domain_publisher uplive.gameros;
backlog 100; #accept connections at the same time
idle_streams_timeout 10;#s -1: unlimited
app {
app_player live ;
app_publisher live ;

record_hls off;#on, off
record_hls_segment_duration 10; #unit s
}
}
}
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
('share/steam-buddy/public', glob('public/*.js')),
('share/steam-buddy/public', glob('public/*.css')),
('share/steam-buddy/config', glob('config/*.cfg')),
('share/steam-buddy/config', glob('config/*.conf')),
('share/steam-buddy/bin', glob('bin/*')),
('bin', glob('launchers/*')),
('share/doc/steam-buddy', ['README.md']),
Expand Down
3 changes: 3 additions & 0 deletions steam_buddy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from steam_buddy.authenticator import Authenticator, generate_password
from steam_buddy.ssh_keys import SSHKeys
from steam_buddy.steamgrid.steamgrid import Steamgrid
from steam_buddy.streaming import StreamServer
from steam_buddy.mangohud_config import MangoHudConfig

DATA_DIR = os.getenv('XDG_DATA_HOME', os.path.expanduser('~/.local/share'))
Expand Down Expand Up @@ -80,4 +81,6 @@

STEAMGRID_HANDLER = Steamgrid("f092e3045f4f041c4bf8a9db2cb8c25c")

STREAMING_HANDLER = StreamServer(SETTINGS_DIR + "/sls.conf")

MANGOHUD_HANDLER = MangoHudConfig(MANGOHUD_DIR)
30 changes: 29 additions & 1 deletion steam_buddy/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import unicodedata
from bottle import app, route, template, static_file, redirect, abort, request, response
from beaker.middleware import SessionMiddleware
from steam_buddy.config import PLATFORMS, SSH_KEY_HANDLER, AUTHENTICATOR, SETTINGS_HANDLER, STEAMGRID_HANDLER, FTP_SERVER, RESOURCE_DIR, BANNER_DIR, CONTENT_DIR, SHORTCUT_DIR, UPLOADS_DIR, SESSION_OPTIONS, MANGOHUD_HANDLER
from steam_buddy.config import PLATFORMS, SSH_KEY_HANDLER, AUTHENTICATOR, SETTINGS_HANDLER, STEAMGRID_HANDLER, FTP_SERVER, RESOURCE_DIR, BANNER_DIR, CONTENT_DIR, SHORTCUT_DIR, UPLOADS_DIR, SESSION_OPTIONS, STREAMING_HANDLER, MANGOHUD_HANDLER
from steam_buddy.functions import load_shortcuts, sanitize, upsert_file, delete_file, generate_banner
from steam_buddy.auth_decorator import authenticate
from steam_buddy.platforms.epic_store import EpicStore
Expand Down Expand Up @@ -500,6 +500,34 @@ def mangohud():
redirect('/')


@route('/streaming/net/start')
@authenticate
def streaming_net_start():
STREAMING_HANDLER.stream_to_lan()
redirect('/')


@route('/streaming/net/stop')
@authenticate
def streaming_stop():
STREAMING_HANDLER.stop_stream()
redirect('/')


@route('/record/start')
@authenticate
def record_start():
STREAMING_HANDLER.record_screen()
redirect('/')


@route('/record/stop')
@authenticate
def record_stop():
STREAMING_HANDLER.stop_record()
redirect('/')


@route('/mangohud/save_config', method='POST')
@authenticate
def mangohud_save_config():
Expand Down
81 changes: 81 additions & 0 deletions steam_buddy/streaming.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import os
import shlex
import time
import subprocess as sp


class StreamServer:

def __init__(self, sls_conf_file):
self.sls_conf_file = sls_conf_file
self._sls = None
self._ffmpeg = None

def __generate_sls_conf(self):
pass

def __start_sls(self):
if self._sls is None:
self._sls = sp.Popen(['sls', '-c', self.sls_conf_file])
else:
raise(Exception("Error starting SLS: Already started"))

def __stop_sls(self):
self._sls.terminate()
try:
self._sls.wait(5)
except sp.TimeoutExpired:
self._sls.kill()
self._sls = None

def __start_ffmpeg(self, local=False):
VCODEC = "libx264"
VCODEC_OPTIONS = "-preset ultrafast -tune zerolatency"
VSIZE = "1920x1080"
ACODEC = "libmp3lame"
ACODEC_OPTIONS = ""
FPS = "60"

if local:
STREAM = "screen_" + \
str(time.strftime("%Y%m%d_%H%M%S")) + \
".mp4"
else:
STREAM = '"srt://localhost:8080?streamid=uplive.gameros/live/stream"'

cmd = ["ffmpeg",
"-f x11grab -framerate", FPS, "-i :0",
"-f alsa -ac 2 -i pulse",
"-vcodec", VCODEC, VCODEC_OPTIONS,
"-acodec", ACODEC, ACODEC_OPTIONS,
"-video_size", VSIZE,
"-flush_packets 0",
"-f mpegts",
STREAM]
args = shlex.split(" ".join(cmd))
if self._ffmpeg is None:
self._ffmpeg = sp.Popen(args, cwd=os.path.expanduser("~"))
else:
raise(Exception("Error starting FFMpeg: Already started"))

def __stop_ffmpeg(self):
self._ffmpeg.terminate()
try:
self._ffmpeg.wait(5)
except sp.TimeoutExpired:
self._ffmpeg.kill()
self._ffmpeg = None

def stream_to_lan(self):
self.__start_sls()
self.__start_ffmpeg()

def stop_stream(self):
self.__stop_ffmpeg()
self.__stop_sls()

def record_screen(self):
self.__start_ffmpeg(local=True)

def stop_record(self):
self.__stop_ffmpeg()

0 comments on commit eafb185

Please sign in to comment.