mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Fix RTL-SDR device conflicts when running ADS-B and airband simultaneously
Problems fixed: 1. Added start_new_session=True to dump1090 Popen - creates proper process group for clean shutdown 2. Use os.killpg() to kill entire process group when stopping ADS-B - ensures child processes are terminated and device is released 3. Track active device index in adsb_active_device for debugging 4. Add device info to /adsb/status endpoint 5. Add logging when starting/stopping ADS-B with device info These changes ensure the RTL-SDR device is properly released when ADS-B stops, allowing another process (e.g., airband) to use a different device. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,7 @@ adsb_messages_received = 0
|
||||
adsb_last_message_time = None
|
||||
adsb_bytes_received = 0
|
||||
adsb_lines_received = 0
|
||||
adsb_active_device = None # Track which device index is being used
|
||||
|
||||
# Track ICAOs already looked up in aircraft database (avoid repeated lookups)
|
||||
_looked_up_icaos: set[str] = set()
|
||||
@@ -286,6 +287,7 @@ def adsb_status():
|
||||
|
||||
return jsonify({
|
||||
'tracking_active': adsb_using_service,
|
||||
'active_device': adsb_active_device,
|
||||
'connected_to_sbs': adsb_connected,
|
||||
'messages_received': adsb_messages_received,
|
||||
'bytes_received': adsb_bytes_received,
|
||||
@@ -303,7 +305,7 @@ def adsb_status():
|
||||
@adsb_bp.route('/start', methods=['POST'])
|
||||
def start_adsb():
|
||||
"""Start ADS-B tracking."""
|
||||
global adsb_using_service
|
||||
global adsb_using_service, adsb_active_device
|
||||
|
||||
with app_module.adsb_lock:
|
||||
if adsb_using_service:
|
||||
@@ -364,17 +366,20 @@ def start_adsb():
|
||||
if not dump1090_path:
|
||||
return jsonify({'status': 'error', 'message': f'readsb or dump1090 not found for {sdr_type.value}. Install readsb with SoapySDR support.'})
|
||||
|
||||
# Kill any stale app-started process
|
||||
# Kill any stale app-started process (use process group to ensure full cleanup)
|
||||
if app_module.adsb_process:
|
||||
try:
|
||||
app_module.adsb_process.terminate()
|
||||
pgid = os.getpgid(app_module.adsb_process.pid)
|
||||
os.killpg(pgid, 15) # SIGTERM
|
||||
app_module.adsb_process.wait(timeout=PROCESS_TERMINATE_TIMEOUT)
|
||||
except (subprocess.TimeoutExpired, OSError):
|
||||
except (subprocess.TimeoutExpired, ProcessLookupError, OSError):
|
||||
try:
|
||||
app_module.adsb_process.kill()
|
||||
except OSError:
|
||||
pgid = os.getpgid(app_module.adsb_process.pid)
|
||||
os.killpg(pgid, 9) # SIGKILL
|
||||
except (ProcessLookupError, OSError):
|
||||
pass
|
||||
app_module.adsb_process = None
|
||||
logger.info("Killed stale ADS-B process")
|
||||
|
||||
# Create device object and build command via abstraction layer
|
||||
sdr_device = SDRFactory.create_default_device(sdr_type, index=device)
|
||||
@@ -393,10 +398,12 @@ def start_adsb():
|
||||
cmd[0] = dump1090_path
|
||||
|
||||
try:
|
||||
logger.info(f"Starting dump1090 with device index {device}: {' '.join(cmd)}")
|
||||
app_module.adsb_process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.PIPE
|
||||
stderr=subprocess.PIPE,
|
||||
start_new_session=True # Create new process group for clean shutdown
|
||||
)
|
||||
|
||||
time.sleep(DUMP1090_START_WAIT)
|
||||
@@ -421,10 +428,11 @@ def start_adsb():
|
||||
return jsonify({'status': 'error', 'message': error_msg})
|
||||
|
||||
adsb_using_service = True
|
||||
adsb_active_device = device # Track which device is being used
|
||||
thread = threading.Thread(target=parse_sbs_stream, args=(f'localhost:{ADSB_SBS_PORT}',), daemon=True)
|
||||
thread.start()
|
||||
|
||||
return jsonify({'status': 'started', 'message': 'ADS-B tracking started'})
|
||||
return jsonify({'status': 'started', 'message': 'ADS-B tracking started', 'device': device})
|
||||
except Exception as e:
|
||||
return jsonify({'status': 'error', 'message': str(e)})
|
||||
|
||||
@@ -432,17 +440,26 @@ def start_adsb():
|
||||
@adsb_bp.route('/stop', methods=['POST'])
|
||||
def stop_adsb():
|
||||
"""Stop ADS-B tracking."""
|
||||
global adsb_using_service
|
||||
global adsb_using_service, adsb_active_device
|
||||
|
||||
with app_module.adsb_lock:
|
||||
if app_module.adsb_process:
|
||||
app_module.adsb_process.terminate()
|
||||
try:
|
||||
# Kill the entire process group to ensure all child processes are terminated
|
||||
pgid = os.getpgid(app_module.adsb_process.pid)
|
||||
os.killpg(pgid, 15) # SIGTERM
|
||||
app_module.adsb_process.wait(timeout=ADSB_TERMINATE_TIMEOUT)
|
||||
except subprocess.TimeoutExpired:
|
||||
app_module.adsb_process.kill()
|
||||
except (subprocess.TimeoutExpired, ProcessLookupError, OSError):
|
||||
try:
|
||||
# Force kill if terminate didn't work
|
||||
pgid = os.getpgid(app_module.adsb_process.pid)
|
||||
os.killpg(pgid, 9) # SIGKILL
|
||||
except (ProcessLookupError, OSError):
|
||||
pass
|
||||
app_module.adsb_process = None
|
||||
logger.info("ADS-B process stopped")
|
||||
adsb_using_service = False
|
||||
adsb_active_device = None
|
||||
|
||||
app_module.adsb_aircraft.clear()
|
||||
_looked_up_icaos.clear()
|
||||
|
||||
Reference in New Issue
Block a user