fix: revert listener port to 5001; set SRT port to 5005 via mediamtx_srt_port config

This commit is contained in:
ComputerTech 2026-04-04 12:39:03 +01:00
parent 498832bdcb
commit effb52c5df
6 changed files with 28 additions and 24 deletions

View File

@ -3,7 +3,7 @@
TechDJ Pro is a local DJ web app with a dual-port architecture: TechDJ Pro is a local DJ web app with a dual-port architecture:
- **DJ Panel** (mix/load tracks + start broadcast): `http://localhost:5000` - **DJ Panel** (mix/load tracks + start broadcast): `http://localhost:5000`
- **Listener Page** (receive the live stream): `http://localhost:5005` - **Listener Page** (receive the live stream): `http://localhost:5001`
It supports: It supports:
- Local library playback (files in `music/`) - Local library playback (files in `music/`)
@ -104,7 +104,7 @@ If you want to lock it while youre playing live, create a `config.json` (not
Behavior: Behavior:
- If `dj_panel_password` is empty/missing, the DJ panel is **unlocked** (default). - If `dj_panel_password` is empty/missing, the DJ panel is **unlocked** (default).
- If set, visiting `http://<DJ_MACHINE_IP>:5000` shows a login prompt. - If set, visiting `http://<DJ_MACHINE_IP>:5000` shows a login prompt.
- Listener (`:5005`) is not affected. - Listener (`:5001`) is not affected.
--- ---
@ -120,7 +120,7 @@ python server.py
You should see output like: You should see output like:
- DJ panel: `http://localhost:5000` - DJ panel: `http://localhost:5000`
- Listener page: `http://localhost:5005` - Listener page: `http://localhost:5001`
--- ---
@ -149,10 +149,10 @@ TechDJ can relay live streams from other DJ servers:
### Listener workflow ### Listener workflow
1. Open the Listener Page: 1. Open the Listener Page:
- Same machine: `http://localhost:5005` - Same machine: `http://localhost:5001`
- Another device on your LAN/WiFi: - Another device on your LAN/WiFi:
`http://<DJ_MACHINE_IP>:5005` `http://<DJ_MACHINE_IP>:5001`
2. Click **ENABLE AUDIO** if prompted 2. Click **ENABLE AUDIO** if prompted
- Browsers block autoplay by default; user interaction is required.3. Enjoy the live stream with real-time spectrum visualization - Browsers block autoplay by default; user interaction is required.3. Enjoy the live stream with real-time spectrum visualization
@ -186,7 +186,7 @@ Use the LAN IP (commonly `192.168.x.x` or `10.x.x.x`).
Make sure the DJ machine allows inbound connections on: Make sure the DJ machine allows inbound connections on:
- TCP `5000` (DJ Panel) - TCP `5000` (DJ Panel)
- TCP `5005` (Listener) - TCP `5001` (Listener)
If listeners cant connect, this is often the cause. If listeners cant connect, this is often the cause.
@ -196,7 +196,7 @@ If listeners cant connect, this is often the cause.
TechDJ serves the listener audio as an **MP3 HTTP stream**: TechDJ serves the listener audio as an **MP3 HTTP stream**:
- MP3 stream endpoint: `http://<DJ_MACHINE_IP>:5005/stream.mp3` - MP3 stream endpoint: `http://<DJ_MACHINE_IP>:5001/stream.mp3`
This requires `ffmpeg` installed on the DJ/server machine. This requires `ffmpeg` installed on the DJ/server machine.
@ -204,7 +204,7 @@ This requires `ffmpeg` installed on the DJ/server machine.
- Stream debug JSON: - Stream debug JSON:
`http://<DJ_MACHINE_IP>:5005/stream_debug` `http://<DJ_MACHINE_IP>:5001/stream_debug`
This shows whether ffmpeg is running and whether MP3 bytes are being produced. This shows whether ffmpeg is running and whether MP3 bytes are being produced.
@ -240,7 +240,7 @@ Example Cloudflare page rule:
- Ensure `ffmpeg` is installed on the server - Ensure `ffmpeg` is installed on the server
- Try opening the MP3 fallback directly: - Try opening the MP3 fallback directly:
`http://<DJ_MACHINE_IP>:5005/stream.mp3` `http://<DJ_MACHINE_IP>:5001/stream.mp3`
### DJ says broadcast is live but listeners hear nothing ### DJ says broadcast is live but listeners hear nothing
@ -248,7 +248,7 @@ Example Cloudflare page rule:
- A deck is actually playing - A deck is actually playing
- Crossfader isnt fully on the silent side - Crossfader isnt fully on the silent side
- Volumes arent at 0 - Volumes arent at 0
- Check `http://<DJ_MACHINE_IP>:5005/stream_debug` and see if `transcoder_bytes_out` increases - Check `http://<DJ_MACHINE_IP>:5001/stream_debug` and see if `transcoder_bytes_out` increases
### Spectrum visualiser not showing ### Spectrum visualiser not showing
- Ensure the listener page is loaded and audio is enabled. - Ensure the listener page is loaded and audio is enabled.

View File

@ -3,7 +3,7 @@
"host": "0.0.0.0", "host": "0.0.0.0",
"dj_port": 5000, "dj_port": 5000,
"listener_port": 5005, "listener_port": 5001,
"dj_panel_password": "", "dj_panel_password": "",
"secret_key": "", "secret_key": "",
@ -19,6 +19,8 @@
"_comment_mediamtx": "MediaMTX / SRT integration. mediamtx_webhook_secret is the shared secret sent in the X-MediaMTX-Webhook-Secret header by webhook callers (leave blank to disable auth). mediamtx_rtsp_url is the RTSP URL MediaMTX exposes for the incoming SRT path.", "_comment_mediamtx": "MediaMTX / SRT integration. mediamtx_webhook_secret is the shared secret sent in the X-MediaMTX-Webhook-Secret header by webhook callers (leave blank to disable auth). mediamtx_rtsp_url is the RTSP URL MediaMTX exposes for the incoming SRT path.",
"mediamtx_webhook_secret": "", "mediamtx_webhook_secret": "",
"_comment_mediamtx_srt_port": "SRT ingest port MediaMTX listens on. Flask does not bind this port — set it in mediamtx.yml. Stored here for reference.",
"mediamtx_srt_port": 5005,
"mediamtx_rtsp_url": "rtsp://127.0.0.1:8554/live", "mediamtx_rtsp_url": "rtsp://127.0.0.1:8554/live",
"mediamtx_hls_url": "http://techy.music:8888/aussie_dj/index.m3u8", "mediamtx_hls_url": "http://techy.music:8888/aussie_dj/index.m3u8",
"_comment_srt_allowed_ips": "List of DJ source IPs allowed to publish an SRT stream. Empty = allow all.", "_comment_srt_allowed_ips": "List of DJ source IPs allowed to publish an SRT stream. Empty = allow all.",

View File

@ -392,7 +392,7 @@
<div class="stream-url-section"> <div class="stream-url-section">
<label>Share this URL:</label> <label>Share this URL:</label>
<div class="url-copy-group"> <div class="url-copy-group">
<input type="text" id="stream-url" readonly value="http://localhost:5005"> <input type="text" id="stream-url" readonly value="http://localhost:5001">
<button onclick="copyStreamUrl(event)" class="copy-btn">COPY</button> <button onclick="copyStreamUrl(event)" class="copy-btn">COPY</button>
</div> </div>
</div> </div>

View File

@ -366,7 +366,7 @@ function animateVUMeters() {
requestAnimationFrame(animateVUMeters); requestAnimationFrame(animateVUMeters);
const anyPlaying = decks.A.playing || decks.B.playing; const anyPlaying = decks.A.playing || decks.B.playing;
const isListener = window.location.port === '5005' || window.location.search.includes('listen=true'); const isListener = window.location.port === '5001' || window.location.search.includes('listen=true');
// When nothing is playing, clear canvases to transparent so they don't show as dark blocks // When nothing is playing, clear canvases to transparent so they don't show as dark blocks
if (!anyPlaying && !isListener) { if (!anyPlaying && !isListener) {
@ -1880,7 +1880,7 @@ window.addEventListener('DOMContentLoaded', () => {
if (host.startsWith('dj.')) { if (host.startsWith('dj.')) {
return `${window.location.protocol}//${host.slice(3)}`; return `${window.location.protocol}//${host.slice(3)}`;
} }
return `${window.location.protocol}//${host}:5005`; return `${window.location.protocol}//${host}:5001`;
}; };
fetch('/client_config') fetch('/client_config')
.then(r => r.json()) .then(r => r.json())

View File

@ -38,7 +38,7 @@ CONFIG = _load_config()
# --- Config-driven settings (config.json > env vars > defaults) --- # --- Config-driven settings (config.json > env vars > defaults) ---
CONFIG_HOST = (CONFIG.get('host') or os.environ.get('HOST') or '0.0.0.0').strip() CONFIG_HOST = (CONFIG.get('host') or os.environ.get('HOST') or '0.0.0.0').strip()
CONFIG_DJ_PORT = int(CONFIG.get('dj_port') or os.environ.get('DJ_PORT') or 5000) CONFIG_DJ_PORT = int(CONFIG.get('dj_port') or os.environ.get('DJ_PORT') or 5000)
CONFIG_LISTENER_PORT = int(CONFIG.get('listener_port') or os.environ.get('LISTEN_PORT') or 5005) CONFIG_LISTENER_PORT = int(CONFIG.get('listener_port') or os.environ.get('LISTEN_PORT') or 5001)
CONFIG_SECRET = (CONFIG.get('secret_key') or '').strip() or 'dj_panel_secret' CONFIG_SECRET = (CONFIG.get('secret_key') or '').strip() or 'dj_panel_secret'
CONFIG_CORS = CONFIG.get('cors_origins', '*') CONFIG_CORS = CONFIG.get('cors_origins', '*')
CONFIG_MAX_UPLOAD_MB = int(CONFIG.get('max_upload_mb') or 500) CONFIG_MAX_UPLOAD_MB = int(CONFIG.get('max_upload_mb') or 500)
@ -48,6 +48,8 @@ CONFIG_LISTENER_URL = (CONFIG.get('listener_url') or '').strip()
# MediaMTX / SRT integration # MediaMTX / SRT integration
# secret shared with MediaMTX webhook requests (leave blank to disable auth) # secret shared with MediaMTX webhook requests (leave blank to disable auth)
_SRT_WEBHOOK_SECRET = (CONFIG.get('mediamtx_webhook_secret') or '').strip() _SRT_WEBHOOK_SECRET = (CONFIG.get('mediamtx_webhook_secret') or '').strip()
# SRT ingest port MediaMTX listens on (Flask does not bind this — configure in mediamtx.yml)
_MEDIAMTX_SRT_PORT = int(CONFIG.get('mediamtx_srt_port') or 5005)
# RTSP URL MediaMTX exposes for the incoming SRT path (used by ffmpeg to pull audio) # RTSP URL MediaMTX exposes for the incoming SRT path (used by ffmpeg to pull audio)
_MEDIAMTX_RTSP_URL = (CONFIG.get('mediamtx_rtsp_url') or 'rtsp://127.0.0.1:8554/live').strip() _MEDIAMTX_RTSP_URL = (CONFIG.get('mediamtx_rtsp_url') or 'rtsp://127.0.0.1:8554/live').strip()
_MEDIAMTX_HLS_URL = (CONFIG.get('mediamtx_hls_url') or 'http://techy.music:8888/aussie_dj/index.m3u8').strip() _MEDIAMTX_HLS_URL = (CONFIG.get('mediamtx_hls_url') or 'http://techy.music:8888/aussie_dj/index.m3u8').strip()
@ -712,7 +714,7 @@ setup_shared_routes(dj_app)
def _protect_dj_panel(): def _protect_dj_panel():
"""Optionally require a password for the DJ panel only (port 5000). """Optionally require a password for the DJ panel only (port 5000).
This does not affect the listener server (port 5005). This does not affect the listener server (port 5001).
""" """
if not DJ_AUTH_ENABLED: if not DJ_AUTH_ENABLED:
return None return None
@ -1103,11 +1105,11 @@ def mediamtx_webhook():
MediaMTX path config example (mediamtx.yml): MediaMTX path config example (mediamtx.yml):
paths: paths:
live: live:
runOnPublish: 'curl -s -X POST http://127.0.0.1:5005/api/webhook -H "Content-Type: application/json" -d \'{"event":"publish","path":"%MTX_PATH%","id":"%MTX_ID%"}\'' runOnPublish: 'curl -s -X POST http://127.0.0.1:5001/api/webhook -H "Content-Type: application/json" -d \'{"event":"publish","path":"%MTX_PATH%","id":"%MTX_ID%"}\''
runOnUnpublish: 'curl -s -X POST http://127.0.0.1:5005/api/webhook -H "Content-Type: application/json" -d \'{"event":"unpublish","path":"%MTX_PATH%","id":"%MTX_ID%"}\'' runOnUnpublish: 'curl -s -X POST http://127.0.0.1:5001/api/webhook -H "Content-Type: application/json" -d \'{"event":"unpublish","path":"%MTX_PATH%","id":"%MTX_ID%"}\''
Or if using MediaMTX >= 1.x webhook integration, point: Or if using MediaMTX >= 1.x webhook integration, point:
api > hooks > [publish|unpublish] > url: http://127.0.0.1:5005/api/webhook api > hooks > [publish|unpublish] > url: http://127.0.0.1:5001/api/webhook
""" """
global _mp3_broadcast_announced global _mp3_broadcast_announced
@ -1197,7 +1199,7 @@ def srt_auth():
attempt. Returning HTTP 200 allows the connection; anything else rejects it. attempt. Returning HTTP 200 allows the connection; anything else rejects it.
mediamtx.yml: mediamtx.yml:
externalAuthenticationURL: http://127.0.0.1:5005/api/srt_auth externalAuthenticationURL: http://127.0.0.1:5001/api/srt_auth
MediaMTX sends JSON like: MediaMTX sends JSON like:
{"ip": "1.2.3.4", "action": "publish", "protocol": "srt", {"ip": "1.2.3.4", "action": "publish", "protocol": "srt",

View File

@ -2686,7 +2686,7 @@ class DJApp(QMainWindow):
def get_listener_base_url(self): def get_listener_base_url(self):
"""Return the listener server base URL (no auth required). """Return the listener server base URL (no auth required).
The listener server runs on DJ_port + 1 by convention (default 5005). The listener server runs on DJ_port + 1 by convention (default 5001).
Library JSON and music_proxy routes are available there without any Library JSON and music_proxy routes are available there without any
password, so we use this for all library / track-download requests. password, so we use this for all library / track-download requests.
""" """
@ -2702,8 +2702,8 @@ class DJApp(QMainWindow):
# Normalise: if the configured port IS the listener port, keep it; # Normalise: if the configured port IS the listener port, keep it;
# otherwise derive listener port as DJ port + 1. # otherwise derive listener port as DJ port + 1.
if dj_port == 5005: if dj_port == 5001:
listener_port = 5005 listener_port = 5001
else: else:
# Remap any reverse-proxy or listener port back to DJ port first, # Remap any reverse-proxy or listener port back to DJ port first,
# then add 1 to get the listener port. # then add 1 to get the listener port.
@ -2726,7 +2726,7 @@ class DJApp(QMainWindow):
port = parsed.port or 5000 port = parsed.port or 5000
# Remap listener port and common reverse-proxy port to the DJ server port # Remap listener port and common reverse-proxy port to the DJ server port
if port in (5005, 8080): if port in (5001, 8080):
port = 5000 port = 5000
# Always use plain HTTP — the server never terminates TLS directly. # Always use plain HTTP — the server never terminates TLS directly.