From aae60e2037d825cf9c6726d315300d49ecfaf707 Mon Sep 17 00:00:00 2001 From: Smittix Date: Thu, 15 Jan 2026 17:17:15 +0000 Subject: [PATCH] Add real-time squelch control and clean up diagnostic logging - Add updateAirbandSquelch() to restart audio when squelch slider changes - Remove verbose diagnostic logging from audio streaming - Remove tee diagnostic for raw rtl_fm output - Keep error logging for troubleshooting - Simplify audio stream generator Co-Authored-By: Claude Opus 4.5 --- instance/intercept.db | Bin 32768 -> 69632 bytes routes/listening_post.py | 80 +++------------------------------- templates/adsb_dashboard.html | 10 ++++- 3 files changed, 14 insertions(+), 76 deletions(-) diff --git a/instance/intercept.db b/instance/intercept.db index 15137ad5eefec838d0fa0e09058b15db5101f2ec..2c3aa904e3276f856a294ced7ee0fb431ae1a909 100644 GIT binary patch literal 69632 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 SZB`U`!?`)_)-2XV0tEp501*NJ diff --git a/routes/listening_post.py b/routes/listening_post.py index d768473..fb4960e 100644 --- a/routes/listening_post.py +++ b/routes/listening_post.py @@ -440,14 +440,12 @@ def _start_audio_stream(frequency: float, modulation: str): ] try: - # Use shell pipe for reliable streaming (Python subprocess piping can be unreliable) - # Log stderr to temp files so we can see any errors from rtl_fm and ffmpeg + # Use shell pipe for reliable streaming + # Log stderr to temp files for error diagnosis rtl_stderr_log = '/tmp/rtl_fm_stderr.log' ffmpeg_stderr_log = '/tmp/ffmpeg_stderr.log' - rtl_raw_output = '/tmp/rtl_fm_raw.bin' - # Use tee to capture rtl_fm raw output for diagnostics while also piping to ffmpeg - shell_cmd = f"{' '.join(sdr_cmd)} 2>{rtl_stderr_log} | tee {rtl_raw_output} | {' '.join(encoder_cmd)} 2>{ffmpeg_stderr_log}" - logger.info(f"Starting audio pipeline: {shell_cmd}") + shell_cmd = f"{' '.join(sdr_cmd)} 2>{rtl_stderr_log} | {' '.join(encoder_cmd)} 2>{ffmpeg_stderr_log}" + logger.info(f"Starting audio: {frequency} MHz, mod={modulation}, device={scanner_config['device']}") audio_rtl_process = None # Not used in shell mode audio_process = subprocess.Popen( @@ -479,22 +477,6 @@ def _start_audio_stream(frequency: float, modulation: str): logger.error(f"Audio pipeline exited immediately. rtl_fm stderr: {rtl_stderr}, ffmpeg stderr: {ffmpeg_stderr}") return - # Also check for errors even if process is still running - try: - with open(rtl_stderr_log, 'r') as f: - rtl_stderr = f.read().strip() - if rtl_stderr: - logger.warning(f"rtl_fm stderr: {rtl_stderr}") - except: - pass - try: - with open(ffmpeg_stderr_log, 'r') as f: - ffmpeg_stderr = f.read().strip() - if ffmpeg_stderr: - logger.warning(f"ffmpeg stderr: {ffmpeg_stderr}") - except: - pass - audio_running = True audio_frequency = frequency audio_modulation = modulation @@ -810,8 +792,6 @@ def start_audio() -> Response: """Start audio at specific frequency (manual mode).""" global scanner_running - logger.info(f"Audio start request received: {request.json}") - # Stop scanner if running if scanner_running: scanner_running = False @@ -858,8 +838,6 @@ def start_audio() -> Response: scanner_config['device'] = device scanner_config['sdr_type'] = sdr_type - logger.info(f"Starting audio: freq={frequency} MHz, mod={modulation}, device={device}, gain={gain}, squelch={squelch}") - _start_audio_stream(frequency, modulation) if audio_running: @@ -895,8 +873,6 @@ def audio_status() -> Response: @listening_post_bp.route('/audio/stream') def stream_audio() -> Response: """Stream MP3 audio.""" - logger.info(f"Audio stream requested - running: {audio_running}, process: {audio_process is not None}") - # Wait for audio to be ready (up to 2 seconds for modulation/squelch changes) for _ in range(40): if audio_running and audio_process: @@ -904,71 +880,25 @@ def stream_audio() -> Response: time.sleep(0.05) if not audio_running or not audio_process: - logger.warning("Audio stream requested but no audio running") return Response(b'', mimetype='audio/mpeg', status=204) - # Check if process is still alive - poll_result = audio_process.poll() - logger.info(f"Audio process poll result: {poll_result} (None means running)") - - # Check for rtl_fm and ffmpeg errors - try: - with open('/tmp/rtl_fm_stderr.log', 'r') as f: - rtl_stderr = f.read().strip() - if rtl_stderr: - logger.warning(f"rtl_fm stderr (at stream request): {rtl_stderr}") - except: - pass - try: - with open('/tmp/ffmpeg_stderr.log', 'r') as f: - ffmpeg_stderr = f.read().strip() - if ffmpeg_stderr: - logger.warning(f"ffmpeg stderr (at stream request): {ffmpeg_stderr}") - except: - pass - def generate(): - bytes_sent = 0 - iterations = 0 - logger.info("Audio stream generator started") try: while audio_running and audio_process and audio_process.poll() is None: - iterations += 1 # Use select to avoid blocking forever ready, _, _ = select.select([audio_process.stdout], [], [], 2.0) if ready: chunk = audio_process.stdout.read(4096) if chunk: - bytes_sent += len(chunk) - if bytes_sent < 50000 or bytes_sent % 100000 < 4096: - logger.debug(f"Audio chunk: {len(chunk)} bytes, total: {bytes_sent}") yield chunk else: - logger.warning(f"Audio stream: empty chunk after {bytes_sent} bytes, iterations={iterations}") break else: - # Check raw rtl_fm output file size - raw_size = 0 - try: - raw_size = os.path.getsize('/tmp/rtl_fm_raw.bin') - except: - pass - logger.warning(f"Audio stream: select timeout after {bytes_sent} bytes, iterations={iterations}, poll={audio_process.poll()}, rtl_raw_size={raw_size}") - # Check for errors on timeout - try: - with open('/tmp/ffmpeg_stderr.log', 'r') as f: - ffmpeg_err = f.read().strip() - if ffmpeg_err: - logger.warning(f"ffmpeg stderr (timeout): {ffmpeg_err}") - except: - pass # Timeout - check if process died if audio_process.poll() is not None: - logger.warning(f"Audio process died during streaming after {bytes_sent} bytes") break - logger.info(f"Audio stream ended - sent {bytes_sent} bytes, iterations={iterations}, running={audio_running}, poll={audio_process.poll() if audio_process else 'N/A'}") except GeneratorExit: - logger.info(f"Audio stream: client disconnected after {bytes_sent} bytes") + pass except Exception as e: logger.error(f"Audio stream error: {e}") diff --git a/templates/adsb_dashboard.html b/templates/adsb_dashboard.html index 4e49a37..7f0ae52 100644 --- a/templates/adsb_dashboard.html +++ b/templates/adsb_dashboard.html @@ -257,7 +257,7 @@
SQ - + VOL
@@ -3221,6 +3221,14 @@ sudo make install } } + function updateAirbandSquelch() { + // If airband is playing, restart with new squelch value + if (isAirbandPlaying) { + stopAirband(); + setTimeout(() => startAirband(), 300); + } + } + // Initialize airband on page load document.addEventListener('DOMContentLoaded', initAirband);