mirror of
https://github.com/smittix/intercept.git
synced 2026-06-08 14:11:54 -07:00
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 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -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}")
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
</select>
|
||||
<div class="airband-sliders">
|
||||
<span title="Squelch">SQ</span>
|
||||
<input type="range" id="airbandSquelch" min="0" max="100" value="20" class="airband-controls" title="Squelch">
|
||||
<input type="range" id="airbandSquelch" min="0" max="100" value="20" class="airband-controls" title="Squelch" onchange="updateAirbandSquelch()">
|
||||
<span title="Volume">VOL</span>
|
||||
<input type="range" id="airbandVolume" min="0" max="100" value="80" class="airband-controls" oninput="updateAirbandVolume()" title="Volume">
|
||||
</div>
|
||||
@@ -3221,6 +3221,14 @@ sudo make install</code>
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user