diff --git a/opendbc_repo b/opendbc_repo index 8c0b1367c5178f..7689bdd278c45d 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit 8c0b1367c5178f919c05ae58a1dcf7439ed3eb37 +Subproject commit 7689bdd278c45da51252fa5beb9a7afe834948ff diff --git a/openpilot/cereal/log.capnp b/openpilot/cereal/log.capnp index 2b43a95d7bee12..d0c5d01eb58c4c 100644 --- a/openpilot/cereal/log.capnp +++ b/openpilot/cereal/log.capnp @@ -811,6 +811,9 @@ struct SelfdriveState { promptDistracted @8; preAlert @9; + + complete @10; + dmCriticalMax @11; } enum OpenpilotState @0xdbe58b96d2d1ac61 { diff --git a/openpilot/selfdrive/assets/sounds/complete.wav b/openpilot/selfdrive/assets/sounds/complete.wav new file mode 100644 index 00000000000000..f85d48f315e074 --- /dev/null +++ b/openpilot/selfdrive/assets/sounds/complete.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3027da9834adf9c71177bc3086f8de3018ce22e4725b694d635723c5b3c860cd +size 97120 diff --git a/openpilot/selfdrive/assets/sounds/critical.wav b/openpilot/selfdrive/assets/sounds/critical.wav new file mode 100644 index 00000000000000..f36aa1bacd0df3 --- /dev/null +++ b/openpilot/selfdrive/assets/sounds/critical.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca29ff46fbd6d00cc02596de8c9abfbf1cacdc6a7b2f98b27a74d24c790da004 +size 52374 diff --git a/openpilot/selfdrive/assets/sounds/disengage.wav b/openpilot/selfdrive/assets/sounds/disengage.wav index 7bfd97ad715e2e..7db1d31911303d 100644 --- a/openpilot/selfdrive/assets/sounds/disengage.wav +++ b/openpilot/selfdrive/assets/sounds/disengage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42bd04a57b527c787a0555503e02a203f7d672c12d448769a3f41f17befbf013 -size 48044 +oid sha256:6f47633b5082b911e79dd13fc2d1f4c2a9d44d2fe0860f3d390ffc4e3d772f7d +size 97120 diff --git a/openpilot/selfdrive/assets/sounds/dm_critical.wav b/openpilot/selfdrive/assets/sounds/dm_critical.wav new file mode 100644 index 00000000000000..9a4171444ff80e --- /dev/null +++ b/openpilot/selfdrive/assets/sounds/dm_critical.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:538271820d618046009bb456e930598f2736dd1a6174c11925ec3912581b05c1 +size 52374 diff --git a/openpilot/selfdrive/assets/sounds/dm_critical_max.wav b/openpilot/selfdrive/assets/sounds/dm_critical_max.wav new file mode 100644 index 00000000000000..9526364f99374b --- /dev/null +++ b/openpilot/selfdrive/assets/sounds/dm_critical_max.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c4699e3a456a0df2bbfac7ab1eb8972fc8bd970296133fd322e214c61884407 +size 52374 diff --git a/openpilot/selfdrive/assets/sounds/dm_warning.wav b/openpilot/selfdrive/assets/sounds/dm_warning.wav new file mode 100644 index 00000000000000..52124b0801c091 --- /dev/null +++ b/openpilot/selfdrive/assets/sounds/dm_warning.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:634fad6590295ef2e73d5f7e5aecbb5dd245a0f7692f1e300c2ebac95aabb8e3 +size 73026 diff --git a/openpilot/selfdrive/assets/sounds/dm_warning_low.wav b/openpilot/selfdrive/assets/sounds/dm_warning_low.wav new file mode 100644 index 00000000000000..1e146ed03d950d --- /dev/null +++ b/openpilot/selfdrive/assets/sounds/dm_warning_low.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc1a1d07a8ecb960705308d8973a1369b71d5ef612552cfd8ac5d4d7c1ebf09d +size 145308 diff --git a/openpilot/selfdrive/assets/sounds/engage.wav b/openpilot/selfdrive/assets/sounds/engage.wav index 8633b5ac2d82b1..a984e2f3da2a27 100644 --- a/openpilot/selfdrive/assets/sounds/engage.wav +++ b/openpilot/selfdrive/assets/sounds/engage.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1e177499d9439367179cc57a6301b6162393972e3a136cc35c5fdac026bf10a -size 48044 +oid sha256:a380fe0a022856b302841a0dd19b71eab318c6b08ec851f128942758a7f1631a +size 97120 diff --git a/openpilot/selfdrive/assets/sounds/pre_alert.wav b/openpilot/selfdrive/assets/sounds/pre_alert.wav index 4443bf7d23425b..d8240a17176f2a 100644 --- a/openpilot/selfdrive/assets/sounds/pre_alert.wav +++ b/openpilot/selfdrive/assets/sounds/pre_alert.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c0af7f5fe57bb36ab96fae868e20feca763541c97a61b3a3a84a0e7fcb81163 -size 83350 +oid sha256:cc9e67cfaba77e8e4f4049f0add9238660e4cf8f886c6915600d8f47a30c98db +size 97120 diff --git a/openpilot/selfdrive/assets/sounds/prompt.wav b/openpilot/selfdrive/assets/sounds/prompt.wav deleted file mode 100644 index e482c85a629806..00000000000000 --- a/openpilot/selfdrive/assets/sounds/prompt.wav +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad19268e4aaaeac8dd21f6b26c16a121e7b3f50bba867748e7226727643ae682 -size 144642 diff --git a/openpilot/selfdrive/assets/sounds/prompt_distracted.wav b/openpilot/selfdrive/assets/sounds/prompt_distracted.wav deleted file mode 100644 index c11993f20c0442..00000000000000 --- a/openpilot/selfdrive/assets/sounds/prompt_distracted.wav +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:412ef25d2fb103c1ebd55c667313a5921493305fb4e1f4e1dafc08d3b95d86ab -size 73026 diff --git a/openpilot/selfdrive/assets/sounds/refuse.wav b/openpilot/selfdrive/assets/sounds/refuse.wav index 1e0c47697d89cb..10026d7be9883b 100644 --- a/openpilot/selfdrive/assets/sounds/refuse.wav +++ b/openpilot/selfdrive/assets/sounds/refuse.wav @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4af81cbf1d96a42cc351878b015298aee82874b46baaf1a615ca91ec36c0ced6 -size 83228 +oid sha256:081d64ca28a84a59ff5e6aea4732865b8687585938b8a287bc7e6a49d0646508 +size 97120 diff --git a/openpilot/selfdrive/assets/sounds/warning.wav b/openpilot/selfdrive/assets/sounds/warning.wav new file mode 100644 index 00000000000000..bb71a0176a51a9 --- /dev/null +++ b/openpilot/selfdrive/assets/sounds/warning.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1bb440f424c989c06e203bfba0b32d39aede8f6c78a9b335e5e778460202b601 +size 73026 diff --git a/openpilot/selfdrive/assets/sounds/warning_immediate.wav b/openpilot/selfdrive/assets/sounds/warning_immediate.wav deleted file mode 100644 index fcbfed79ed87d6..00000000000000 --- a/openpilot/selfdrive/assets/sounds/warning_immediate.wav +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5a390831afca3bfc6ea3c2739b872ebf866e70df8ae30653f8587e5cd3993959 -size 68306 diff --git a/openpilot/selfdrive/assets/sounds/warning_soft.wav b/openpilot/selfdrive/assets/sounds/warning_soft.wav deleted file mode 100644 index 7db30303d60f5d..00000000000000 --- a/openpilot/selfdrive/assets/sounds/warning_soft.wav +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:67e636d072703e6b1233a12344c0a6304fd43d64dbb31c66b71c2c8870a339c1 -size 153764 diff --git a/openpilot/selfdrive/ui/mici/layouts/settings/developer.py b/openpilot/selfdrive/ui/mici/layouts/settings/developer.py index 2d7dc0899ddda8..efee3bb7fc6ecd 100644 --- a/openpilot/selfdrive/ui/mici/layouts/settings/developer.py +++ b/openpilot/selfdrive/ui/mici/layouts/settings/developer.py @@ -1,5 +1,11 @@ +import threading +import time +import wave from collections.abc import Callable +from openpilot.cereal import messaging +from openpilot.common.basedir import BASEDIR from openpilot.common.time_helpers import system_time_valid +from openpilot.selfdrive.ui.soundd import AudibleAlert, sound_list from openpilot.system.ui.widgets.scroller import NavScroller from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigToggle, BigParamControl, BigCircleParamControl, GreyBigButton from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigInputDialog, BigConfirmationCircleButton @@ -85,8 +91,13 @@ def ssh_keys_callback(): self._debug_mode_toggle = BigParamControl("ui debug mode", "ShowDebugInfo", toggle_callback=lambda checked: (gui_app.set_show_touches(checked), gui_app.set_show_fps(checked))) + self._playing_sounds = False + self._play_sounds_btn = BigButton("play sounds") + self._play_sounds_btn.set_click_callback(self._on_play_sounds) + self._play_sounds_btn.set_enabled(lambda: ui_state.is_offroad() and not self._playing_sounds) self._scroller.add_widgets([ + self._play_sounds_btn, self._adb_toggle, self._ssh_toggle, self._ssh_keys_btn, @@ -162,6 +173,46 @@ def _update_toggles(self): for key, item in self._refresh_toggles: item.set_checked(ui_state.params.get_bool(key)) + def _on_play_sounds(self): + self._playing_sounds = True + + def play(): + pm = messaging.PubMaster(['selfdriveState']) + sm = messaging.SubMaster(['managerState']) + + def publish(alert, duration): + for _ in range(int(duration * 20)): + msg = messaging.new_message('selfdriveState') + msg.selfdriveState.alertSound = alert + pm.send('selfdriveState', msg) + time.sleep(0.05) + + try: + ui_state.params.put_bool("IsDriverViewEnabled", True) # get manager to start soundd offroad + deadline = time.monotonic() + 10. + while time.monotonic() < deadline: + sm.update(100) + if any(p.name == 'soundd' and p.running for p in sm['managerState'].processes): + break + time.sleep(1.) # let soundd open its audio stream + + # each sound plays twice back to back, same transitions soundd sees while driving + for alert, (filename, play_count, _) in sound_list.items(): + with wave.open(BASEDIR + "/openpilot/selfdrive/assets/sounds/" + filename) as f: + duration = f.getnframes() / f.getframerate() + if play_count is None: + publish(alert, 2 * duration - 0.1) # seamless loop, stop finishes the second loop + else: + publish(alert, duration + 0.1) + publish(AudibleAlert.none, 0.05) # one frame of none to retrigger + publish(alert, duration + 0.1) + publish(AudibleAlert.none, 1.) + finally: + ui_state.params.put_bool("IsDriverViewEnabled", False) + self._playing_sounds = False + + threading.Thread(target=play, daemon=True).start() + def _on_joystick_debug_mode(self, state: bool): ui_state.params.put_bool("JoystickDebugMode", state, block=True) ui_state.params.put_bool("LongitudinalManeuverMode", False, block=True) diff --git a/openpilot/selfdrive/ui/soundd.py b/openpilot/selfdrive/ui/soundd.py index d84c98710b6d50..5667a3ab444c59 100644 --- a/openpilot/selfdrive/ui/soundd.py +++ b/openpilot/selfdrive/ui/soundd.py @@ -22,7 +22,7 @@ SELFDRIVE_STATE_TIMEOUT = 5 # 5 seconds FILTER_DT = 1. / (micd.SAMPLE_RATE / micd.FFT_SAMPLES) -AMBIENT_DB = 24 # DB where MIN_VOLUME is applied +AMBIENT_DB = 25 # DB where MIN_VOLUME is applied DB_SCALE = 30 # AMBIENT_DB + DB_SCALE is where MAX_VOLUME is applied VOLUME_BASE = 20 @@ -39,14 +39,17 @@ AudibleAlert.disengage: ("disengage.wav", 1, MAX_VOLUME), AudibleAlert.refuse: ("refuse.wav", 1, MAX_VOLUME), - AudibleAlert.prompt: ("prompt.wav", 1, MAX_VOLUME), - AudibleAlert.promptRepeat: ("prompt.wav", None, MAX_VOLUME), - AudibleAlert.promptDistracted: ("prompt_distracted.wav", None, MAX_VOLUME), + AudibleAlert.prompt: ("warning.wav", 1, MAX_VOLUME), + AudibleAlert.promptRepeat: ("warning.wav", None, MAX_VOLUME), + AudibleAlert.promptDistracted: ("dm_warning.wav", None, MAX_VOLUME), AudibleAlert.preAlert: ("pre_alert.wav", 1, MAX_VOLUME), - AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME), - AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), + AudibleAlert.complete: ("complete.wav", 1, MAX_VOLUME), + AudibleAlert.dmCriticalMax: ("dm_critical_max.wav", None, MAX_VOLUME), + + AudibleAlert.warningSoft: ("critical.wav", None, MAX_VOLUME), + AudibleAlert.warningImmediate: ("dm_critical.wav", None, MAX_VOLUME), } if HARDWARE.get_device_type() == "tizi": sound_list.update({ @@ -76,6 +79,7 @@ def __init__(self): self.ramp_start_time = 0. self.selfdrive_timeout_alert = False + self.pending_stop = False self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) @@ -114,6 +118,10 @@ def get_sound_data(self, frames): # get "frames" worth of data from the current self.current_sound_frame += frames_to_write current_sound_frame = self.current_sound_frame % len(sound_data) loops = self.current_sound_frame // len(sound_data) + if self.pending_stop and current_sound_frame == 0: + self.current_alert = AudibleAlert.none + self.pending_stop = False + break return ret * self.current_volume @@ -124,6 +132,15 @@ def callback(self, data_out: np.ndarray, frames: int, time, status) -> None: def update_alert(self, new_alert): current_alert_played_once = self.current_alert == AudibleAlert.none or self.current_sound_frame >= len(self.loaded_sounds[self.current_alert]) + # let looping sounds finish the current loop instead of cutting off mid tone + if new_alert == AudibleAlert.none and self.current_alert != AudibleAlert.none and sound_list[self.current_alert][1] is None: + if current_alert_played_once: + self.pending_stop = True + else: + self.current_alert = AudibleAlert.none + self.current_sound_frame = 0 + return + self.pending_stop = False if self.current_alert != new_alert and (new_alert != AudibleAlert.none or current_alert_played_once): if new_alert == AudibleAlert.warningImmediate: self.ramp_start_volume = self.current_volume