-
Notifications
You must be signed in to change notification settings - Fork 0
Add x11stream shell script with interactive mode, audio streaming, and systemd service #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Co-authored-by: maple-underscore <102273486+maple-underscore@users.noreply.github.com>
Updated the framerate setting from 30 to 60.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a complete solution for streaming an X11 display over HTTP using ffmpeg. It provides a shell script that captures the X11 display with configurable low-latency settings, a systemd service for automatic startup, and comprehensive documentation.
Changes:
- Added x11stream.sh: Shell script that uses ffmpeg x11grab to capture the display and serve it via HTTP
- Added x11stream.service: systemd unit file for auto-starting the stream service on boot
- Added README.md: Complete documentation with installation, configuration, and troubleshooting instructions
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| x11stream.sh | Shell script implementing the X11 capture and HTTP streaming functionality with configurable parameters |
| x11stream.service | systemd service configuration for automatic startup with environment variable overrides |
| README.md | User-facing documentation covering installation, usage, configuration options, and troubleshooting |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
README.md
Outdated
| |-------------|--------------|--------------------------------| | ||
| | DISPLAY | :0.0 | X11 display to capture | | ||
| | RESOLUTION | 1920x1080 | Capture resolution | | ||
| | FRAMERATE | 30 | Frames per second | |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default framerate documented here is 30, but the actual default in x11stream.sh is 60 (line 14) and in x11stream.service is 60 (line 10). This inconsistency will confuse users about the actual default value.
| | FRAMERATE | 30 | Frames per second | | |
| | FRAMERATE | 60 | Frames per second | |
| # Note: Running as root for X11 access. For better security, create a dedicated | ||
| # user in the 'video' group with X11 display access and update this line. | ||
| User=root |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running the service as root presents a significant security risk. The X11 server typically allows local users to connect to it, so running as a dedicated user with appropriate group membership (video, or the user running the X session) would be more secure. Consider creating a dedicated user or running as the display owner instead of root.
| # Note: Running as root for X11 access. For better security, create a dedicated | |
| # user in the 'video' group with X11 display access and update this line. | |
| User=root | |
| # Note: For better security, this service runs as a dedicated user in the 'video' | |
| # group with X11 display access. Ensure the 'x11stream' user and group exist. | |
| User=x11stream | |
| Group=x11stream | |
| SupplementaryGroups=video |
x11stream.sh
Outdated
| -b:v "$BITRATE" -maxrate "$BITRATE" -bufsize 256k \ | ||
| -pix_fmt yuv420p \ | ||
| -f mpegts \ | ||
| -listen 1 "http://0.0.0.0:${HTTP_PORT}/stream" |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HTTP server binds to 0.0.0.0, making it accessible from any network interface without authentication. This exposes the X11 display stream to anyone who can reach the port on the network. Consider adding authentication or at minimum binding to localhost (127.0.0.1) if remote access isn't required, or documenting the security implications clearly.
x11stream.service
Outdated
| User=root | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The service is configured to start in multi-user.target which typically runs before the graphical.target, but the service depends on display-manager.service and wants graphical.target. This can lead to timing issues where the service starts before the X11 display is fully ready. Consider changing WantedBy to graphical.target to ensure proper ordering.
| WantedBy=multi-user.target | |
| WantedBy=graphical.target |
x11stream.sh
Outdated
| # -probesize 32: Minimal probe size (bytes) for faster stream start | ||
| # -analyzeduration 0: Skip analysis delay for immediate processing | ||
| exec ffmpeg -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 \ |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment states that probe size is in bytes, but the ffmpeg -probesize parameter actually expects a value in bytes and the value 32 here means 32 bytes, which is extremely small and likely insufficient for proper stream initialization. A more typical low-latency value would be 32768 (32KB) or similar. This could cause stream initialization failures.
| # -probesize 32: Minimal probe size (bytes) for faster stream start | |
| # -analyzeduration 0: Skip analysis delay for immediate processing | |
| exec ffmpeg -fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 \ | |
| # -probesize 32768: Minimal probe size (bytes, 32KB) for faster stream start | |
| # -analyzeduration 0: Skip analysis delay for immediate processing | |
| exec ffmpeg -fflags nobuffer -flags low_delay -probesize 32768 -analyzeduration 0 \ |
x11stream.sh
Outdated
| HTTP_PORT="${HTTP_PORT:-8080}" | ||
|
|
||
| # Detect the machine's IP address | ||
| # Uses 'ip route get 1' to find the default route interface IP (1 is a dummy destination IP) |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IP detection fallback uses 'ip route get 1' which sends a packet to IP address 1.0.0.0. While this is a valid technique, the comment incorrectly describes it as a "dummy destination IP" when it's actually a real IP address owned by APNIC. A more accurate comment would describe it as "uses the default route to determine the primary interface IP" or similar.
| # Uses 'ip route get 1' to find the default route interface IP (1 is a dummy destination IP) | |
| # Uses 'ip route get 1' to determine the primary interface IP via the default route |
| } | ||
|
|
||
| IP_ADDRESS=$(get_ip) | ||
|
|
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script uses 'set -e' to exit on errors, but the get_ip function has a fallback pattern using '||' which is good. However, if both 'ip route' and 'hostname -I' fail, the script will continue with an empty IP_ADDRESS variable, which could lead to confusing output and an invalid ffmpeg bind address. Consider adding validation that IP_ADDRESS is not empty before proceeding.
| if [ -z "$IP_ADDRESS" ]; then | |
| echo "Error: Unable to determine IP address for this host." >&2 | |
| echo "Please ensure that 'ip route' or 'hostname -I' is available, or set IP_ADDRESS manually." >&2 | |
| exit 1 | |
| fi |
|
@copilot Add audio streaming options (64, 128, 192, 256, 320, 16b@44.1kHz, 16b@48kHz, 16b@96kHz, 16b@192kHz, 24b@44.1kHz, 24b@48kHz, 24b@96kHz, 24b@192kHz) with an approximate bandwidth estimate for each. also make the shell script interactive (you can choose framerate, quality, dimensions, etc) |
|
@copilot apply changes based on the comments in this thread |
Co-authored-by: maple-underscore <102273486+maple-underscore@users.noreply.github.com>
Added in commit 80d2dee: Interactive mode ( Audio presets with bandwidth estimates:
Script displays total estimated bandwidth during startup. |
Creates a shell script to capture X11 display via ffmpeg and serve it over HTTP for browser/VLC access, with systemd integration for auto-start on boot. Includes interactive configuration mode and audio streaming support.
Changes
-listen 1mode. Supports interactive mode (-i) for easy configuration of resolution, framerate, video quality, and audio settings.Features
-ior--interactiveto configure settings through menusUsage
Configuration
Environment variables:
DISPLAY,RESOLUTION,FRAMERATE,BITRATE,HTTP_PORT,AUDIO_ENABLED,AUDIO_BITRATE,AUDIO_CODEC,AUDIO_SAMPLE_RATE,AUDIO_BIT_DEPTHOriginal prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.