diff --git a/config/sls.conf b/config/sls.conf new file mode 100644 index 00000000..638543c3 --- /dev/null +++ b/config/sls.conf @@ -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 + } + } +} diff --git a/setup.py b/setup.py index 0f164800..33ae9e75 100644 --- a/setup.py +++ b/setup.py @@ -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']), diff --git a/steam_buddy/config.py b/steam_buddy/config.py index eb1e62f1..016a69ae 100644 --- a/steam_buddy/config.py +++ b/steam_buddy/config.py @@ -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 DATA_DIR = os.getenv('XDG_DATA_HOME', os.path.expanduser('~/.local/share')) CONFIG_DIR = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) @@ -77,3 +78,5 @@ SSH_KEY_HANDLER = SSHKeys(os.path.expanduser('~/.ssh/authorized_keys')) STEAMGRID_HANDLER = Steamgrid("f092e3045f4f041c4bf8a9db2cb8c25c") + +STREAMING_HANDLER = StreamServer(SETTINGS_DIR + "/sls.conf") diff --git a/steam_buddy/server.py b/steam_buddy/server.py index d9ea2e29..f261b875 100644 --- a/steam_buddy/server.py +++ b/steam_buddy/server.py @@ -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 +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 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 @@ -491,6 +491,21 @@ def mangohud(): finally: 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('/') + + def retroarch_cmd(msg): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.sendto(bytes(msg, "utf-8"), ('127.0.0.1', 55355)) diff --git a/steam_buddy/streaming.py b/steam_buddy/streaming.py new file mode 100644 index 00000000..aff8fdb8 --- /dev/null +++ b/steam_buddy/streaming.py @@ -0,0 +1,76 @@ +import os +import shlex +import datetime as dt +import subprocess as sp + + +class StreamServer: + + def __init__(self, sls_conf_file): + self.sls_conf_file = sls_conf_file + self._ffmpeg_cmd = "ffmpeg" + self._sls_cmd = "sls" + 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([self._sls_cmd, '-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): + command_line = "" + VCODEC = "libx264" + VCODEC_OPTIONS = "-preset ultrafast -tune zerolatency" + VSIZE = "1920x1080" + ACODEC = "libmp3lame" + ACODEC_OPTIONS = "" + FPS = "60" + + if local: + STREAM = "~/screen" + dt.datetime.now() +".mp4" + else: + STREAM = '"srt://localhost:8080?streamid=uplive.gameros/live/stream"' + + command_line = self._ffmpeg_cmd + " " + \ + "-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(command_line) + if self._ffmpeg is None: + self._ffmpeg = sp.Popen(args) + 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()