1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- #include "selfdrive/ui/soundd/sound.h"
- #include <cmath>
- #include <QAudio>
- #include <QAudioDeviceInfo>
- #include <QDebug>
- #include "cereal/messaging/messaging.h"
- #include "common/util.h"
- // TODO: detect when we can't play sounds
- // TODO: detect when we can't display the UI
- Sound::Sound(QObject *parent) : sm({"controlsState", "deviceState", "microphone"}) {
- qInfo() << "default audio device: " << QAudioDeviceInfo::defaultOutputDevice().deviceName();
- for (auto &[alert, fn, loops] : sound_list) {
- QSoundEffect *s = new QSoundEffect(this);
- QObject::connect(s, &QSoundEffect::statusChanged, [=]() {
- assert(s->status() != QSoundEffect::Error);
- });
- s->setSource(QUrl::fromLocalFile("../../assets/sounds/" + fn));
- sounds[alert] = {s, loops};
- }
- QTimer *timer = new QTimer(this);
- QObject::connect(timer, &QTimer::timeout, this, &Sound::update);
- timer->start(1000 / UI_FREQ);
- };
- void Sound::update() {
- const bool started_prev = sm["deviceState"].getDeviceState().getStarted();
- sm.update(0);
- const bool started = sm["deviceState"].getDeviceState().getStarted();
- if (started && !started_prev) {
- started_frame = sm.frame;
- }
- // no sounds while offroad
- // also no sounds if nothing is alive in case thermald crashes while offroad
- const bool crashed = (sm.frame - std::max(sm.rcv_frame("deviceState"), sm.rcv_frame("controlsState"))) > 10*UI_FREQ;
- if (!started || crashed) {
- setAlert({});
- return;
- }
- // scale volume using ambient noise level
- if (sm.updated("microphone")) {
- float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 56.f, 0.f, 1.f);
- volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale);
- Hardware::set_volume(volume);
- }
- setAlert(Alert::get(sm, started_frame));
- }
- void Sound::setAlert(const Alert &alert) {
- if (!current_alert.equal(alert)) {
- current_alert = alert;
- // stop sounds
- for (auto &[s, loops] : sounds) {
- // Only stop repeating sounds
- if (s->loopsRemaining() > 1 || s->loopsRemaining() == QSoundEffect::Infinite) {
- s->stop();
- }
- }
- // play sound
- if (alert.sound != AudibleAlert::NONE) {
- auto &[s, loops] = sounds[alert.sound];
- s->setLoopCount(loops);
- s->play();
- }
- }
- }
|