From abe39e50766c418818bf72d2567db78978dbd466 Mon Sep 17 00:00:00 2001 From: Justin Newberry Date: Tue, 5 Dec 2023 18:10:01 -0800 Subject: [PATCH] Soundd: move to python (#30567) soundd python --- docs/c_docs.rst | 6 - release/files_common | 5 +- selfdrive/assets/sounds/warning_immediate.wav | Bin 62760 -> 68306 bytes selfdrive/manager/process_config.py | 2 +- selfdrive/test/test_onroad.py | 2 +- selfdrive/ui/SConscript | 6 - selfdrive/ui/__init__.py | 0 selfdrive/ui/soundd.py | 160 ++++++++++++++++++ selfdrive/ui/soundd/.gitignore | 1 - selfdrive/ui/soundd/main.cc | 18 -- selfdrive/ui/soundd/sound.cc | 67 -------- selfdrive/ui/soundd/sound.h | 41 ----- selfdrive/ui/soundd/soundd | 4 - selfdrive/ui/tests/test_sound.cc | 75 -------- selfdrive/ui/tests/test_soundd.py | 80 +++------ system/hardware/base.h | 1 - system/hardware/pc/hardware.h | 8 - system/hardware/tici/hardware.h | 8 - 18 files changed, 186 insertions(+), 298 deletions(-) create mode 100644 selfdrive/ui/__init__.py create mode 100644 selfdrive/ui/soundd.py delete mode 100644 selfdrive/ui/soundd/.gitignore delete mode 100644 selfdrive/ui/soundd/main.cc delete mode 100644 selfdrive/ui/soundd/sound.cc delete mode 100644 selfdrive/ui/soundd/sound.h delete mode 100755 selfdrive/ui/soundd/soundd delete mode 100644 selfdrive/ui/tests/test_sound.cc diff --git a/docs/c_docs.rst b/docs/c_docs.rst index 0b9d23972e..6e8808ec20 100644 --- a/docs/c_docs.rst +++ b/docs/c_docs.rst @@ -41,12 +41,6 @@ ui .. autodoxygenindex:: :project: selfdrive_ui -soundd -"""""" -.. autodoxygenindex:: - :project: selfdrive_ui_soundd - - replay """""" .. autodoxygenindex:: diff --git a/release/files_common b/release/files_common index 3fd5df5693..ddc3e31d4d 100644 --- a/release/files_common +++ b/release/files_common @@ -306,10 +306,7 @@ selfdrive/ui/*.h selfdrive/ui/ui selfdrive/ui/text selfdrive/ui/spinner -selfdrive/ui/soundd/*.cc -selfdrive/ui/soundd/*.h -selfdrive/ui/soundd/soundd -selfdrive/ui/soundd/.gitignore +selfdrive/ui/soundd.py selfdrive/ui/translations/*.ts selfdrive/ui/translations/languages.json selfdrive/ui/update_translations.py diff --git a/selfdrive/assets/sounds/warning_immediate.wav b/selfdrive/assets/sounds/warning_immediate.wav index 9f6f672e2829c0924fc9bdb175050240ef9259e0..b1815a95867b9e4f5e2f5ec41ad29f80ffae228f 100644 GIT binary patch literal 68306 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 literal 62760 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 z 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 diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 4ad2574188..36d69b03bb 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -60,7 +60,7 @@ procs = [ PythonProcess("navmodeld", "selfdrive.modeld.navmodeld", only_onroad), NativeProcess("sensord", "system/sensord", ["./sensord"], only_onroad, enabled=not PC), NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)), - NativeProcess("soundd", "selfdrive/ui/soundd", ["./soundd"], only_onroad), + PythonProcess("soundd", "selfdrive.ui.soundd", only_onroad), NativeProcess("locationd", "selfdrive/locationd", ["./locationd"], only_onroad), NativeProcess("boardd", "selfdrive/boardd", ["./boardd"], always_run, enabled=False), PythonProcess("calibrationd", "selfdrive.locationd.calibrationd", only_onroad), diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index e89ce5c72b..f8d8db9cdc 100755 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -46,7 +46,7 @@ PROCS = { "selfdrive.thermald.thermald": 3.87, "selfdrive.locationd.calibrationd": 2.0, "selfdrive.locationd.torqued": 5.0, - "./_soundd": (1.0, 65.0), + "selfdrive.ui.soundd": 5.8, "selfdrive.monitoring.dmonitoringd": 4.0, "./proclogd": 1.54, "system.logmessaged": 0.2, diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 916f1017a3..f0db1f63a7 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -70,12 +70,6 @@ qt_env.Command(assets, [assets_src, translations_assets_src], f"rcc $SOURCES -o qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, translations_assets_src, "#selfdrive/assets/assets.o"]) + [lrelease]) asset_obj = qt_env.Object("assets", assets) -# build soundd -qt_env.Program("soundd/_soundd", ["soundd/main.cc", "soundd/sound.cc"], LIBS=qt_libs) -if GetOption('extras'): - qt_env.Program("tests/playsound", "tests/playsound.cc", LIBS=base_libs) - qt_env.Program('tests/test_sound', ['tests/test_runner.cc', 'soundd/sound.cc', 'tests/test_sound.cc'], LIBS=qt_libs) - qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs) # spinner and text window diff --git a/selfdrive/ui/__init__.py b/selfdrive/ui/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py new file mode 100644 index 0000000000..33fcf0be31 --- /dev/null +++ b/selfdrive/ui/soundd.py @@ -0,0 +1,160 @@ +import math +import time +import numpy as np +import os +import wave + +from typing import Dict, Optional, Tuple + +from cereal import car, messaging +from openpilot.common.basedir import BASEDIR +from openpilot.common.realtime import Ratekeeper +from openpilot.system.hardware import PC +from openpilot.system.swaglog import cloudlog + +SAMPLE_RATE = 48000 +MAX_VOLUME = 1.0 +MIN_VOLUME = 0.1 +CONTROLS_TIMEOUT = 5 # 5 seconds + +AMBIENT_DB = 30 # DB where MIN_VOLUME is applied +DB_SCALE = 30 # AMBIENT_DB + DB_SCALE is where MAX_VOLUME is applied + +AudibleAlert = car.CarControl.HUDControl.AudibleAlert + + +sound_list: Dict[int, Tuple[str, Optional[int], float]] = { + # AudibleAlert, file name, play count (none for infinite) + AudibleAlert.engage: ("engage.wav", 1, MAX_VOLUME), + 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.warningSoft: ("warning_soft.wav", None, MAX_VOLUME), + AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), +} + +def check_controls_timeout_alert(sm): + controls_missing = time.monotonic() - sm.rcv_time['controlsState'] + + if controls_missing > CONTROLS_TIMEOUT: + if sm['controlsState'].enabled and (controls_missing - CONTROLS_TIMEOUT) < 10: + return True + + return False + + +class Soundd: + def __init__(self): + self.load_sounds() + + self.current_alert = AudibleAlert.none + self.current_volume = MIN_VOLUME + self.current_sound_frame = 0 + + self.controls_timeout_alert = False + + if not PC: + os.system("pactl set-sink-volume @DEFAULT_SINK@ 0.9") # set to max volume and control volume within soundd + + def load_sounds(self): + self.loaded_sounds: Dict[int, np.ndarray] = {} + + # Load all sounds + for sound in sound_list: + filename, play_count, volume = sound_list[sound] + + wavefile = wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r') + + assert wavefile.getnchannels() == 1 + assert wavefile.getsampwidth() == 2 + assert wavefile.getframerate() == SAMPLE_RATE + + length = wavefile.getnframes() + self.loaded_sounds[sound] = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2) + + def get_sound_data(self, frames): # get "frames" worth of data from the current alert sound, looping when required + + ret = np.zeros(frames, dtype=np.float32) + + if self.current_alert != AudibleAlert.none: + num_loops = sound_list[self.current_alert][1] + sound_data = self.loaded_sounds[self.current_alert] + written_frames = 0 + + current_sound_frame = self.current_sound_frame % len(sound_data) + loops = self.current_sound_frame // len(sound_data) + + while written_frames < frames and (num_loops is None or loops < num_loops): + available_frames = sound_data.shape[0] - current_sound_frame + frames_to_write = min(available_frames, frames - written_frames) + ret[written_frames:written_frames+frames_to_write] = sound_data[current_sound_frame:current_sound_frame+frames_to_write] + written_frames += frames_to_write + self.current_sound_frame += frames_to_write + + return ret * self.current_volume + + def callback(self, data_out: np.ndarray, frames: int, time, status) -> None: + if status: + cloudlog.warning(f"soundd stream over/underflow: {status}") + data_out[:frames, 0] = self.get_sound_data(frames) + + 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]) + if self.current_alert != new_alert and (new_alert != AudibleAlert.none or current_alert_played_once): + self.current_alert = new_alert + self.current_sound_frame = 0 + + def get_audible_alert(self, sm): + if sm.updated['controlsState']: + new_alert = sm['controlsState'].alertSound.raw + self.update_alert(new_alert) + elif check_controls_timeout_alert(sm): + self.update_alert(AudibleAlert.warningImmediate) + self.controls_timeout_alert = True + elif self.controls_timeout_alert: + self.update_alert(AudibleAlert.none) + self.controls_timeout_alert = False + + def calculate_volume(self, weighted_db): + volume = ((weighted_db - AMBIENT_DB) / DB_SCALE) * (MAX_VOLUME - MIN_VOLUME) + MIN_VOLUME + return math.pow(10, (np.clip(volume, MIN_VOLUME, MAX_VOLUME) - 1)) + + def soundd_thread(self): + # sounddevice must be imported after forking processes + import sounddevice as sd + + rk = Ratekeeper(20) + + sm = messaging.SubMaster(['controlsState', 'microphone']) + + if PC: + device = None + else: + device = "pulse" # "sdm845-tavil-snd-card: - (hw:0,0)" + + with sd.OutputStream(device=device, channels=1, samplerate=SAMPLE_RATE, callback=self.callback) as stream: + cloudlog.info(f"soundd stream started: {stream.samplerate=} {stream.channels=} {stream.dtype=} {stream.device=}") + while True: + sm.update(0) + + if sm.updated['microphone']: + self.current_volume = self.calculate_volume(sm["microphone"].filteredSoundPressureWeightedDb) + + self.get_audible_alert(sm) + + rk.keep_time() + + assert stream.active + + +def main(): + s = Soundd() + s.soundd_thread() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/selfdrive/ui/soundd/.gitignore b/selfdrive/ui/soundd/.gitignore deleted file mode 100644 index c47f949d37..0000000000 --- a/selfdrive/ui/soundd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_soundd diff --git a/selfdrive/ui/soundd/main.cc b/selfdrive/ui/soundd/main.cc deleted file mode 100644 index c6c7434ca4..0000000000 --- a/selfdrive/ui/soundd/main.cc +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#include - -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/soundd/sound.h" - -int main(int argc, char **argv) { - qInstallMessageHandler(swagLogMessageHandler); - setpriority(PRIO_PROCESS, 0, -20); - - QApplication a(argc, argv); - std::signal(SIGINT, sigTermHandler); - std::signal(SIGTERM, sigTermHandler); - - Sound sound; - return a.exec(); -} diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc deleted file mode 100644 index a5884f113f..0000000000 --- a/selfdrive/ui/soundd/sound.cc +++ /dev/null @@ -1,67 +0,0 @@ -#include "selfdrive/ui/soundd/sound.h" - -#include - -#include -#include -#include - -#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", "microphone"}) { - qInfo() << "default audio device: " << QAudioDeviceInfo::defaultOutputDevice().deviceName(); - - for (auto &[alert, fn, loops, volume] : sound_list) { - QSoundEffect *s = new QSoundEffect(this); - QObject::connect(s, &QSoundEffect::statusChanged, [=]() { - assert(s->status() != QSoundEffect::Error); - }); - s->setSource(QUrl::fromLocalFile("../../assets/sounds/" + fn)); - s->setVolume(volume); - 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() { - sm.update(0); - - // scale volume using ambient noise level - if (sm.updated("microphone")) { - float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 60.f, 0.f, 1.f); - volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); - // set volume on changes - if (std::exchange(current_volume, std::nearbyint(volume * 10)) != current_volume) { - Hardware::set_volume(volume); - } - } - - setAlert(Alert::get(sm, 0)); -} - -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(); - } - } -} diff --git a/selfdrive/ui/soundd/sound.h b/selfdrive/ui/soundd/sound.h deleted file mode 100644 index 4fcb2e1bce..0000000000 --- a/selfdrive/ui/soundd/sound.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include "system/hardware/hw.h" -#include "selfdrive/ui/ui.h" - - -const float MAX_VOLUME = 1.0; - -const std::tuple sound_list[] = { - // AudibleAlert, file name, loop count - {AudibleAlert::ENGAGE, "engage.wav", 0, MAX_VOLUME}, - {AudibleAlert::DISENGAGE, "disengage.wav", 0, MAX_VOLUME}, - {AudibleAlert::REFUSE, "refuse.wav", 0, MAX_VOLUME}, - - {AudibleAlert::PROMPT, "prompt.wav", 0, MAX_VOLUME}, - {AudibleAlert::PROMPT_REPEAT, "prompt.wav", QSoundEffect::Infinite, MAX_VOLUME}, - {AudibleAlert::PROMPT_DISTRACTED, "prompt_distracted.wav", QSoundEffect::Infinite, MAX_VOLUME}, - - {AudibleAlert::WARNING_SOFT, "warning_soft.wav", QSoundEffect::Infinite, MAX_VOLUME}, - {AudibleAlert::WARNING_IMMEDIATE, "warning_immediate.wav", QSoundEffect::Infinite, MAX_VOLUME}, -}; - -class Sound : public QObject { -public: - explicit Sound(QObject *parent = 0); - -protected: - void update(); - void setAlert(const Alert &alert); - - SubMaster sm; - Alert current_alert = {}; - QMap> sounds; - int current_volume = -1; -}; diff --git a/selfdrive/ui/soundd/soundd b/selfdrive/ui/soundd/soundd deleted file mode 100755 index 9b7a32fec9..0000000000 --- a/selfdrive/ui/soundd/soundd +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -cd "$(dirname "$0")" -export QT_QPA_PLATFORM="offscreen" -exec ./_soundd diff --git a/selfdrive/ui/tests/test_sound.cc b/selfdrive/ui/tests/test_sound.cc deleted file mode 100644 index d9cb5c0a7f..0000000000 --- a/selfdrive/ui/tests/test_sound.cc +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include - -#include "catch2/catch.hpp" -#include "selfdrive/ui/soundd/sound.h" - -class TestSound : public Sound { -public: - TestSound() : Sound() { - for (auto i = sounds.constBegin(); i != sounds.constEnd(); ++i) { - sound_stats[i.key()] = {0, 0}; - QObject::connect(i.value().first, &QSoundEffect::playingChanged, [=, s = i.value().first, a = i.key()]() { - if (s->isPlaying()) { - sound_stats[a].first++; - } else { - sound_stats[a].second++; - } - }); - } - } - - QMap> sound_stats; -}; - -void controls_thread(int loop_cnt) { - PubMaster pm({"controlsState", "deviceState"}); - MessageBuilder deviceStateMsg; - auto deviceState = deviceStateMsg.initEvent().initDeviceState(); - deviceState.setStarted(true); - - const int DT_CTRL = 10; // ms - for (int i = 0; i < loop_cnt; ++i) { - for (auto &[alert, fn, loops, volume] : sound_list) { - printf("testing %s\n", qPrintable(fn)); - for (int j = 0; j < 1000 / DT_CTRL; ++j) { - MessageBuilder msg; - auto cs = msg.initEvent().initControlsState(); - cs.setAlertSound(alert); - cs.setAlertType(fn.toStdString()); - pm.send("controlsState", msg); - pm.send("deviceState", deviceStateMsg); - QThread::msleep(DT_CTRL); - } - } - } - - // send no alert sound - for (int j = 0; j < 1000 / DT_CTRL; ++j) { - MessageBuilder msg; - msg.initEvent().initControlsState(); - pm.send("controlsState", msg); - QThread::msleep(DT_CTRL); - } - - QThread::currentThread()->quit(); -} - -TEST_CASE("test soundd") { - QEventLoop loop; - TestSound test_sound; - const int test_loop_cnt = 2; - - QThread t; - QObject::connect(&t, &QThread::started, [=]() { controls_thread(test_loop_cnt); }); - QObject::connect(&t, &QThread::finished, [&]() { loop.quit(); }); - t.start(); - loop.exec(); - - for (const AudibleAlert alert : test_sound.sound_stats.keys()) { - auto [play, stop] = test_sound.sound_stats[alert]; - REQUIRE(play == test_loop_cnt); - REQUIRE(stop == test_loop_cnt); - } -} diff --git a/selfdrive/ui/tests/test_soundd.py b/selfdrive/ui/tests/test_soundd.py index 80a261e6d9..94ce26eb47 100755 --- a/selfdrive/ui/tests/test_soundd.py +++ b/selfdrive/ui/tests/test_soundd.py @@ -1,75 +1,41 @@ #!/usr/bin/env python3 -import subprocess -import time import unittest -from cereal import log, car -import cereal.messaging as messaging -from openpilot.selfdrive.test.helpers import phone_only, with_processes -# TODO: rewrite for unittest -from openpilot.common.realtime import DT_CTRL -from openpilot.system.hardware import HARDWARE +from cereal import car +from cereal import messaging +from cereal.messaging import SubMaster, PubMaster +from openpilot.selfdrive.ui.soundd import CONTROLS_TIMEOUT, check_controls_timeout_alert -AudibleAlert = car.CarControl.HUDControl.AudibleAlert +import time -SOUNDS = { - # sound: total writes - AudibleAlert.none: 0, - AudibleAlert.engage: 184, - AudibleAlert.disengage: 186, - AudibleAlert.refuse: 194, - AudibleAlert.prompt: 184, - AudibleAlert.promptRepeat: 487, - AudibleAlert.promptDistracted: 508, - AudibleAlert.warningSoft: 471, - AudibleAlert.warningImmediate: 470, -} +AudibleAlert = car.CarControl.HUDControl.AudibleAlert -def get_total_writes(): - audio_flinger = subprocess.check_output('dumpsys media.audio_flinger', shell=True, encoding='utf-8').strip() - write_lines = [l for l in audio_flinger.split('\n') if l.strip().startswith('Total writes')] - return sum(int(l.split(':')[1]) for l in write_lines) class TestSoundd(unittest.TestCase): - def test_sound_card_init(self): - assert HARDWARE.get_sound_card_online() + def test_check_controls_timeout_alert(self): + sm = SubMaster(['controlsState']) + pm = PubMaster(['controlsState']) + + for _ in range(100): + cs = messaging.new_message('controlsState') + cs.controlsState.enabled = True + + pm.send("controlsState", cs) - @phone_only - @with_processes(['soundd']) - def test_alert_sounds(self): - pm = messaging.PubMaster(['deviceState', 'controlsState']) + time.sleep(0.01) - # make sure they're all defined - alert_sounds = {v: k for k, v in car.CarControl.HUDControl.AudibleAlert.schema.enumerants.items()} - diff = set(SOUNDS.keys()).symmetric_difference(alert_sounds.keys()) - assert len(diff) == 0, f"not all sounds defined in test: {diff}" + sm.update(0) - # wait for procs to init - time.sleep(1) + self.assertFalse(check_controls_timeout_alert(sm)) - for sound, expected_writes in SOUNDS.items(): - print(f"testing {alert_sounds[sound]}") - start_writes = get_total_writes() + for _ in range(CONTROLS_TIMEOUT * 110): + sm.update(0) + time.sleep(0.01) - for i in range(int(10 / DT_CTRL)): - msg = messaging.new_message('deviceState') - msg.deviceState.started = True - pm.send('deviceState', msg) + self.assertTrue(check_controls_timeout_alert(sm)) - msg = messaging.new_message('controlsState') - if i < int(6 / DT_CTRL): - msg.controlsState.alertSound = sound - msg.controlsState.alertType = str(sound) - msg.controlsState.alertText1 = "Testing Sounds" - msg.controlsState.alertText2 = f"playing {alert_sounds[sound]}" - msg.controlsState.alertSize = log.ControlsState.AlertSize.mid - pm.send('controlsState', msg) - time.sleep(DT_CTRL) + # TODO: add test with micd for checking that soundd actually outputs sounds - tolerance = expected_writes / 8 - actual_writes = get_total_writes() - start_writes - print(f" expected {expected_writes} writes, got {actual_writes}") - assert abs(expected_writes - actual_writes) <= tolerance, f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}" if __name__ == "__main__": unittest.main() diff --git a/system/hardware/base.h b/system/hardware/base.h index 890a743ea0..dc2282a93a 100644 --- a/system/hardware/base.h +++ b/system/hardware/base.h @@ -29,7 +29,6 @@ public: static void poweroff() {} static void set_brightness(int percent) {} static void set_display_power(bool on) {} - static void set_volume(float volume) {} static bool get_ssh_enabled() { return false; } static void set_ssh_enabled(bool enabled) {} diff --git a/system/hardware/pc/hardware.h b/system/hardware/pc/hardware.h index 189adbbbee..5dea184ca6 100644 --- a/system/hardware/pc/hardware.h +++ b/system/hardware/pc/hardware.h @@ -13,14 +13,6 @@ public: static bool TICI() { return util::getenv("TICI", 0) == 1; } static bool AGNOS() { return util::getenv("TICI", 0) == 1; } - static void set_volume(float volume) { - volume = util::map_val(volume, 0.f, 1.f, MIN_VOLUME, MAX_VOLUME); - - char volume_str[6]; - snprintf(volume_str, sizeof(volume_str), "%.3f", volume); - std::system(("pactl set-sink-volume @DEFAULT_SINK@ " + std::string(volume_str)).c_str()); - } - static void config_cpu_rendering(bool offscreen) { if (offscreen) { setenv("QT_QPA_PLATFORM", "offscreen", 1); diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index 0a00aca5be..f6ea86b002 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -67,14 +67,6 @@ public: bl_power_control.close(); } } - static void set_volume(float volume) { - volume = util::map_val(volume, 0.f, 1.f, MIN_VOLUME, MAX_VOLUME); - - char volume_str[6]; - snprintf(volume_str, sizeof(volume_str), "%.3f", volume); - std::system(("pactl set-sink-volume @DEFAULT_SINK@ " + std::string(volume_str)).c_str()); - } - static std::map get_init_logs() { std::map ret = {