sound.cc 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #include "selfdrive/ui/soundd/sound.h"
  2. #include <cmath>
  3. #include <QAudio>
  4. #include <QAudioDeviceInfo>
  5. #include <QDebug>
  6. #include "cereal/messaging/messaging.h"
  7. #include "common/util.h"
  8. // TODO: detect when we can't play sounds
  9. // TODO: detect when we can't display the UI
  10. Sound::Sound(QObject *parent) : sm({"controlsState", "deviceState", "microphone"}) {
  11. qInfo() << "default audio device: " << QAudioDeviceInfo::defaultOutputDevice().deviceName();
  12. for (auto &[alert, fn, loops] : sound_list) {
  13. QSoundEffect *s = new QSoundEffect(this);
  14. QObject::connect(s, &QSoundEffect::statusChanged, [=]() {
  15. assert(s->status() != QSoundEffect::Error);
  16. });
  17. s->setSource(QUrl::fromLocalFile("../../assets/sounds/" + fn));
  18. sounds[alert] = {s, loops};
  19. }
  20. QTimer *timer = new QTimer(this);
  21. QObject::connect(timer, &QTimer::timeout, this, &Sound::update);
  22. timer->start(1000 / UI_FREQ);
  23. };
  24. void Sound::update() {
  25. const bool started_prev = sm["deviceState"].getDeviceState().getStarted();
  26. sm.update(0);
  27. const bool started = sm["deviceState"].getDeviceState().getStarted();
  28. if (started && !started_prev) {
  29. started_frame = sm.frame;
  30. }
  31. // no sounds while offroad
  32. // also no sounds if nothing is alive in case thermald crashes while offroad
  33. const bool crashed = (sm.frame - std::max(sm.rcv_frame("deviceState"), sm.rcv_frame("controlsState"))) > 10*UI_FREQ;
  34. if (!started || crashed) {
  35. setAlert({});
  36. return;
  37. }
  38. // scale volume using ambient noise level
  39. if (sm.updated("microphone")) {
  40. float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 56.f, 0.f, 1.f);
  41. volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale);
  42. Hardware::set_volume(volume);
  43. }
  44. setAlert(Alert::get(sm, started_frame));
  45. }
  46. void Sound::setAlert(const Alert &alert) {
  47. if (!current_alert.equal(alert)) {
  48. current_alert = alert;
  49. // stop sounds
  50. for (auto &[s, loops] : sounds) {
  51. // Only stop repeating sounds
  52. if (s->loopsRemaining() > 1 || s->loopsRemaining() == QSoundEffect::Infinite) {
  53. s->stop();
  54. }
  55. }
  56. // play sound
  57. if (alert.sound != AudibleAlert::NONE) {
  58. auto &[s, loops] = sounds[alert.sound];
  59. s->setLoopCount(loops);
  60. s->play();
  61. }
  62. }
  63. }