refactor: streamline system control UI and persist streaming state across restarts
This commit is contained in:
@@ -438,8 +438,8 @@ else:
|
||||
if start_stream:
|
||||
# Always send stop to ensure backend is in a clean state, regardless of current status
|
||||
r = requests.post(f"{BACKEND_URL}/stop_audio").json()
|
||||
if r['was_running']:
|
||||
st.success("Stream Stopped!")
|
||||
#if r['was_running']:
|
||||
# st.success("Stream Stopped!")
|
||||
|
||||
# Small pause lets backend fully release audio devices before re-init
|
||||
time.sleep(1)
|
||||
@@ -551,21 +551,12 @@ else:
|
||||
############################
|
||||
# System expander (collapsed)
|
||||
############################
|
||||
with st.expander("System", expanded=False):
|
||||
with st.expander("System control", expanded=False):
|
||||
|
||||
st.subheader("Change password")
|
||||
if is_pw_disabled():
|
||||
st.info("Frontend password protection is disabled via DISABLE_FRONTEND_PW.")
|
||||
st.subheader("System control")
|
||||
if st.button("Reboot now", type="primary"):
|
||||
try:
|
||||
r = requests.post(f"{BACKEND_URL}/system_reboot", timeout=1)
|
||||
if r.ok:
|
||||
st.success("Reboot initiated. The UI will become unreachable shortly.")
|
||||
else:
|
||||
st.error(f"Failed to reboot: {r.status_code} {r.text}")
|
||||
except Exception as e:
|
||||
st.error(f"Error calling reboot: {e}")
|
||||
else:
|
||||
st.subheader("Change password")
|
||||
with st.form("change_pw_form"):
|
||||
cur = st.text_input("Current password", type="password")
|
||||
new1 = st.text_input("New password", type="password")
|
||||
@@ -587,16 +578,16 @@ with st.expander("System", expanded=False):
|
||||
except Exception as e:
|
||||
st.error(f"Failed to update password: {e}")
|
||||
|
||||
st.subheader("System control")
|
||||
if st.button("Reboot now", type="primary"):
|
||||
try:
|
||||
r = requests.post(f"{BACKEND_URL}/system_reboot", timeout=1)
|
||||
if r.ok:
|
||||
st.success("Reboot initiated. The UI will become unreachable shortly.")
|
||||
else:
|
||||
st.error(f"Failed to reboot: {r.status_code} {r.text}")
|
||||
except Exception as e:
|
||||
st.error(f"Error calling reboot: {e}")
|
||||
st.subheader("Reboot")
|
||||
if st.button("Reboot now", type="primary"):
|
||||
try:
|
||||
r = requests.post(f"{BACKEND_URL}/system_reboot", timeout=1)
|
||||
if r.ok:
|
||||
st.success("Reboot initiated. The UI will become unreachable shortly.")
|
||||
else:
|
||||
st.error(f"Failed to reboot: {r.status_code} {r.text}")
|
||||
except Exception as e:
|
||||
st.error(f"Error calling reboot: {e}")
|
||||
|
||||
log.basicConfig(
|
||||
level=os.environ.get('LOG_LEVEL', log.DEBUG),
|
||||
|
||||
@@ -146,6 +146,7 @@ async def initialize(conf: auracast_config.AuracastConfigGroup):
|
||||
'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),
|
||||
'is_streaming': False, # will be set to True below if we actually start
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
})
|
||||
global_config_group = conf
|
||||
@@ -160,6 +161,11 @@ async def initialize(conf: auracast_config.AuracastConfigGroup):
|
||||
if any(big.audio_source.startswith("device:") or big.audio_source.startswith("file:") for big in conf.bigs):
|
||||
log.info("Auto-starting streaming on multicaster1")
|
||||
await multicaster1.start_streaming()
|
||||
# Mark persisted state as streaming
|
||||
settings = load_stream_settings() or {}
|
||||
settings['is_streaming'] = True
|
||||
settings['timestamp'] = datetime.utcnow().isoformat()
|
||||
save_stream_settings(settings)
|
||||
except Exception as e:
|
||||
log.error("Exception in /init: %s", traceback.format_exc())
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
@@ -230,6 +236,16 @@ async def stop_audio():
|
||||
await multicaster2.reset() # Fully reset controller and advertising
|
||||
running = True
|
||||
|
||||
# Persist is_streaming=False
|
||||
try:
|
||||
settings = load_stream_settings() or {}
|
||||
if settings.get('is_streaming'):
|
||||
settings['is_streaming'] = False
|
||||
settings['timestamp'] = datetime.utcnow().isoformat()
|
||||
save_stream_settings(settings)
|
||||
except Exception:
|
||||
log.warning("Failed to persist is_streaming=False during stop_audio", exc_info=True)
|
||||
|
||||
return {"status": "stopped", "was_running": running}
|
||||
except Exception as e:
|
||||
log.error("Exception in /stop_audio: %s", traceback.format_exc())
|
||||
@@ -268,6 +284,7 @@ async def _autostart_from_settings():
|
||||
languages = settings.get('languages') or ["deu"]
|
||||
stream_password = settings.get('stream_password')
|
||||
original_ts = settings.get('timestamp')
|
||||
previously_streaming = bool(settings.get('is_streaming'))
|
||||
|
||||
try:
|
||||
usb_names = {d.get('name') for _, d in list_usb_pw_inputs(refresh=False)}
|
||||
@@ -279,7 +296,9 @@ async def _autostart_from_settings():
|
||||
else:
|
||||
os.environ.setdefault("PULSE_LATENCY_MSEC", "3")
|
||||
|
||||
# Only auto-start device-based inputs; Webapp and Demo require external sources/UI
|
||||
# Only auto-start if the previous state was streaming and it's a device-based input.
|
||||
if not previously_streaming:
|
||||
return
|
||||
if not input_device_name:
|
||||
return
|
||||
if rate is None or octets is None:
|
||||
@@ -467,6 +486,14 @@ async def offer(offer: Offer):
|
||||
# Yield control so the Streamer coroutine has a chance to
|
||||
# create the WebRTCAudioInput before we push samples.
|
||||
await asyncio.sleep(0)
|
||||
# Persist is_streaming=True for Webapp mode
|
||||
try:
|
||||
settings = load_stream_settings() or {}
|
||||
settings['is_streaming'] = True
|
||||
settings['timestamp'] = datetime.utcnow().isoformat()
|
||||
save_stream_settings(settings)
|
||||
except Exception:
|
||||
log.warning("Failed to persist is_streaming=True on WebRTC start", exc_info=True)
|
||||
first = False
|
||||
# in stereo case this is interleaved data format
|
||||
frame_array = frame.to_ndarray()
|
||||
|
||||
Reference in New Issue
Block a user