From fa537390c57508d68b587a9b7c1002e4edbfd90b Mon Sep 17 00:00:00 2001 From: Smittix Date: Tue, 6 Jan 2026 21:42:55 +0000 Subject: [PATCH] Fix audio stream errors and improve error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix "no supported source" error by returning empty audio response instead of JSON when audio not running (browser can't parse JSON) - Add wait loop in stream endpoint to handle race condition with start - Add logging for rtl_fm and ffmpeg commands - Capture stderr to log actual process errors - Check if processes exit immediately and log reason - Improved error messages for users 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- routes/listening_post.py | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/routes/listening_post.py b/routes/listening_post.py index 1b173dd..bddb38a 100644 --- a/routes/listening_post.py +++ b/routes/listening_post.py @@ -379,24 +379,41 @@ def _start_audio_stream(frequency: float, modulation: str): ] try: + logger.info(f"Starting rtl_fm: {' '.join(rtl_cmd)}") audio_rtl_process = subprocess.Popen( rtl_cmd, stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL + stderr=subprocess.PIPE ) + logger.info(f"Starting ffmpeg: {' '.join(encoder_cmd)}") audio_process = subprocess.Popen( encoder_cmd, stdin=audio_rtl_process.stdout, stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, + stderr=subprocess.PIPE, bufsize=0 ) audio_rtl_process.stdout.close() + + # Brief delay to check if processes started successfully + time.sleep(0.2) + + if audio_rtl_process.poll() is not None: + stderr = audio_rtl_process.stderr.read().decode() if audio_rtl_process.stderr else '' + logger.error(f"rtl_fm exited immediately: {stderr}") + return + + if audio_process.poll() is not None: + stderr = audio_process.stderr.read().decode() if audio_process.stderr else '' + logger.error(f"ffmpeg exited immediately: {stderr}") + return + audio_running = True audio_frequency = frequency audio_modulation = modulation + logger.info(f"Audio stream started: {frequency} MHz ({modulation})") except Exception as e: logger.error(f"Failed to start audio stream: {e}") @@ -694,7 +711,7 @@ def start_audio() -> Response: else: return jsonify({ 'status': 'error', - 'message': 'Failed to start audio' + 'message': 'Failed to start audio. Check that rtl_fm and ffmpeg are installed, and that an SDR device is connected and not in use by another process.' }), 500 @@ -718,11 +735,15 @@ def audio_status() -> Response: @listening_post_bp.route('/audio/stream') def stream_audio() -> Response: """Stream MP3 audio.""" + # Wait briefly for audio to start (handles race condition with /audio/start) + for _ in range(10): + if audio_running and audio_process: + break + time.sleep(0.1) + if not audio_running or not audio_process: - return jsonify({ - 'status': 'error', - 'message': 'Audio not running' - }), 400 + # Return empty audio response instead of JSON (browser audio element can't parse JSON) + return Response(b'', mimetype='audio/mpeg', status=204) def generate(): chunk_size = 4096