updated to ubuntu 26
This commit is contained in:
parent
d8d2518924
commit
5a191cc425
21
Dockerfile
21
Dockerfile
@ -1,12 +1,9 @@
|
|||||||
FROM ubuntu:22.04
|
FROM ubuntu:26.04
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
# Install unzip first so we can extract the large static zips
|
# Install unzip first so we can extract the large static zips
|
||||||
RUN apt-get update && apt-get install -y unzip && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y unzip && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Create user
|
|
||||||
RUN useradd -m -s /bin/bash ubuntu
|
|
||||||
|
|
||||||
# Copy and extract large static files first
|
# Copy and extract large static files first
|
||||||
COPY nosteam.zip /home/ubuntu/
|
COPY nosteam.zip /home/ubuntu/
|
||||||
COPY wine_user_folder.zip /home/ubuntu/
|
COPY wine_user_folder.zip /home/ubuntu/
|
||||||
@ -20,21 +17,26 @@ RUN dpkg --add-architecture i386 && \
|
|||||||
gnupg2 \
|
gnupg2 \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
&& mkdir -pm755 /etc/apt/keyrings \
|
&& mkdir -pm755 /etc/apt/keyrings \
|
||||||
&& wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key \
|
&& wget -O- https://dl.winehq.org/wine-builds/winehq.key | gpg --dearmor -o /etc/apt/keyrings/winehq-archive.key \
|
||||||
&& echo "deb [signed-by=/etc/apt/keyrings/winehq-archive.key] https://dl.winehq.org/wine-builds/ubuntu/ jammy main" > /etc/apt/sources.list.d/winehq.list \
|
&& echo "deb [signed-by=/etc/apt/keyrings/winehq-archive.key] https://dl.winehq.org/wine-builds/ubuntu/ resolute main" > /etc/apt/sources.list.d/winehq.list \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get install -y --install-recommends winehq-stable \
|
&& apt-get install -y --install-recommends winehq-stable \
|
||||||
&& apt-get install -y \
|
&& apt-get install -y \
|
||||||
winetricks \
|
winetricks \
|
||||||
weston \
|
weston \
|
||||||
xwayland \
|
xwayland \
|
||||||
pulseaudio \
|
dbus-x11 \
|
||||||
|
pipewire \
|
||||||
|
pipewire-pulse \
|
||||||
|
pipewire-audio-client-libraries \
|
||||||
|
wireplumber \
|
||||||
pulseaudio-utils \
|
pulseaudio-utils \
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
xdotool \
|
xdotool \
|
||||||
nodejs \
|
nodejs \
|
||||||
npm \
|
npm \
|
||||||
mesa-vulkan-drivers \
|
mesa-vulkan-drivers \
|
||||||
|
vulkan-tools \
|
||||||
gstreamer1.0-tools \
|
gstreamer1.0-tools \
|
||||||
gstreamer1.0-plugins-base \
|
gstreamer1.0-plugins-base \
|
||||||
gstreamer1.0-plugins-good \
|
gstreamer1.0-plugins-good \
|
||||||
@ -42,6 +44,7 @@ RUN dpkg --add-architecture i386 && \
|
|||||||
gstreamer1.0-plugins-ugly \
|
gstreamer1.0-plugins-ugly \
|
||||||
gstreamer1.0-libav \
|
gstreamer1.0-libav \
|
||||||
gstreamer1.0-nice \
|
gstreamer1.0-nice \
|
||||||
|
gstreamer1.0-pipewire \
|
||||||
gir1.2-gst-plugins-bad-1.0 \
|
gir1.2-gst-plugins-bad-1.0 \
|
||||||
python3-gi \
|
python3-gi \
|
||||||
python3-gst-1.0 \
|
python3-gst-1.0 \
|
||||||
@ -49,7 +52,7 @@ RUN dpkg --add-architecture i386 && \
|
|||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Environment variables
|
# Environment variables
|
||||||
ENV VK_ICD_FILENAMES="/usr/share/vulkan/icd.d/lvp_icd.x86_64.json"
|
ENV VK_ICD_FILENAMES="/usr/share/vulkan/icd.d/lvp_icd.json"
|
||||||
ENV XDG_RUNTIME_DIR=/tmp/weston-runtime
|
ENV XDG_RUNTIME_DIR=/tmp/weston-runtime
|
||||||
ENV WAYLAND_DISPLAY=wayland-0
|
ENV WAYLAND_DISPLAY=wayland-0
|
||||||
ENV DISPLAY=:99
|
ENV DISPLAY=:99
|
||||||
@ -61,7 +64,7 @@ ENV MESA_SHADER_CACHE_MAX_SIZE=10G
|
|||||||
COPY start.sh /home/ubuntu/start.sh
|
COPY start.sh /home/ubuntu/start.sh
|
||||||
COPY streaming-agent/ /home/ubuntu/streaming-agent/
|
COPY streaming-agent/ /home/ubuntu/streaming-agent/
|
||||||
RUN cd /home/ubuntu/streaming-agent && npm install
|
RUN cd /home/ubuntu/streaming-agent && npm install
|
||||||
RUN pip3 install -r /home/ubuntu/streaming-agent/requirements.txt
|
RUN pip3 install --break-system-packages -r /home/ubuntu/streaming-agent/requirements.txt
|
||||||
RUN chown -R ubuntu:ubuntu /home/ubuntu/
|
RUN chown -R ubuntu:ubuntu /home/ubuntu/
|
||||||
RUN chmod +x /home/ubuntu/start.sh
|
RUN chmod +x /home/ubuntu/start.sh
|
||||||
USER ubuntu
|
USER ubuntu
|
||||||
|
|||||||
87
start.sh
87
start.sh
@ -1,44 +1,85 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Clean up stale sockets from previous run
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ── Clean up stale sockets from previous run ──────────────────────────────────
|
||||||
rm -f /tmp/.X99-lock
|
rm -f /tmp/.X99-lock
|
||||||
rm -f /tmp/.X11-unix/X99
|
rm -f /tmp/.X11-unix/X99
|
||||||
rm -rf /tmp/pulse-*
|
|
||||||
rm -f /run/user/$(id -u)/pulse/native
|
|
||||||
rm -rf /tmp/weston-runtime
|
rm -rf /tmp/weston-runtime
|
||||||
|
|
||||||
# Set up Weston runtime directory
|
# ── XDG runtime dir (required by Weston and PipeWire) ────────────────────────
|
||||||
export XDG_RUNTIME_DIR=/tmp/weston-runtime
|
export XDG_RUNTIME_DIR=/tmp/weston-runtime
|
||||||
mkdir -p $XDG_RUNTIME_DIR
|
mkdir -p "$XDG_RUNTIME_DIR"
|
||||||
chmod 700 $XDG_RUNTIME_DIR
|
chmod 700 "$XDG_RUNTIME_DIR"
|
||||||
|
|
||||||
# Start Weston in headless mode (handles Vulkan/DXVK rendering)
|
# ── D-Bus session bus (required by PipeWire / wireplumber) ───────────────────
|
||||||
|
eval $(dbus-launch --sh-syntax)
|
||||||
|
export DBUS_SESSION_BUS_ADDRESS
|
||||||
|
|
||||||
|
# ── Wine virtual desktop matching Weston size ────────────────────────────────
|
||||||
|
wine reg add "HKCU\\Software\\Wine\\Explorer" /v "Desktop" /t REG_SZ /d "Default" /f
|
||||||
|
wine reg add "HKCU\\Software\\Wine\\Explorer\\Desktops" /v "Default" /t REG_SZ /d "800x600" /f
|
||||||
|
wine reg add "HKCU\\Software\\Valve\\Source\\cstrike\\Settings" /v ScreenWidth /t REG_DWORD /d 800 /f
|
||||||
|
wine reg add "HKCU\\Software\\Valve\\Source\\cstrike\\Settings" /v ScreenHeight /t REG_DWORD /d 600 /f
|
||||||
|
wine reg add "HKCU\\Software\\Wine\\WineDbg" /v ShowCrashDialog /t REG_DWORD /d 0 /f
|
||||||
|
export DXVK_CUSTOM_DISPLAY_MODES="800x600@60"
|
||||||
|
|
||||||
|
# ── Start Weston (headless Wayland compositor) ────────────────────────────────
|
||||||
weston --backend=headless-backend.so --width=800 --height=600 --no-config &
|
weston --backend=headless-backend.so --width=800 --height=600 --no-config &
|
||||||
sleep 2
|
sleep 2
|
||||||
export WAYLAND_DISPLAY=wayland-0
|
|
||||||
|
|
||||||
# Start Xwayland — bridges Weston Wayland to X11 for ximagesrc capture
|
export WAYLAND_DISPLAY=$(ls "$XDG_RUNTIME_DIR/" | grep -o 'wayland-[0-9]*' | head -1)
|
||||||
Xwayland :99 &
|
echo "Using WAYLAND_DISPLAY=$WAYLAND_DISPLAY"
|
||||||
|
|
||||||
|
# ── Start Xwayland (X11 compatibility layer over Wayland) ────────────────────
|
||||||
|
# -geometry fixes the virtual framebuffer at exactly 800x600 from the start,
|
||||||
|
# matching Weston's headless output — no xrandr mode-adding needed.
|
||||||
|
Xwayland :99 -glamor off -shm -geometry 800x600 &
|
||||||
|
|
||||||
|
for i in $(seq 1 20); do
|
||||||
|
DISPLAY=:99 xdpyinfo > /dev/null 2>&1 && echo "Xwayland ready" && break
|
||||||
|
echo "Waiting for Xwayland... attempt $i"
|
||||||
sleep 1
|
sleep 1
|
||||||
|
done
|
||||||
export DISPLAY=:99
|
export DISPLAY=:99
|
||||||
|
echo "xrandr result: $(DISPLAY=:99 xrandr | grep '*')"
|
||||||
|
|
||||||
# Suppress Wine crash dialog
|
# ── Start PipeWire stack ──────────────────────────────────────────────────────
|
||||||
wine reg add "HKCU\\Software\\Wine\\WineDbg" /v ShowCrashDialog /t REG_DWORD /d 0 /f
|
export PULSE_RUNTIME_PATH="$XDG_RUNTIME_DIR/pulse"
|
||||||
|
rm -rf "$PULSE_RUNTIME_PATH"
|
||||||
|
|
||||||
# Start PulseAudio for game audio
|
pipewire &
|
||||||
pulseaudio --start --exit-idle-time=-1
|
sleep 1
|
||||||
for i in $(seq 1 10); do
|
wireplumber &
|
||||||
pactl info > /dev/null 2>&1 && break
|
sleep 1
|
||||||
echo "Waiting for PulseAudio... attempt $i"
|
pipewire-pulse &
|
||||||
|
|
||||||
|
# Wait for the PulseAudio-compatible socket
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
pactl info > /dev/null 2>&1 && echo "PipeWire-Pulse ready" && break
|
||||||
|
echo "Waiting for PipeWire-Pulse... attempt $i"
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
# Virtual microphone
|
export PULSE_SERVER="unix:${PULSE_RUNTIME_PATH}/native"
|
||||||
pactl load-module module-null-sink sink_name=mic_sink
|
|
||||||
pactl load-module module-virtual-source source_name=virtual_mic master=mic_sink.monitor
|
|
||||||
pactl set-default-source virtual_mic
|
|
||||||
|
|
||||||
# Launch CSS — Wine uses Wayland driver for rendering via Weston/Vulkan
|
# Virtual microphone — use || true so a pre-existing module doesn't abort
|
||||||
|
# the script (set -e is active). The "Failure: No such entity" in the old
|
||||||
|
# logs was module-virtual-source failing; under PipeWire-Pulse we use
|
||||||
|
# module-null-sink + module-remap-source which is better supported.
|
||||||
|
pactl load-module module-null-sink sink_name=mic_sink sink_properties=device.description=mic_sink || true
|
||||||
|
pactl load-module module-remap-source source_name=virtual_mic master=mic_sink.monitor || true
|
||||||
|
pactl set-default-source virtual_mic || true
|
||||||
|
|
||||||
|
# ── Launch CSS ────────────────────────────────────────────────────────────────
|
||||||
wine ~/Counter-Strike\ Source/revLoader.exe &
|
wine ~/Counter-Strike\ Source/revLoader.exe &
|
||||||
sleep 5
|
|
||||||
|
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
WIN=$(DISPLAY=:99 xdotool search --name "" 2>/dev/null | head -1)
|
||||||
|
[ -n "$WIN" ] && echo "CSS window found: $WIN" && break
|
||||||
|
echo "Waiting for CSS window... attempt $i"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# ── Start streaming agent ─────────────────────────────────────────────────────
|
||||||
python3 ~/streaming-agent/gst_agent.py
|
python3 ~/streaming-agent/gst_agent.py
|
||||||
|
|||||||
@ -4,14 +4,15 @@ GStreamer WebRTC Agent for CSS Streaming
|
|||||||
|
|
||||||
Two tracks published to Cloudflare Calls:
|
Two tracks published to Cloudflare Calls:
|
||||||
- Video: ximagesrc (Xwayland :99) → VP8 → webrtcbin
|
- Video: ximagesrc (Xwayland :99) → VP8 → webrtcbin
|
||||||
- Game audio: pulsesrc → Opus → webrtcbin
|
- Game audio: pipewiresrc → Opus → webrtcbin
|
||||||
|
|
||||||
CSS renders via Wine Wayland driver → Weston (Vulkan/DXVK) → Xwayland → X11
|
CSS renders via Wine Wayland driver → Weston (Vulkan/DXVK) → Xwayland → X11
|
||||||
ximagesrc captures from Xwayland X11 display :99
|
ximagesrc captures from Xwayland X11 display :99
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
apt: python3-gst-1.0 gstreamer1.0-plugins-bad gstreamer1.0-plugins-good
|
apt: python3-gst-1.0 gstreamer1.0-plugins-bad gstreamer1.0-plugins-good
|
||||||
gstreamer1.0-plugins-ugly gstreamer1.0-libav xdotool weston xwayland
|
gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-pipewire
|
||||||
|
xdotool weston xwayland wireplumber pipewire pipewire-pulse
|
||||||
pip: requests websockets
|
pip: requests websockets
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -109,19 +110,26 @@ class CSSStreamAgent:
|
|||||||
|
|
||||||
def build_pipeline(self):
|
def build_pipeline(self):
|
||||||
pipeline_str = (
|
pipeline_str = (
|
||||||
# Video: ximagesrc from Xwayland display → VP8
|
# Video: ximagesrc → convert → scale → rate-enforce → VP8
|
||||||
|
# videoconvert must come before caps negotiation;
|
||||||
|
# videoscale enforces width/height; videorate enforces framerate.
|
||||||
f'ximagesrc display-name={DISPLAY} use-damage=0 ! '
|
f'ximagesrc display-name={DISPLAY} use-damage=0 ! '
|
||||||
f'video/x-raw,framerate={CAP_FPS}/1,width={CAP_W},height={CAP_H} ! '
|
|
||||||
f'videoconvert ! '
|
f'videoconvert ! '
|
||||||
|
f'videoscale ! '
|
||||||
|
f'videorate ! '
|
||||||
|
f'video/x-raw,framerate={CAP_FPS}/1,width={CAP_W},height={CAP_H} ! '
|
||||||
f'vp8enc deadline=1 target-bitrate=1500000 keyframe-max-dist=60 '
|
f'vp8enc deadline=1 target-bitrate=1500000 keyframe-max-dist=60 '
|
||||||
f'error-resilient=partitions lag-in-frames=0 ! '
|
f'error-resilient=partitions lag-in-frames=0 ! '
|
||||||
f'rtpvp8pay pt=96 ! '
|
f'rtpvp8pay pt=96 ! '
|
||||||
f'application/x-rtp,media=video,encoding-name=VP8,payload=96 ! '
|
f'application/x-rtp,media=video,encoding-name=VP8,payload=96 ! '
|
||||||
f'webrtcbin. '
|
f'webrtcbin. '
|
||||||
|
|
||||||
# Game audio: pulsesrc → Opus
|
# Game audio: pipewiresrc → Opus
|
||||||
f'pulsesrc ! '
|
# pipewiresrc is the native PipeWire GStreamer source (Ubuntu 24+/26).
|
||||||
f'audio/x-raw,rate=48000,channels=2 ! '
|
# It connects to the default audio output monitor via PipeWire directly,
|
||||||
|
# avoiding the PulseAudio compatibility layer entirely.
|
||||||
|
f'pipewiresrc ! '
|
||||||
|
f'audio/x-raw,format=F32LE,rate=48000,channels=2 ! '
|
||||||
f'audioconvert ! '
|
f'audioconvert ! '
|
||||||
f'opusenc ! '
|
f'opusenc ! '
|
||||||
f'rtpopuspay pt=97 ! '
|
f'rtpopuspay pt=97 ! '
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user