audio fixes attempt
CI / lint (push) Failing after 6s
CI / test (push) Successful in 19s
Build edge-node / build (push) Successful in 7m54s
Build op25 / build (push) Successful in 1h25m50s

This commit is contained in:
Logan
2026-05-23 14:59:48 -04:00
parent dccbab00d6
commit 16f6e0de95
4 changed files with 41 additions and 3 deletions
+9
View File
@@ -107,6 +107,7 @@ def _to_hz(freq) -> int:
async def _generate_op25_config(config: SystemConfig) -> bool: async def _generate_op25_config(config: SystemConfig) -> bool:
"""Translate a SystemConfig (Firestore format) into OP25 active.cfg.json + op25.liq.""" """Translate a SystemConfig (Firestore format) into OP25 active.cfg.json + op25.liq."""
from app.internal.op25_client import op25_client from app.internal.op25_client import op25_client
node_cfg = load_node_config()
raw = config.config raw = config.config
payload = { payload = {
"type": config.type, "type": config.type,
@@ -124,12 +125,16 @@ async def _generate_op25_config(config: SystemConfig) -> bool:
"icecast_mountpoint": settings.icecast_mount, "icecast_mountpoint": settings.icecast_mount,
"icecast_password": settings.icecast_source_password, "icecast_password": settings.icecast_source_password,
}, },
"hardware_preset": node_cfg.hardware_preset,
**({"ppm_override": node_cfg.ppm_override} if node_cfg.ppm_override is not None else {}),
} }
return await op25_client.generate_config(payload) return await op25_client.generate_config(payload)
async def on_config_push(payload: dict): async def on_config_push(payload: dict):
"""C2 pushes a system config — translate it to OP25 format and restart OP25.""" """C2 pushes a system config — translate it to OP25 format and restart OP25."""
hardware_preset = payload.pop("hardware_preset", None)
ppm_override = payload.pop("ppm_override", None)
try: try:
config = SystemConfig(**payload) config = SystemConfig(**payload)
except Exception as e: except Exception as e:
@@ -140,6 +145,10 @@ async def on_config_push(payload: dict):
node_cfg.assigned_system_id = config.system_id node_cfg.assigned_system_id = config.system_id
node_cfg.system_config = config node_cfg.system_config = config
node_cfg.configured = True node_cfg.configured = True
if hardware_preset is not None:
node_cfg.hardware_preset = hardware_preset
if ppm_override is not None:
node_cfg.ppm_override = float(ppm_override)
save_node_config(node_cfg) save_node_config(node_cfg)
from app.internal.op25_client import op25_client from app.internal.op25_client import op25_client
+2
View File
@@ -31,6 +31,8 @@ class NodeConfig(BaseModel):
assigned_system_id: Optional[str] = None assigned_system_id: Optional[str] = None
system_config: Optional[SystemConfig] = None system_config: Optional[SystemConfig] = None
configured: bool = False configured: bool = False
hardware_preset: str = "rtl-sdr-v3"
ppm_override: Optional[float] = None
class CallEvent(BaseModel): class CallEvent(BaseModel):
+25
View File
@@ -2,6 +2,29 @@ from pydantic import BaseModel
from typing import List, Optional, Union from typing import List, Optional, Union
from enum import Enum from enum import Enum
# Preset device settings for common RTL-SDR hardware.
# gains: OP25 gain string passed to the device block.
# ppm: frequency offset correction (user should calibrate and override).
# cqpsk_tracking: disable for TCXO dongles (RTL-SDR v3, NESDR) once PPM is dialled in;
# leave enabled for unknown hardware as a safety net.
HARDWARE_PRESETS: dict = {
"rtl-sdr-v3": {
"gains": "lna:34",
"ppm": 0.0,
"cqpsk_tracking": False,
},
"nesdr-smart-v4": {
"gains": "lna:32",
"ppm": 0.0,
"cqpsk_tracking": False,
},
"other": {
"gains": "lna:32",
"ppm": 0.0,
"cqpsk_tracking": True,
},
}
class DecodeMode(str, Enum): class DecodeMode(str, Enum):
P25 = "P25" P25 = "P25"
DMR = "DMR" DMR = "DMR"
@@ -18,6 +41,8 @@ class ConfigGenerator(BaseModel):
tags: Optional[List[TalkgroupTag]] tags: Optional[List[TalkgroupTag]]
whitelist: Optional[List[int]] whitelist: Optional[List[int]]
icecastConfig: Optional[IcecastConfig] icecastConfig: Optional[IcecastConfig]
hardware_preset: str = "rtl-sdr-v3"
ppm_override: Optional[float] = None # when set, overrides the preset's default PPM
class DemodType(str, Enum): class DemodType(str, Enum):
CQPSK = "cqpsk" CQPSK = "cqpsk"
@@ -3,7 +3,7 @@ import subprocess
import os import os
import signal import signal
import json import json
from models import ConfigGenerator, DecodeMode, ChannelConfig, DeviceConfig, TrunkingConfig, TrunkingChannelConfig, TerminalConfig, MetadataConfig, MetadataStreamConfig from models import ConfigGenerator, DecodeMode, ChannelConfig, DeviceConfig, TrunkingConfig, TrunkingChannelConfig, TerminalConfig, MetadataConfig, MetadataStreamConfig, HARDWARE_PRESETS
from internal.logger import create_logger from internal.logger import create_logger
from internal.op25_config_utls import save_talkgroup_tags, save_whitelist, del_none_in_dict, get_current_system_from_config from internal.op25_config_utls import save_talkgroup_tags, save_whitelist, del_none_in_dict, get_current_system_from_config
from internal.liquidsoap_config_utils import generate_liquid_script from internal.liquidsoap_config_utils import generate_liquid_script
@@ -73,16 +73,18 @@ def create_op25_router():
async def generate_config(generator: ConfigGenerator): async def generate_config(generator: ConfigGenerator):
try: try:
if generator.type == DecodeMode.P25: if generator.type == DecodeMode.P25:
preset = HARDWARE_PRESETS.get(generator.hardware_preset, HARDWARE_PRESETS["other"])
ppm = generator.ppm_override if generator.ppm_override is not None else preset["ppm"]
channels = [ChannelConfig( channels = [ChannelConfig(
name=generator.systemName, name=generator.systemName,
trunking_sysname=generator.systemName, trunking_sysname=generator.systemName,
enable_analog="off", enable_analog="off",
demod_type="cqpsk", demod_type="cqpsk",
cqpsk_tracking=True, cqpsk_tracking=preset["cqpsk_tracking"],
filter_type="rc", filter_type="rc",
meta_stream_name="stream_0" meta_stream_name="stream_0"
)] )]
devices = [DeviceConfig()] devices = [DeviceConfig(gains=preset["gains"], ppm=ppm)]
save_talkgroup_tags(generator.tags) save_talkgroup_tags(generator.tags)
save_whitelist(generator.whitelist) save_whitelist(generator.whitelist)
has_talkgroups = bool(generator.whitelist) has_talkgroups = bool(generator.whitelist)