Bind monitor audio stream to start request token

This commit is contained in:
Smittix
2026-02-24 09:15:24 +00:00
parent d9b528f3d3
commit 55c38522a4
2 changed files with 43 additions and 25 deletions

View File

@@ -1606,14 +1606,25 @@ def audio_probe() -> Response:
return jsonify({'status': 'ok', 'bytes': size}) return jsonify({'status': 'ok', 'bytes': size})
@receiver_bp.route('/audio/stream') @receiver_bp.route('/audio/stream')
def stream_audio() -> Response: def stream_audio() -> Response:
"""Stream WAV audio.""" """Stream WAV audio."""
if audio_source == 'waterfall': request_token_raw = request.args.get('request_token')
for _ in range(40): request_token = None
if audio_running: if request_token_raw is not None:
break try:
time.sleep(0.05) request_token = int(request_token_raw)
except (ValueError, TypeError):
request_token = None
if request_token is not None and request_token < audio_start_token:
return Response(b'', mimetype='audio/wav', status=204)
if audio_source == 'waterfall':
for _ in range(40):
if audio_running:
break
time.sleep(0.05)
if not audio_running: if not audio_running:
return Response(b'', mimetype='audio/wav', status=204) return Response(b'', mimetype='audio/wav', status=204)
@@ -1633,6 +1644,8 @@ def stream_audio() -> Response:
inactive_since: float | None = None inactive_since: float | None = None
while audio_running and audio_source == 'waterfall': while audio_running and audio_source == 'waterfall':
if request_token is not None and request_token < audio_start_token:
break
chunk = read_shared_monitor_audio_chunk(timeout=1.0) chunk = read_shared_monitor_audio_chunk(timeout=1.0)
if chunk: if chunk:
inactive_since = None inactive_since = None
@@ -1672,11 +1685,11 @@ def stream_audio() -> Response:
if not audio_running or not audio_process: if not audio_running or not audio_process:
return Response(b'', mimetype='audio/wav', status=204) return Response(b'', mimetype='audio/wav', status=204)
def generate(): def generate():
# Capture local reference to avoid race condition with stop # Capture local reference to avoid race condition with stop
proc = audio_process proc = audio_process
if not proc or not proc.stdout: if not proc or not proc.stdout:
return return
try: try:
# Drain stale audio that accumulated in the pipe buffer # Drain stale audio that accumulated in the pipe buffer
# between pipeline start and stream connection. Keep the # between pipeline start and stream connection. Keep the
@@ -1695,15 +1708,17 @@ def stream_audio() -> Response:
if header_chunk: if header_chunk:
yield header_chunk yield header_chunk
# Stream real-time audio # Stream real-time audio
first_chunk_deadline = time.time() + 20.0 first_chunk_deadline = time.time() + 20.0
warned_wait = False warned_wait = False
while audio_running and proc.poll() is None: while audio_running and proc.poll() is None:
# Use select to avoid blocking forever if request_token is not None and request_token < audio_start_token:
ready, _, _ = select.select([proc.stdout], [], [], 2.0) break
if ready: # Use select to avoid blocking forever
chunk = proc.stdout.read(8192) ready, _, _ = select.select([proc.stdout], [], [], 2.0)
if chunk: if ready:
chunk = proc.stdout.read(8192)
if chunk:
warned_wait = False warned_wait = False
yield chunk yield chunk
else: else:

View File

@@ -2603,7 +2603,7 @@ const Waterfall = (function () {
player.load(); player.load();
} }
async function _attachMonitorAudio(nonce) { async function _attachMonitorAudio(nonce, streamToken = null) {
const player = document.getElementById('wfAudioPlayer'); const player = document.getElementById('wfAudioPlayer');
if (!player) { if (!player) {
return { ok: false, reason: 'player_missing', message: 'Audio player is unavailable.' }; return { ok: false, reason: 'player_missing', message: 'Audio player is unavailable.' };
@@ -2622,7 +2622,10 @@ const Waterfall = (function () {
} }
await _pauseMonitorAudioElement(); await _pauseMonitorAudioElement();
player.src = `/receiver/audio/stream?fresh=1&t=${Date.now()}-${attempt}`; const tokenQuery = (streamToken !== null && streamToken !== undefined && String(streamToken).length > 0)
? `&request_token=${encodeURIComponent(String(streamToken))}`
: '';
player.src = `/receiver/audio/stream?fresh=1&t=${Date.now()}-${attempt}${tokenQuery}`;
player.load(); player.load();
try { try {
@@ -2886,7 +2889,7 @@ const Waterfall = (function () {
return; return;
} }
const attach = await _attachMonitorAudio(nonce); const attach = await _attachMonitorAudio(nonce, payload?.request_token);
if (nonce !== _audioConnectNonce) return; if (nonce !== _audioConnectNonce) return;
_monitorSource = payload?.source === 'waterfall' ? 'waterfall' : 'process'; _monitorSource = payload?.source === 'waterfall' ? 'waterfall' : 'process';
if ( if (