feat: add QoS controls for presentation delay and retransmission settings

This commit is contained in:
pstruebi
2025-10-01 17:05:15 +02:00
parent 4d84d727f9
commit 89de05b812
2 changed files with 71 additions and 5 deletions
+50 -5
View File
@@ -154,7 +154,7 @@ if audio_mode == "Demo":
type=("password"),
help="Optional: Set a broadcast code to protect your stream. Leave empty for an open (uncoded) broadcast."
)
col_flags1, col_flags2, col_placeholder = st.columns([1, 1, 2])
col_flags1, col_flags2, col_pdelay, col_rtn = st.columns([1, 1, 1, 1], gap="small")
with col_flags1:
assisted_listening = st.checkbox(
"Assistive listening",
@@ -165,6 +165,20 @@ if audio_mode == "Demo":
"Immediate rendering",
value=bool(saved_settings.get('immediate_rendering', False))
)
# QoS/presentation controls inline with flags
default_pdelay = int(saved_settings.get('presentation_delay_us', 40000) or 40000)
with col_pdelay:
presentation_delay_us = st.number_input(
"Presentation delay (µs)",
min_value=10000, max_value=200000, step=1000, value=default_pdelay,
help="Delay between capture and presentation for receivers."
)
default_rtn = int(saved_settings.get('rtn', 4) or 4)
with col_rtn:
rtn = st.selectbox(
"Retransmissions (RTN)", options=[0,1,2,3,4], index=[0,1,2,3,4].index(default_rtn),
help="Number of ISO retransmissions (higher improves robustness at cost of airtime)."
)
#st.info(f"Demo mode selected: {demo_selected} (Streams: {demo_stream_map[demo_selected]['streams']}, Rate: {demo_stream_map[demo_selected]['rate']} Hz)")
# Start/Stop buttons for demo mode
if 'demo_stream_started' not in st.session_state:
@@ -215,9 +229,15 @@ if audio_mode == "Demo":
config1 = auracast_config.AuracastConfigGroup(
auracast_sampling_rate_hz=q['rate'],
octets_per_frame=q['octets'],
transport='', # is set in backend
transport='', # is set in baccol_qoskend
assisted_listening_stream=assisted_listening,
immediate_rendering=immediate_rendering,
presentation_delay_us=presentation_delay_us,
qos_config=auracast_config.AuracastQoSConfig(
iso_int_multiple_10ms=1,
number_of_retransmissions=int(rtn),
max_transport_latency_ms=int(rtn)*10 + 3,
),
bigs=bigs1
)
config2 = None
@@ -228,6 +248,12 @@ if audio_mode == "Demo":
transport='', # is set in backend
assisted_listening_stream=assisted_listening,
immediate_rendering=immediate_rendering,
presentation_delay_us=presentation_delay_us,
qos_config=auracast_config.AuracastQoSConfig(
iso_int_multiple_10ms=1,
number_of_retransmissions=int(rtn),
max_transport_latency_ms=int(rtn)*10 + 3,
),
bigs=bigs2
)
# Call /init and /init2
@@ -306,8 +332,8 @@ else:
type="password",
help="Optional: Set a broadcast code to protect your stream. Leave empty for an open (uncoded) broadcast."
)
# Flags: Assistive Listening and Immediate Rendering (one row)
col_flags1, col_flags2, col_placeholder = st.columns([1, 1, 2])
# Flags and QoS row (compact, four columns)
col_flags1, col_flags2, col_pdelay, col_rtn = st.columns([1, 1, 1, 1], gap="small")
with col_flags1:
assisted_listening = st.checkbox(
"Assistive listening",
@@ -318,6 +344,20 @@ else:
"Immediate rendering",
value=bool(saved_settings.get('immediate_rendering', False))
)
# QoS/presentation controls inline with flags
default_pdelay = int(saved_settings.get('presentation_delay_us', 40000) or 40000)
with col_pdelay:
presentation_delay_us = st.number_input(
"Presentation delay (µs)",
min_value=10000, max_value=200000, step=1000, value=default_pdelay,
help="Delay between capture and presentation for receivers."
)
default_rtn = int(saved_settings.get('rtn', 4) or 4)
with col_rtn:
rtn = st.selectbox(
"Retransmissions (RTN)", options=[0,1,2,3,4], index=[0,1,2,3,4].index(default_rtn),
help="Number of ISO retransmissions (higher improves robustness at cost of airtime)."
)
# Gain slider for Webapp mode
if audio_mode == "Webapp":
mic_gain = st.slider("Microphone Gain", 0.0, 2.0, 1.0, 0.1, help="Adjust microphone volume sent to Auracast")
@@ -464,7 +504,12 @@ else:
transport='', # is set in backend
assisted_listening_stream=assisted_listening,
immediate_rendering=immediate_rendering,
presentation_delay_us=40000,
presentation_delay_us=presentation_delay_us,
qos_config=auracast_config.AuracastQoSConfig(
iso_int_multiple_10ms=1,
number_of_retransmissions=int(rtn),
max_transport_latency_ms=int(rtn)*10 + 3,
),
bigs = [
auracast_config.AuracastBigConfig(
code=(stream_passwort.strip() or None),
+21
View File
@@ -200,6 +200,10 @@ class StreamerWorker:
for big in conf.bigs:
big.input_format = f"int16le,{capture_rate},{channels}"
# Coerce QoS: compute max_transport_latency from RTN if qos_config present
if getattr(conf, 'qos_config', None) and getattr(conf.qos_config, 'number_of_retransmissions', None) is not None:
conf.qos_config.max_transport_latency_ms = int(conf.qos_config.number_of_retransmissions) * 10 + 3
# Create and init multicaster1
self._multicaster1 = multicast_control.Multicaster(conf, conf.bigs)
await reset_nrf54l(1)
@@ -219,6 +223,8 @@ class StreamerWorker:
'gain': [getattr(big, 'input_gain', 1.0) for big in conf.bigs],
'auracast_sampling_rate_hz': conf.auracast_sampling_rate_hz,
'octets_per_frame': conf.octets_per_frame,
'presentation_delay_us': getattr(conf, 'presentation_delay_us', None),
'rtn': getattr(getattr(conf, 'qos_config', None), 'number_of_retransmissions', None),
'immediate_rendering': getattr(conf, 'immediate_rendering', False),
'assisted_listening_stream': getattr(conf, 'assisted_listening_stream', False),
'stream_password': (conf.bigs[0].code if conf.bigs and getattr(conf.bigs[0], 'code', None) else None),
@@ -241,6 +247,11 @@ class StreamerWorker:
if device_index is None:
raise HTTPException(status_code=400, detail=f"Audio device '{device_name}' not found.")
big.audio_source = f'device:{device_index}'
# Coerce QoS: compute max_transport_latency from RTN if qos_config present
if getattr(conf, 'qos_config', None) and getattr(conf.qos_config, 'number_of_retransmissions', None) is not None:
conf.qos_config.max_transport_latency_ms = int(conf.qos_config.number_of_retransmissions) * 10 + 3
self._multicaster2 = multicast_control.Multicaster(conf, conf.bigs)
await reset_nrf54l(0)
await self._multicaster2.init_broadcast()
@@ -379,6 +390,8 @@ async def _autostart_from_settings():
input_device_name = settings.get('input_device')
rate = settings.get('auracast_sampling_rate_hz')
octets = settings.get('octets_per_frame')
pres_delay = settings.get('presentation_delay_us')
saved_rtn = settings.get('rtn')
immediate_rendering = settings.get('immediate_rendering', False)
assisted_listening_stream = settings.get('assisted_listening_stream', False)
channel_names = settings.get('channel_names') or ["Broadcast0"]
@@ -442,8 +455,16 @@ async def _autostart_from_settings():
transport=TRANSPORT1,
immediate_rendering=immediate_rendering,
assisted_listening_stream=assisted_listening_stream,
presentation_delay_us=pres_delay if pres_delay is not None else 40000,
bigs=bigs,
)
# Attach QoS if saved_rtn present
conf.qos_config = auracast_config.AuracastQoSConfig(
iso_int_multiple_10ms=1,
number_of_retransmissions=int(saved_rtn),
max_transport_latency_ms=int(saved_rtn) * 10 + 3,
)
# Initialize and start
await asyncio.sleep(0.5)
await initialize(conf)