UI changes: Block everything while streaming (basically read only). Move start stop buttons for demo.
This commit is contained in:
@@ -163,6 +163,7 @@ audio_mode = st.selectbox(
|
||||
"Audio Mode",
|
||||
options,
|
||||
index=options.index(saved_audio_mode) if saved_audio_mode in options else options.index("Demo"),
|
||||
disabled=is_streaming,
|
||||
help=(
|
||||
"Select the audio input source. Choose 'USB' for a connected USB audio device (via PipeWire), "
|
||||
"'Network' (AES67) for network RTP/AES67 sources, "
|
||||
@@ -192,10 +193,10 @@ else:
|
||||
running_mode = backend_mode_mapped if (is_streaming and backend_mode_mapped) else audio_mode
|
||||
|
||||
# Start/Stop buttons and status (moved to top)
|
||||
if audio_mode != "Demo":
|
||||
start_stream, stop_stream = render_stream_controls(is_streaming, "Start Auracast", "Stop Auracast", running_mode, secondary_is_streaming)
|
||||
if audio_mode == "Demo":
|
||||
start_stream, stop_stream = render_stream_controls(is_streaming, "Start Demo", "Stop Demo", running_mode, secondary_is_streaming)
|
||||
else:
|
||||
start_stream, stop_stream = False, False
|
||||
start_stream, stop_stream = render_stream_controls(is_streaming, "Start Auracast", "Stop Auracast", running_mode, secondary_is_streaming)
|
||||
|
||||
# Placeholder for validation errors (will be filled in later)
|
||||
validation_error_placeholder = st.empty()
|
||||
@@ -238,6 +239,7 @@ if audio_mode == "Demo":
|
||||
"Demo Stream Type",
|
||||
demo_options,
|
||||
index=default_index,
|
||||
disabled=is_streaming,
|
||||
help="Select the demo stream configuration."
|
||||
)
|
||||
# Stream password and flags (same as USB/AES67)
|
||||
@@ -246,6 +248,7 @@ if audio_mode == "Demo":
|
||||
"Stream Passwort",
|
||||
value=saved_pwd,
|
||||
type=("password"),
|
||||
disabled=is_streaming,
|
||||
help="Optional: Set a broadcast code to protect your stream. Leave empty for an open (uncoded) broadcast."
|
||||
)
|
||||
col_flags1, col_flags2, col_pdelay, col_qos = st.columns([1, 1, 0.7, 0.6], gap="small", vertical_alignment="center")
|
||||
@@ -253,12 +256,14 @@ if audio_mode == "Demo":
|
||||
assisted_listening = st.checkbox(
|
||||
"Assistive listening",
|
||||
value=bool(saved_settings.get('assisted_listening_stream', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver that this is an assistive listening stream"
|
||||
)
|
||||
with col_flags2:
|
||||
immediate_rendering = st.checkbox(
|
||||
"Immediate rendering",
|
||||
value=bool(saved_settings.get('immediate_rendering', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver to ignore presentation delay and render immediately if possible."
|
||||
)
|
||||
# QoS/presentation controls inline with flags
|
||||
@@ -268,6 +273,7 @@ if audio_mode == "Demo":
|
||||
presentation_delay_ms = st.number_input(
|
||||
"Delay (ms)",
|
||||
min_value=10, max_value=200, step=5, value=default_pdelay_ms,
|
||||
disabled=is_streaming,
|
||||
help="Delay between capture and presentation for receivers."
|
||||
)
|
||||
with col_qos:
|
||||
@@ -276,103 +282,10 @@ if audio_mode == "Demo":
|
||||
default_qos_idx = qos_options.index(saved_qos) if saved_qos in qos_options else 0
|
||||
qos_preset = st.selectbox(
|
||||
"QoS", options=qos_options, index=default_qos_idx,
|
||||
disabled=is_streaming,
|
||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||
)
|
||||
#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:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
start_demo, stop_demo = render_stream_controls(is_streaming, "Start Demo", "Stop Demo", running_mode, secondary_is_streaming)
|
||||
if start_demo:
|
||||
# Always stop any running stream for clean state
|
||||
try:
|
||||
requests.post(f"{BACKEND_URL}/stop_audio").json()
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(1)
|
||||
demo_cfg = demo_stream_map[demo_selected]
|
||||
# Octets per frame logic matches quality_map
|
||||
q = QUALITY_MAP[demo_cfg['quality']]
|
||||
|
||||
# Language configs and test files
|
||||
lang_cfgs = [
|
||||
(auracast_config.AuracastBigConfigDeu, 'de'),
|
||||
(auracast_config.AuracastBigConfigEng, 'en'),
|
||||
(auracast_config.AuracastBigConfigFra, 'fr'),
|
||||
(auracast_config.AuracastBigConfigSpa, 'es'),
|
||||
(auracast_config.AuracastBigConfigIta, 'it'),
|
||||
(auracast_config.AuracastBigConfigPol, 'pl'),
|
||||
]
|
||||
bigs1 = []
|
||||
for i in range(demo_cfg['streams']):
|
||||
cfg_cls, lang = lang_cfgs[i % len(lang_cfgs)]
|
||||
bigs1.append(cfg_cls(
|
||||
code=(stream_passwort.strip() or None),
|
||||
audio_source=f'file:../testdata/wave_particle_5min_{lang}_{int(q["rate"]/1000)}kHz_mono.wav',
|
||||
iso_que_len=32,
|
||||
sampling_frequency=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
))
|
||||
|
||||
# Split bigs into two configs if needed
|
||||
max_per_mc = {48000: 1, 24000: 2, 16000: 3}
|
||||
max_streams = max_per_mc.get(q['rate'], 3)
|
||||
bigs2 = []
|
||||
if len(bigs1) > max_streams:
|
||||
bigs2 = bigs1[max_streams:]
|
||||
bigs1 = bigs1[:max_streams]
|
||||
config1 = auracast_config.AuracastConfigGroup(
|
||||
auracast_sampling_rate_hz=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
transport='', # is set in baccol_qoskend
|
||||
assisted_listening_stream=assisted_listening,
|
||||
immediate_rendering=immediate_rendering,
|
||||
presentation_delay_us=int(presentation_delay_ms * 1000),
|
||||
qos_config=QOS_PRESET_MAP[qos_preset],
|
||||
bigs=bigs1
|
||||
)
|
||||
config2 = None
|
||||
if bigs2:
|
||||
config2 = auracast_config.AuracastConfigGroup(
|
||||
auracast_sampling_rate_hz=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
transport='', # is set in backend
|
||||
assisted_listening_stream=assisted_listening,
|
||||
immediate_rendering=immediate_rendering,
|
||||
presentation_delay_us=int(presentation_delay_ms * 1000),
|
||||
qos_config=QOS_PRESET_MAP[qos_preset],
|
||||
bigs=bigs2
|
||||
)
|
||||
# Call /init and /init2
|
||||
is_started = False
|
||||
try:
|
||||
r1 = requests.post(f"{BACKEND_URL}/init", json=config1.model_dump())
|
||||
if r1.status_code == 200:
|
||||
st.session_state['demo_stream_started'] = True
|
||||
is_started = True
|
||||
else:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
st.error(f"Failed to initialize multicaster 1: {r1.text}")
|
||||
if config2:
|
||||
r2 = requests.post(f"{BACKEND_URL}/init2", json=config2.model_dump())
|
||||
if r2.status_code == 200:
|
||||
is_started = True
|
||||
else:
|
||||
st.error(f"Failed to initialize multicaster 2: {r2.text}")
|
||||
except Exception as e:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
st.error(f"Error: {e}")
|
||||
if is_started:
|
||||
pass
|
||||
elif stop_demo:
|
||||
try:
|
||||
r = requests.post(f"{BACKEND_URL}/stop_audio").json()
|
||||
st.session_state['demo_stream_started'] = False
|
||||
if r.get('was_running'):
|
||||
is_stopped = True
|
||||
except Exception as e:
|
||||
st.error(f"Error: {e}")
|
||||
|
||||
quality = None # Not used in demo mode
|
||||
else:
|
||||
# --- Mode-specific configuration ---
|
||||
@@ -395,14 +308,6 @@ else:
|
||||
with st.container(border=True):
|
||||
st.subheader("Radio 1")
|
||||
|
||||
# Stereo mode toggle for analog
|
||||
stereo_enabled = st.checkbox(
|
||||
"🎧 Stereo Mode",
|
||||
value=bool(saved_settings.get('analog_stereo_mode', False)),
|
||||
help="Enable stereo streaming for analog inputs. When enabled, ch1 becomes left channel and ch2 becomes right channel in a single stereo stream. Radio 2 will be disabled in stereo mode.",
|
||||
disabled=is_streaming
|
||||
)
|
||||
|
||||
# Always-enabled checkbox for Radio 1
|
||||
st.checkbox(
|
||||
"Radio 1 always enabled",
|
||||
@@ -411,6 +316,14 @@ else:
|
||||
help="Radio 1 is always enabled, Radio 2 can be turned on or off."
|
||||
)
|
||||
|
||||
# Stereo mode toggle for analog
|
||||
stereo_enabled = st.checkbox(
|
||||
"🎧 Stereo Mode",
|
||||
value=bool(saved_settings.get('analog_stereo_mode', False)),
|
||||
help="Enable stereo streaming for analog inputs. When enabled, ch1 becomes left channel and ch2 becomes right channel in a single stereo stream. Radio 2 will be disabled in stereo mode.",
|
||||
disabled=is_streaming
|
||||
)
|
||||
|
||||
# Use analog-specific defaults (not from saved settings which may have Dante values)
|
||||
default_name = "Analog_Radio_1"
|
||||
default_program_info = "Analog Radio Broadcast"
|
||||
@@ -422,6 +335,7 @@ else:
|
||||
"Stream Quality (Radio 1)",
|
||||
quality_options,
|
||||
index=quality_options.index(default_quality),
|
||||
disabled=is_streaming,
|
||||
help="Select the audio sampling rate for Radio 1."
|
||||
)
|
||||
|
||||
@@ -429,6 +343,7 @@ else:
|
||||
"Stream Passwort (Radio 1)",
|
||||
value="",
|
||||
type="password",
|
||||
disabled=is_streaming,
|
||||
help="Optional: Set a broadcast code for Radio 1."
|
||||
)
|
||||
|
||||
@@ -437,12 +352,14 @@ else:
|
||||
assisted_listening1 = st.checkbox(
|
||||
"Assistive listening (R1)",
|
||||
value=bool(saved_settings.get('assisted_listening_stream', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver that this is an assistive listening stream"
|
||||
)
|
||||
with col_r1_flags2:
|
||||
immediate_rendering1 = st.checkbox(
|
||||
"Immediate rendering (R1)",
|
||||
value=bool(saved_settings.get('immediate_rendering', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver to ignore presentation delay and render immediately if possible."
|
||||
)
|
||||
default_pdelay = int(saved_settings.get('presentation_delay_us', 40000) or 40000)
|
||||
@@ -451,6 +368,7 @@ else:
|
||||
presentation_delay_ms1 = st.number_input(
|
||||
"Delay (ms, R1)",
|
||||
min_value=10, max_value=200, step=5, value=default_pdelay_ms,
|
||||
disabled=is_streaming,
|
||||
help="Delay between capture and presentation for Radio 1."
|
||||
)
|
||||
with col_r1_qos:
|
||||
@@ -459,6 +377,7 @@ else:
|
||||
default_qos_idx = qos_options.index(saved_qos) if saved_qos in qos_options else 0
|
||||
qos_preset1 = st.selectbox(
|
||||
"QoS (R1)", options=qos_options, index=default_qos_idx,
|
||||
disabled=is_streaming,
|
||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||
)
|
||||
|
||||
@@ -467,17 +386,20 @@ else:
|
||||
stream_name1 = st.text_input(
|
||||
"Channel Name (Radio 1)",
|
||||
value=default_name,
|
||||
disabled=is_streaming,
|
||||
help="Name for the first analog radio (Radio 1)."
|
||||
)
|
||||
with col_r1_lang:
|
||||
language1 = st.text_input(
|
||||
"Language (ISO 639-3) (Radio 1)",
|
||||
value=default_lang,
|
||||
disabled=is_streaming,
|
||||
help="Language code for Radio 1."
|
||||
)
|
||||
program_info1 = st.text_input(
|
||||
"Program Info (Radio 1)",
|
||||
value=default_program_info,
|
||||
disabled=is_streaming,
|
||||
help="Program information for Radio 1."
|
||||
)
|
||||
|
||||
@@ -517,6 +439,7 @@ else:
|
||||
"Input Device (Radio 1) - Stereo",
|
||||
['ch1 + ch2 (Stereo: Left+Right channels)'],
|
||||
index=0,
|
||||
disabled=is_streaming,
|
||||
help="Stereo mode: Captures both ch1 (left) and ch2 (right) as a single stereo stream"
|
||||
)
|
||||
st.info("🎧 Stereo mode enabled - both ch1 and ch2 will be captured as left/right channels")
|
||||
@@ -530,6 +453,7 @@ else:
|
||||
"Input Device (Radio 1)",
|
||||
analog_names,
|
||||
index=default_r1_idx,
|
||||
disabled=is_streaming,
|
||||
)
|
||||
else:
|
||||
input_device1 = None
|
||||
@@ -568,6 +492,7 @@ else:
|
||||
radio2_enabled = st.checkbox(
|
||||
"Enable Radio 2",
|
||||
value=radio2_enabled_default,
|
||||
disabled=is_streaming,
|
||||
help="Activate a second analog radio with its own quality and timing settings."
|
||||
)
|
||||
|
||||
@@ -581,6 +506,7 @@ else:
|
||||
"Stream Quality (Radio 2)",
|
||||
quality_options,
|
||||
index=quality_options.index(default_quality),
|
||||
disabled=is_streaming,
|
||||
help="Select the audio sampling rate for Radio 2."
|
||||
)
|
||||
|
||||
@@ -588,6 +514,7 @@ else:
|
||||
"Stream Passwort (Radio 2)",
|
||||
value="",
|
||||
type="password",
|
||||
disabled=is_streaming,
|
||||
help="Optional: Set a broadcast code for Radio 2."
|
||||
)
|
||||
|
||||
@@ -596,18 +523,21 @@ else:
|
||||
assisted_listening2 = st.checkbox(
|
||||
"Assistive listening (R2)",
|
||||
value=bool(saved_settings.get('assisted_listening_stream', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver that this is an assistive listening stream"
|
||||
)
|
||||
with col_r2_flags2:
|
||||
immediate_rendering2 = st.checkbox(
|
||||
"Immediate rendering (R2)",
|
||||
value=bool(saved_settings.get('immediate_rendering', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver to ignore presentation delay and render immediately if possible."
|
||||
)
|
||||
with col_r2_pdelay:
|
||||
presentation_delay_ms2 = st.number_input(
|
||||
"Delay (ms, R2)",
|
||||
min_value=10, max_value=200, step=5, value=default_pdelay_ms,
|
||||
disabled=is_streaming,
|
||||
help="Delay between capture and presentation for Radio 2."
|
||||
)
|
||||
with col_r2_qos:
|
||||
@@ -615,6 +545,7 @@ else:
|
||||
default_qos_idx2 = qos_options.index(saved_qos2) if saved_qos2 in qos_options else 0
|
||||
qos_preset2 = st.selectbox(
|
||||
"QoS (R2)", options=qos_options, index=default_qos_idx2,
|
||||
disabled=is_streaming,
|
||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||
)
|
||||
|
||||
@@ -623,17 +554,20 @@ else:
|
||||
stream_name2 = st.text_input(
|
||||
"Channel Name (Radio 2)",
|
||||
value=default_name_r2,
|
||||
disabled=is_streaming,
|
||||
help="Name for the second analog radio (Radio 2)."
|
||||
)
|
||||
with col_r2_lang:
|
||||
language2 = st.text_input(
|
||||
"Language (ISO 639-3) (Radio 2)",
|
||||
value=default_lang_r2,
|
||||
disabled=is_streaming,
|
||||
help="Language code for Radio 2."
|
||||
)
|
||||
program_info2 = st.text_input(
|
||||
"Program Info (Radio 2)",
|
||||
value=default_program_info_r2,
|
||||
disabled=is_streaming,
|
||||
help="Program information for Radio 2."
|
||||
)
|
||||
|
||||
@@ -644,6 +578,7 @@ else:
|
||||
"Input Device (Radio 2)",
|
||||
analog_names,
|
||||
index=default_r2_idx,
|
||||
disabled=is_streaming,
|
||||
)
|
||||
else:
|
||||
input_device2 = None
|
||||
@@ -791,6 +726,7 @@ else:
|
||||
"Stream Configuration (Radio 1)",
|
||||
r1_stream_options,
|
||||
index=default_r1_idx,
|
||||
disabled=is_streaming,
|
||||
help="Select the number and quality of streams for Radio 1"
|
||||
)
|
||||
|
||||
@@ -815,6 +751,7 @@ else:
|
||||
"Stream Quality (Radio 1)",
|
||||
r1_available_qualities,
|
||||
index=r1_available_qualities.index(saved_r1_quality),
|
||||
disabled=is_streaming,
|
||||
help=f"Select stream quality for Radio 1. Maximum quality based on configuration: {r1_max_quality}"
|
||||
)
|
||||
|
||||
@@ -826,6 +763,7 @@ else:
|
||||
r1_assisted_listening = st.checkbox(
|
||||
"Assistive (R1)",
|
||||
value=bool(saved_r1_config.get('assisted_listening', False)),
|
||||
disabled=is_streaming,
|
||||
help="Assistive listening stream"
|
||||
)
|
||||
|
||||
@@ -833,6 +771,7 @@ else:
|
||||
r1_immediate_rendering = st.checkbox(
|
||||
"Immediate (R1)",
|
||||
value=bool(saved_r1_config.get('immediate_rendering', False)),
|
||||
disabled=is_streaming,
|
||||
help="Ignore presentation delay"
|
||||
)
|
||||
|
||||
@@ -842,6 +781,7 @@ else:
|
||||
r1_presentation_delay_ms = st.number_input(
|
||||
"Delay (ms, R1)",
|
||||
min_value=10, max_value=200, step=5, value=default_pdelay_ms,
|
||||
disabled=is_streaming,
|
||||
help="Presentation delay for Radio 1"
|
||||
)
|
||||
|
||||
@@ -851,6 +791,7 @@ else:
|
||||
default_qos_idx = qos_options.index(saved_qos) if saved_qos in qos_options else 0
|
||||
r1_qos_preset = st.selectbox(
|
||||
"QoS (R1)", options=qos_options, index=default_qos_idx,
|
||||
disabled=is_streaming,
|
||||
help="Quality of Service preset for Radio 1"
|
||||
)
|
||||
|
||||
@@ -874,6 +815,7 @@ else:
|
||||
stream_name = st.text_input(
|
||||
"Channel Name",
|
||||
value=saved_stream.get('name', 'Dante_Stereo'),
|
||||
disabled=is_streaming,
|
||||
key="r1_stereo_name"
|
||||
)
|
||||
|
||||
@@ -882,6 +824,7 @@ else:
|
||||
"Stream Password",
|
||||
value=saved_stream.get('stream_password', ''),
|
||||
type="password",
|
||||
disabled=is_streaming,
|
||||
key="r1_stereo_password",
|
||||
help="Optional: Set a broadcast code for this stream"
|
||||
)
|
||||
@@ -893,6 +836,7 @@ else:
|
||||
program_info = st.text_input(
|
||||
"Program Info",
|
||||
value=saved_stream.get('program_info', 'Dante Stereo Broadcast'),
|
||||
disabled=is_streaming,
|
||||
key="r1_stereo_program"
|
||||
)
|
||||
|
||||
@@ -900,6 +844,7 @@ else:
|
||||
language = st.text_input(
|
||||
"Language",
|
||||
value=saved_stream.get('language', 'eng'),
|
||||
disabled=is_streaming,
|
||||
key="r1_stereo_lang",
|
||||
help="ISO 639-3 language code"
|
||||
)
|
||||
@@ -944,6 +889,7 @@ else:
|
||||
stream_name = st.text_input(
|
||||
f"Channel Name",
|
||||
value=saved_stream.get('name', f'Dante_R1_S{i+1}'),
|
||||
disabled=is_streaming,
|
||||
key=f"r1_stream_{i}_name"
|
||||
)
|
||||
|
||||
@@ -952,6 +898,7 @@ else:
|
||||
f"Stream Password",
|
||||
value=saved_stream.get('stream_password', ''),
|
||||
type="password",
|
||||
disabled=is_streaming,
|
||||
key=f"r1_stream_{i}_password",
|
||||
help="Optional: Set a broadcast code for this stream"
|
||||
)
|
||||
@@ -963,6 +910,7 @@ else:
|
||||
program_info = st.text_input(
|
||||
f"Program Info",
|
||||
value=saved_stream.get('program_info', f'Dante Radio 1 Stream {i+1}'),
|
||||
disabled=is_streaming,
|
||||
key=f"r1_stream_{i}_program"
|
||||
)
|
||||
|
||||
@@ -970,6 +918,7 @@ else:
|
||||
language = st.text_input(
|
||||
f"Language",
|
||||
value=saved_stream.get('language', 'eng'),
|
||||
disabled=is_streaming,
|
||||
key=f"r1_stream_{i}_lang",
|
||||
help="ISO 639-3 language code"
|
||||
)
|
||||
@@ -996,6 +945,7 @@ else:
|
||||
f"Input Device",
|
||||
input_options,
|
||||
index=input_options.index(default_input_label) if default_input_label in input_options else 0,
|
||||
disabled=is_streaming,
|
||||
key=f"r1_stream_{i}_device"
|
||||
)
|
||||
input_device = option_name_map.get(selected_option)
|
||||
@@ -1044,6 +994,7 @@ else:
|
||||
radio2_enabled = st.checkbox(
|
||||
"Enable Radio 2",
|
||||
value=radio2_enabled_default,
|
||||
disabled=is_streaming,
|
||||
help="Activate a second Dante radio with its own quality and timing settings."
|
||||
)
|
||||
|
||||
@@ -1057,6 +1008,7 @@ else:
|
||||
"Stream Configuration (Radio 2)",
|
||||
r2_stream_options,
|
||||
index=default_r2_idx,
|
||||
disabled=is_streaming,
|
||||
help="Select the number and quality of streams for Radio 2"
|
||||
)
|
||||
r2_num_streams = dante_stream_options[r2_stream_config]["streams"]
|
||||
@@ -1080,6 +1032,7 @@ else:
|
||||
"Stream Quality (Radio 2)",
|
||||
r2_available_qualities,
|
||||
index=r2_available_qualities.index(saved_r2_quality),
|
||||
disabled=is_streaming,
|
||||
help=f"Select stream quality for Radio 2. Maximum quality based on configuration: {r2_max_quality}"
|
||||
)
|
||||
|
||||
@@ -1091,6 +1044,7 @@ else:
|
||||
r2_assisted_listening = st.checkbox(
|
||||
"Assistive (R2)",
|
||||
value=bool(saved_r2_config.get('assisted_listening', False)),
|
||||
disabled=is_streaming,
|
||||
help="Assistive listening stream"
|
||||
)
|
||||
|
||||
@@ -1098,6 +1052,7 @@ else:
|
||||
r2_immediate_rendering = st.checkbox(
|
||||
"Immediate (R2)",
|
||||
value=bool(saved_r2_config.get('immediate_rendering', False)),
|
||||
disabled=is_streaming,
|
||||
help="Ignore presentation delay"
|
||||
)
|
||||
|
||||
@@ -1107,6 +1062,7 @@ else:
|
||||
r2_presentation_delay_ms = st.number_input(
|
||||
"Delay (ms, R2)",
|
||||
min_value=10, max_value=200, step=5, value=default_pdelay_ms,
|
||||
disabled=is_streaming,
|
||||
help="Presentation delay for Radio 2"
|
||||
)
|
||||
|
||||
@@ -1116,6 +1072,7 @@ else:
|
||||
default_qos_idx = qos_options.index(saved_qos) if saved_qos in qos_options else 0
|
||||
r2_qos_preset = st.selectbox(
|
||||
"QoS (R2)", options=qos_options, index=default_qos_idx,
|
||||
disabled=is_streaming,
|
||||
help="Quality of Service preset for Radio 2"
|
||||
)
|
||||
|
||||
@@ -1135,6 +1092,7 @@ else:
|
||||
stream_name = st.text_input(
|
||||
f"Channel Name",
|
||||
value=saved_stream.get('name', f'Dante_R2_S{i+1}'),
|
||||
disabled=is_streaming,
|
||||
key=f"r2_stream_{i}_name"
|
||||
)
|
||||
|
||||
@@ -1143,6 +1101,7 @@ else:
|
||||
f"Stream Password",
|
||||
value=saved_stream.get('stream_password', ''),
|
||||
type="password",
|
||||
disabled=is_streaming,
|
||||
key=f"r2_stream_{i}_password",
|
||||
help="Optional: Set a broadcast code for this stream"
|
||||
)
|
||||
@@ -1154,6 +1113,7 @@ else:
|
||||
program_info = st.text_input(
|
||||
f"Program Info",
|
||||
value=saved_stream.get('program_info', f'Dante Radio 2 Stream {i+1}'),
|
||||
disabled=is_streaming,
|
||||
key=f"r2_stream_{i}_program"
|
||||
)
|
||||
|
||||
@@ -1161,6 +1121,7 @@ else:
|
||||
language = st.text_input(
|
||||
f"Language",
|
||||
value=saved_stream.get('language', 'eng'),
|
||||
disabled=is_streaming,
|
||||
key=f"r2_stream_{i}_lang",
|
||||
help="ISO 639-3 language code"
|
||||
)
|
||||
@@ -1187,6 +1148,7 @@ else:
|
||||
f"Input Device",
|
||||
input_options,
|
||||
index=input_options.index(default_input_label) if default_input_label in input_options else 0,
|
||||
disabled=is_streaming,
|
||||
key=f"r2_stream_{i}_device"
|
||||
)
|
||||
input_device = option_name_map.get(selected_option)
|
||||
@@ -1285,6 +1247,7 @@ else:
|
||||
"Stream Quality (Sampling Rate)",
|
||||
quality_options,
|
||||
index=quality_options.index(default_quality),
|
||||
disabled=is_streaming,
|
||||
help="Select the audio sampling rate for the stream. Lower rates may improve compatibility."
|
||||
)
|
||||
|
||||
@@ -1292,6 +1255,7 @@ else:
|
||||
"Stream Passwort",
|
||||
value="",
|
||||
type="password",
|
||||
disabled=is_streaming,
|
||||
help="Optional: Set a broadcast code to protect your stream. Leave empty for an open (uncoded) broadcast."
|
||||
)
|
||||
|
||||
@@ -1300,12 +1264,14 @@ else:
|
||||
assisted_listening = st.checkbox(
|
||||
"Assistive listening",
|
||||
value=bool(saved_settings.get('assisted_listening_stream', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver that this is an assistive listening stream"
|
||||
)
|
||||
with col_flags2:
|
||||
immediate_rendering = st.checkbox(
|
||||
"Immediate rendering",
|
||||
value=bool(saved_settings.get('immediate_rendering', False)),
|
||||
disabled=is_streaming,
|
||||
help="tells the receiver to ignore presentation delay and render immediately if possible."
|
||||
)
|
||||
default_pdelay = int(saved_settings.get('presentation_delay_us', 40000) or 40000)
|
||||
@@ -1314,6 +1280,7 @@ else:
|
||||
presentation_delay_ms = st.number_input(
|
||||
"Delay (ms)",
|
||||
min_value=10, max_value=200, step=5, value=default_pdelay_ms,
|
||||
disabled=is_streaming,
|
||||
help="Delay between capture and presentation for receivers."
|
||||
)
|
||||
with col_qos:
|
||||
@@ -1322,22 +1289,26 @@ else:
|
||||
default_qos_idx = qos_options.index(saved_qos) if saved_qos in qos_options else 0
|
||||
qos_preset = st.selectbox(
|
||||
"QoS", options=qos_options, index=default_qos_idx,
|
||||
disabled=is_streaming,
|
||||
help="Fast: 2 retransmissions, lower latency. Robust: 4 retransmissions, better reliability."
|
||||
)
|
||||
|
||||
stream_name = st.text_input(
|
||||
"Channel Name",
|
||||
value=default_name,
|
||||
disabled=is_streaming,
|
||||
help="The primary name for your broadcast. Like the SSID of a WLAN, it identifies your stream for receivers."
|
||||
)
|
||||
program_info = st.text_input(
|
||||
"Program Info",
|
||||
value=default_program_info,
|
||||
disabled=is_streaming,
|
||||
help="Additional details about the broadcast program, such as its content or purpose. Shown to receivers for more context."
|
||||
)
|
||||
language = st.text_input(
|
||||
"Language (ISO 639-3)",
|
||||
value=default_lang,
|
||||
disabled=is_streaming,
|
||||
help="Three-letter language code (e.g., 'eng' for English, 'deu' for German). Used by receivers to display the language of the stream. See: https://en.wikipedia.org/wiki/List_of_ISO_639-3_codes"
|
||||
)
|
||||
|
||||
@@ -1424,6 +1395,8 @@ if stop_stream:
|
||||
st.session_state['stream_started'] = False
|
||||
try:
|
||||
r = requests.post(f"{BACKEND_URL}/stop_audio").json()
|
||||
if audio_mode == "Demo":
|
||||
st.session_state['demo_stream_started'] = False
|
||||
if r['was_running']:
|
||||
is_stopped = True
|
||||
except Exception as e:
|
||||
@@ -1436,6 +1409,77 @@ if start_stream:
|
||||
# Small pause lets backend fully release audio devices before re-init
|
||||
time.sleep(1)
|
||||
|
||||
if audio_mode == "Demo":
|
||||
demo_cfg = demo_stream_map[demo_selected]
|
||||
q = QUALITY_MAP[demo_cfg['quality']]
|
||||
|
||||
lang_cfgs = [
|
||||
(auracast_config.AuracastBigConfigDeu, 'de'),
|
||||
(auracast_config.AuracastBigConfigEng, 'en'),
|
||||
(auracast_config.AuracastBigConfigFra, 'fr'),
|
||||
(auracast_config.AuracastBigConfigSpa, 'es'),
|
||||
(auracast_config.AuracastBigConfigIta, 'it'),
|
||||
(auracast_config.AuracastBigConfigPol, 'pl'),
|
||||
]
|
||||
bigs1 = []
|
||||
for i in range(demo_cfg['streams']):
|
||||
cfg_cls, lang = lang_cfgs[i % len(lang_cfgs)]
|
||||
bigs1.append(cfg_cls(
|
||||
code=(stream_passwort.strip() or None),
|
||||
audio_source=f'file:../testdata/wave_particle_5min_{lang}_{int(q["rate"]/1000)}kHz_mono.wav',
|
||||
iso_que_len=32,
|
||||
sampling_frequency=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
))
|
||||
|
||||
max_per_mc = {48000: 1, 24000: 2, 16000: 3}
|
||||
max_streams = max_per_mc.get(q['rate'], 3)
|
||||
bigs2 = []
|
||||
if len(bigs1) > max_streams:
|
||||
bigs2 = bigs1[max_streams:]
|
||||
bigs1 = bigs1[:max_streams]
|
||||
config1 = auracast_config.AuracastConfigGroup(
|
||||
auracast_sampling_rate_hz=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
transport='',
|
||||
assisted_listening_stream=assisted_listening,
|
||||
immediate_rendering=immediate_rendering,
|
||||
presentation_delay_us=int(presentation_delay_ms * 1000),
|
||||
qos_config=QOS_PRESET_MAP[qos_preset],
|
||||
bigs=bigs1
|
||||
)
|
||||
config2 = None
|
||||
if bigs2:
|
||||
config2 = auracast_config.AuracastConfigGroup(
|
||||
auracast_sampling_rate_hz=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
transport='',
|
||||
assisted_listening_stream=assisted_listening,
|
||||
immediate_rendering=immediate_rendering,
|
||||
presentation_delay_us=int(presentation_delay_ms * 1000),
|
||||
qos_config=QOS_PRESET_MAP[qos_preset],
|
||||
bigs=bigs2
|
||||
)
|
||||
|
||||
is_started = False
|
||||
try:
|
||||
r1 = requests.post(f"{BACKEND_URL}/init", json=config1.model_dump())
|
||||
if r1.status_code == 200:
|
||||
st.session_state['demo_stream_started'] = True
|
||||
is_started = True
|
||||
else:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
st.error(f"Failed to initialize multicaster 1: {r1.text}")
|
||||
if config2:
|
||||
r2 = requests.post(f"{BACKEND_URL}/init2", json=config2.model_dump())
|
||||
if r2.status_code == 200:
|
||||
is_started = True
|
||||
else:
|
||||
st.error(f"Failed to initialize multicaster 2: {r2.text}")
|
||||
except Exception as e:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
st.error(f"Error: {e}")
|
||||
|
||||
if audio_mode == "Analog":
|
||||
# Build separate configs per radio, each with its own quality and QoS parameters.
|
||||
is_started = False
|
||||
@@ -1570,7 +1614,7 @@ if start_stream:
|
||||
st.error(f"Failed to initialize Dante Radio 2: {r2.text}")
|
||||
except Exception as e:
|
||||
st.error(f"Error while starting Dante radios: {e}")
|
||||
else:
|
||||
if audio_mode not in ("Demo", "Analog", "Network - Dante"):
|
||||
# USB/Network: single config as before, using shared controls
|
||||
q = QUALITY_MAP[quality]
|
||||
config = auracast_config.AuracastConfigGroup(
|
||||
|
||||
Reference in New Issue
Block a user