mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 14:50:00 -07:00
Fix digital voice decoder producing no output due to wrong dsd-fme flags
The _DSD_FME_PROTOCOL_FLAGS dictionary had every protocol flag wrong, causing dsd-fme (the preferred binary) to receive invalid or mismatched -f flags. Also fix orphaned process leak on startup failure and add centralized input validation for frequency/gain/device. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ from utils.logging import get_logger
|
|||||||
from utils.sse import format_sse
|
from utils.sse import format_sse
|
||||||
from utils.event_pipeline import process_event
|
from utils.event_pipeline import process_event
|
||||||
from utils.process import register_process, unregister_process
|
from utils.process import register_process, unregister_process
|
||||||
|
from utils.validation import validate_frequency, validate_gain, validate_device_index
|
||||||
from utils.constants import (
|
from utils.constants import (
|
||||||
SSE_QUEUE_TIMEOUT,
|
SSE_QUEUE_TIMEOUT,
|
||||||
SSE_KEEPALIVE_INTERVAL,
|
SSE_KEEPALIVE_INTERVAL,
|
||||||
@@ -56,12 +57,12 @@ _DSD_PROTOCOL_FLAGS = {
|
|||||||
|
|
||||||
# dsd-fme uses different flag names
|
# dsd-fme uses different flag names
|
||||||
_DSD_FME_PROTOCOL_FLAGS = {
|
_DSD_FME_PROTOCOL_FLAGS = {
|
||||||
'auto': ['-ft'],
|
'auto': [],
|
||||||
'dmr': ['-fs'],
|
'dmr': ['-fd'],
|
||||||
'p25': ['-f1'],
|
'p25': ['-fp'],
|
||||||
'nxdn': ['-fi'],
|
'nxdn': ['-fn'],
|
||||||
'dstar': [],
|
'dstar': ['-fi'],
|
||||||
'provoice': ['-fp'],
|
'provoice': ['-fv'],
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
@@ -321,16 +322,13 @@ def start_dmr() -> Response:
|
|||||||
data = request.json or {}
|
data = request.json or {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
frequency = float(data.get('frequency', 462.5625))
|
frequency = validate_frequency(data.get('frequency', 462.5625))
|
||||||
gain = int(data.get('gain', 40))
|
gain = int(validate_gain(data.get('gain', 40)))
|
||||||
device = int(data.get('device', 0))
|
device = validate_device_index(data.get('device', 0))
|
||||||
protocol = str(data.get('protocol', 'auto')).lower()
|
protocol = str(data.get('protocol', 'auto')).lower()
|
||||||
except (ValueError, TypeError) as e:
|
except (ValueError, TypeError) as e:
|
||||||
return jsonify({'status': 'error', 'message': f'Invalid parameter: {e}'}), 400
|
return jsonify({'status': 'error', 'message': f'Invalid parameter: {e}'}), 400
|
||||||
|
|
||||||
if frequency <= 0:
|
|
||||||
return jsonify({'status': 'error', 'message': 'Frequency must be positive'}), 400
|
|
||||||
|
|
||||||
if protocol not in VALID_PROTOCOLS:
|
if protocol not in VALID_PROTOCOLS:
|
||||||
return jsonify({'status': 'error', 'message': f'Invalid protocol. Use: {", ".join(VALID_PROTOCOLS)}'}), 400
|
return jsonify({'status': 'error', 'message': f'Invalid protocol. Use: {", ".join(VALID_PROTOCOLS)}'}), 400
|
||||||
|
|
||||||
@@ -402,6 +400,21 @@ def start_dmr() -> Response:
|
|||||||
if dmr_dsd_process.stderr:
|
if dmr_dsd_process.stderr:
|
||||||
dsd_err = dmr_dsd_process.stderr.read().decode('utf-8', errors='replace')[:500]
|
dsd_err = dmr_dsd_process.stderr.read().decode('utf-8', errors='replace')[:500]
|
||||||
logger.error(f"DSD pipeline died: rtl_fm rc={rtl_rc} err={rtl_err!r}, dsd rc={dsd_rc} err={dsd_err!r}")
|
logger.error(f"DSD pipeline died: rtl_fm rc={rtl_rc} err={rtl_err!r}, dsd rc={dsd_rc} err={dsd_err!r}")
|
||||||
|
# Terminate surviving process and unregister both
|
||||||
|
for proc in [dmr_dsd_process, dmr_rtl_process]:
|
||||||
|
if proc and proc.poll() is None:
|
||||||
|
try:
|
||||||
|
proc.terminate()
|
||||||
|
proc.wait(timeout=2)
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
proc.kill()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if proc:
|
||||||
|
unregister_process(proc)
|
||||||
|
dmr_rtl_process = None
|
||||||
|
dmr_dsd_process = None
|
||||||
if dmr_active_device is not None:
|
if dmr_active_device is not None:
|
||||||
app_module.release_sdr_device(dmr_active_device)
|
app_module.release_sdr_device(dmr_active_device)
|
||||||
dmr_active_device = None
|
dmr_active_device = None
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
import pytest
|
import pytest
|
||||||
from routes.dmr import parse_dsd_output
|
from routes.dmr import parse_dsd_output, _DSD_PROTOCOL_FLAGS, _DSD_FME_PROTOCOL_FLAGS
|
||||||
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
@@ -98,6 +98,21 @@ def test_parse_unrecognized():
|
|||||||
assert result['text'] == 'some random text'
|
assert result['text'] == 'some random text'
|
||||||
|
|
||||||
|
|
||||||
|
def test_dsd_fme_protocol_flags_match_classic():
|
||||||
|
"""dsd-fme flags must match classic DSD flags (same fork, same CLI)."""
|
||||||
|
assert _DSD_FME_PROTOCOL_FLAGS == _DSD_PROTOCOL_FLAGS
|
||||||
|
|
||||||
|
|
||||||
|
def test_dsd_protocol_flags_known_values():
|
||||||
|
"""Protocol flags should map to the correct DSD -f flags."""
|
||||||
|
assert _DSD_PROTOCOL_FLAGS['dmr'] == ['-fd']
|
||||||
|
assert _DSD_PROTOCOL_FLAGS['p25'] == ['-fp']
|
||||||
|
assert _DSD_PROTOCOL_FLAGS['nxdn'] == ['-fn']
|
||||||
|
assert _DSD_PROTOCOL_FLAGS['dstar'] == ['-fi']
|
||||||
|
assert _DSD_PROTOCOL_FLAGS['provoice'] == ['-fv']
|
||||||
|
assert _DSD_PROTOCOL_FLAGS['auto'] == []
|
||||||
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Endpoint tests
|
# Endpoint tests
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|||||||
Reference in New Issue
Block a user