Files
StarPilot/openpilot/starpilot/audio/axis_alerts.py
T
firestar5683 fd4ca85d61 Audio
Provide alert playback and volume control with a native audio callback that does not depend on the Python GIL.

Co-authored-by: Daniel Koepping <elkoled@gmail.com>
2026-10-14 20:02:39 -05:00

67 lines
3.1 KiB
Python

from openpilot.cereal import log
from openpilot.starpilot.aol.runtime import current_intent
from openpilot.starpilot.aol.wire import INTENT_SERVICE
AudibleAlert = log.SelfdriveState.AudibleAlert
COALESCE_NS = 250_000_000
class _Transition:
def __init__(self):
self.session = None
self.sequence = 0
self.active = False
self.observed_at = 0
def update(self, session, sequence: int, active: bool, now_ns: int) -> int:
changed = 0
if session is None:
self.session = None
elif session != self.session or now_ns - self.observed_at > COALESCE_NS:
self.session, self.sequence, self.active, self.observed_at = session, sequence, active, now_ns
elif sequence > self.sequence:
changed = int(active) - int(self.active)
self.sequence, self.active, self.observed_at = sequence, active, now_ns
return changed
class AxisAlerts:
def __init__(self):
self.lateral = _Transition()
self.longitudinal = _Transition()
self.last_sound = AudibleAlert.none
self.last_sound_at = 0
self.native_sound = AudibleAlert.none
def update(self, sm, native_sound: int, now_ns: int) -> int:
intent = (current_intent(sm, car_state_ns=int(sm.logMonoTime[INTENT_SERVICE]), now_ns=now_ns)
if INTENT_SERVICE in sm.logMonoTime else None)
# Engagement is persistent driver intent. Temporary native permission loss,
# pedal override and output suppression must not replay engagement sounds.
state_ns = int(sm.logMonoTime.get('selfdriveState', 0))
state_fresh = (state_ns > 0 and 0 <= now_ns - state_ns <= 100_000_000 and
sm.valid['selfdriveState'] and sm.alive['selfdriveState'])
lateral_known = intent is not None and (intent.pauseLateral or intent.lateralArmed or state_fresh)
lateral = self.lateral.update(intent.producerSessionId if lateral_known else None, intent.sequence if intent else 0,
bool(intent and not intent.pauseLateral and
(intent.lateralArmed or (state_fresh and sm['selfdriveState'].active))), now_ns)
longitudinal = self.longitudinal.update(
intent.producerSessionId if intent is not None and state_fresh else None,
intent.sequence if intent is not None else 0,
bool(intent is not None and state_fresh and sm['selfdriveState'].enabled and not intent.pauseLongitudinal), now_ns)
extra_sound = (AudibleAlert.disengage if min(lateral, longitudinal) < 0 else
AudibleAlert.engage if max(lateral, longitudinal) > 0 else AudibleAlert.none)
if native_sound != AudibleAlert.none:
if native_sound != self.native_sound and native_sound in (AudibleAlert.engage, AudibleAlert.disengage):
self.last_sound, self.last_sound_at = native_sound, now_ns
self.native_sound = native_sound
return native_sound
self.native_sound = native_sound
if extra_sound != AudibleAlert.none:
if extra_sound == self.last_sound and now_ns - self.last_sound_at < COALESCE_NS:
return AudibleAlert.none
self.last_sound, self.last_sound_at = extra_sound, now_ns
return extra_sound