aboutsummaryrefslogtreecommitdiffstats
path: root/src/audiomixer-service.cpp
diff options
context:
space:
mode:
authorScott Murray <scott.murray@konsulko.com>2022-06-17 20:24:27 -0400
committerScott Murray <scott.murray@konsulko.com>2022-06-17 20:29:19 -0400
commit298bbf445a731b85cb8d5d19a3b595e8870d8701 (patch)
treeffc1e0f3ff78cd160bf6e080c0caa48449499a3e /src/audiomixer-service.cpp
parent75f7a06890b0c02d179a0eb240e7f06b7f0d2220 (diff)
Repurpose into VIS clientmarlin
Repurpose repository for a spiritual successor of the previous binding. The replacement is a daemon that demonstrates servicing the volume actuator from the VSS schema via VIS signals from KUKSA.val. Currently the connection to KUKSA.val is websocket based using the boost::asio framework, but the plan is to migrate to gRPC as that becomes more robust in KUKSA.val. As well, this new code will serve as the base for implementing a gRPC API to expose the full set of WirePlumber controls as was done with the previous binding. Notable changes: - New code is completely C++, partly to leverage using Boost, but also to futureproof future work with gRPC. The WirePlumber interfacing code that has been kept from the old binding is still C for now, converting it to C++ is a planned future rework. - Switch from CMake to meson for ease of development and some degree of futureproofing. - Use with systemd is assumed; behavior follows the systemd daemon guidelines barring the use of journald logging prefixes, which may be addressed with future work. A systemd unit is also installed as part of the build. - SPDX license headers using SPDX "short identifiers" are used in source files rather than the full copyright headers used in the previous codebase. This follows the direction that projects such as the Linux kernel are going in. Bug-AGL: SPEC-4409 Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: Ibb7091c4354432bb094147d1419ab475486a4abc
Diffstat (limited to 'src/audiomixer-service.cpp')
-rw-r--r--src/audiomixer-service.cpp129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/audiomixer-service.cpp b/src/audiomixer-service.cpp
new file mode 100644
index 0000000..5787153
--- /dev/null
+++ b/src/audiomixer-service.cpp
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include "audiomixer-service.hpp"
+#include <iostream>
+#include <algorithm>
+
+
+AudiomixerService::AudiomixerService(const VisConfig &config, net::io_context& ioc, ssl::context& ctx) :
+ VisSession(config, ioc, ctx)
+{
+ m_audiomixer = audiomixer_new();
+ if (m_audiomixer) {
+ // Set up callbacks for WirePlumber events
+ m_audiomixer_events.controls_changed = audiomixer_control_change_cb;
+ m_audiomixer_events.value_changed = audiomixer_value_change_cb;
+ audiomixer_add_event_listener(m_audiomixer, &m_audiomixer_events, this);
+
+ // Drive connecting to PipeWire core and refreshing controls list
+ audiomixer_lock(m_audiomixer);
+ audiomixer_ensure_controls(m_audiomixer, 3);
+ audiomixer_unlock(m_audiomixer);
+ } else {
+ std::cerr << "Could not create WirePlumber connection" << std::endl;
+ }
+}
+
+AudiomixerService::~AudiomixerService()
+{
+ audiomixer_free(m_audiomixer);
+}
+
+void AudiomixerService::handle_authorized_response(void)
+{
+ subscribe("Vehicle.Cabin.Infotainment.Media.Volume");
+ subscribe("Vehicle.Cabin.SteeringWheel.Switches.VolumeUp");
+ subscribe("Vehicle.Cabin.SteeringWheel.Switches.VolumeDown");
+ subscribe("Vehicle.Cabin.SteeringWheel.Switches.VolumeMute");
+
+ // Set initial volume in VSS
+ // For now a value of 50 matches the default in the homescreen app.
+ // Ideally there would be some form of persistence scheme to restore
+ // the last value on restart.
+ set("Vehicle.Cabin.Infotainment.Media.Volume", "50");
+}
+
+void AudiomixerService::handle_get_response(std::string &path, std::string &value, std::string &timestamp)
+{
+ // Placeholder since no gets are performed ATM
+}
+
+void AudiomixerService::handle_notification(std::string &path, std::string &value, std::string &timestamp)
+{
+ if (!m_audiomixer) {
+ return;
+ }
+
+ audiomixer_lock(m_audiomixer);
+
+ const struct mixer_control *ctl = audiomixer_find_control(m_audiomixer, "Master Playback");
+ if (!ctl) {
+ audiomixer_unlock(m_audiomixer);
+ return;
+ }
+
+ if (path == "Vehicle.Cabin.Infotainment.Media.Volume") {
+ try {
+ int volume = std::stoi(value);
+ if (volume >= 0 && volume <= 100) {
+ double v = (double) volume / 100.0;
+ if (m_config.verbose() > 1)
+ std::cout << "Setting volume to " << v << std::endl;
+ audiomixer_change_volume(m_audiomixer, ctl, v);
+ }
+ }
+ catch (std::exception ex) {
+ // ignore bad value
+ }
+ } else if (path == "Vehicle.Cabin.SteeringWheel.Switches.VolumeUp" && value == "true") {
+ double volume = ctl->volume;
+ volume += 0.05; // up 5%
+ if (volume > 1.0)
+ volume = 1.0; // clamp to 100%
+ if (m_config.verbose() > 1)
+ std::cout << "Increasing volume to " << volume << std::endl;
+ audiomixer_change_volume(m_audiomixer, ctl, volume);
+
+ } else if (path == "Vehicle.Cabin.SteeringWheel.Switches.VolumeDown" && value == "true") {
+ double volume = ctl->volume;
+ volume -= 0.05; // down 5%
+ if (volume < 0.0)
+ volume = 0.0; // clamp to 0%
+ if (m_config.verbose() > 1)
+ std::cout << "Decreasing volume to " << volume << std::endl;
+ audiomixer_change_volume(m_audiomixer, ctl, volume);
+
+ } else if (path == "Vehicle.Cabin.SteeringWheel.Switches.VolumeMute" && value == "true") {
+ if (m_config.verbose() > 1) {
+ if (ctl->mute)
+ std::cout << "Unmuting" << std::endl;
+ else
+ std::cout << "Muting" << std::endl;
+ }
+ audiomixer_change_mute(m_audiomixer, ctl, !ctl->mute);
+ }
+ // else ignore
+
+ audiomixer_unlock(m_audiomixer);
+}
+
+void AudiomixerService::handle_control_change(void)
+{
+ // Ignore for now
+}
+
+void AudiomixerService::handle_value_change(unsigned int change_mask, const struct mixer_control *control)
+{
+ if (!control)
+ return;
+
+ if (change_mask & MIXER_CONTROL_CHANGE_FLAG_VOLUME) {
+ if (std::string(control->name) == "Master Playback") {
+ // Push change into VIS
+ std::string value = std::to_string((int) (control->volume * 100.0));
+ set("Vehicle.Cabin.Infotainment.Media.Volume", value);
+ }
+ } else if (change_mask & MIXER_CONTROL_CHANGE_FLAG_MUTE) {
+ // For now, do nothing, new state is in control->mute
+ }
+}