From 5ef07dccfe23c892b2c9275e7e7238a2d51178f5 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 20 Sep 2022 17:04:24 +0200 Subject: Add volume fixing daemon/worker mode --- src/main.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b1736cc..e537a74 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ static QString _pendingCardDefaultId; static QString _pendingCardDefaultPort; /** While running, we want to set each port's volume to 100% the first time we see it. Unfortunately - * a port only startes to exist once its according profile is selected, so there is no way to have + * a port only starts to exist once its according profile is selected, so there is no way to have * a simple "set everything to 100%" method run on startup, at least not without switching through * all profiles on all cards, which sounds like it could be annoying and buggy. So do it this way * for now. @@ -59,27 +59,53 @@ static void queueGuiUpdate(int ms = 50) _updateDelay.start(ms); } -static void addDevicePortToWindow(PulseAudioQt::Card *card, PulseAudioQt::Device *device, PulseAudioQt::Port *port, int portIndex, bool isOutput) +/** + * Make sure the port is enabled and volume up, the first time we see it at least. + */ +static void autoVolumeAdjustment(PulseAudioQt::Device *device, PulseAudioQt::Port *port, int portIndex = -1) { - //if (port->availability() == PulseAudioQt::Port::Unavailable) - // continue; + QString id = device->name() + port->name(); + if (_donePorts.contains(id)) + return; + if (portIndex == -1) { + int i = -1; + for (auto *p : device->ports()) { + ++i; + if (port == p) { + portIndex = i; + } + } + if (portIndex == -1) { + printf("Port not found\n"); + return; + } + } bool portIsActive = portIndex == device->activePortIndex(); bool defaultSinkAndPort = (device->isDefault() && portIsActive); qint64 volume = device->volume(); - printf("[%c] Output: '%s %s', volume: %d, mute: %d\n", - defaultSinkAndPort ? 'x' : ' ', - device->description().toLocal8Bit().constData(), port->description().toLocal8Bit().constData(), - (int)volume, (int)device->isMuted()); - QString id = device->name() + port->name(); // Only once, update port volume to be 100% if it's low - if (defaultSinkAndPort && !_donePorts.contains(id)) { + if (defaultSinkAndPort) { _donePorts.insert(id); + printf("Initial volume fix for %s\n", id.toLocal8Bit().constData()); if (volume < 60000) { volume = 65535; device->setVolume(volume); } device->setMuted(false); } +} + +static void addDevicePortToWindow(PulseAudioQt::Card *card, PulseAudioQt::Device *device, PulseAudioQt::Port *port, int portIndex, bool isOutput) +{ + //if (port->availability() == PulseAudioQt::Port::Unavailable) + // continue; + bool portIsActive = portIndex == device->activePortIndex(); + bool defaultSinkAndPort = (device->isDefault() && portIsActive); + qint64 volume = device->volume(); + printf("[%c] Output: '%s %s', volume: %d, mute: %d\n", + defaultSinkAndPort ? 'x' : ' ', + device->description().toLocal8Bit().constData(), port->description().toLocal8Bit().constData(), + (int)volume, (int)device->isMuted()); //knownCardPortCombos.insert(card->name() + ":" + port->name()); _mainWindow->getDevice(card, device, port, isOutput)->updateDeviceAndPort(defaultSinkAndPort, device->isMuted(), (portIsActive && device->isVolumeWritable()) ? device->volume() : -1); @@ -430,6 +456,36 @@ void enableSource(const QString &source, const QString &port) queueGuiUpdate(); } +static void setupAutoVolumeDevice(PulseAudioQt::Device *device) +{ + auto fn = [device]() { + int pi = device->activePortIndex(); + if (pi < 0 || pi >= device->ports().size()) + return; + auto *port = device->ports().at(pi); + autoVolumeAdjustment(device, port, pi); + }; + QObject::connect(device, &PulseAudioQt::Source::activePortIndexChanged, fn); + fn(); +} + +static void setupAutoVolume() +{ + auto *i = PulseAudioQt::Context::instance(); + for (auto *sink : i->sinks()) { + setupAutoVolumeDevice(sink); + } + for (auto *source : i->sources()) { + setupAutoVolumeDevice(source); + } + QObject::connect(i, &PulseAudioQt::Context::sinkAdded, [](PulseAudioQt::Sink *sink) { + setupAutoVolumeDevice(sink); + }); + QObject::connect(i, &PulseAudioQt::Context::sourceAdded, [](PulseAudioQt::Source *source) { + setupAutoVolumeDevice(source); + }); +} + int main(int argc, char **argv) { QApplication a(argc, argv); @@ -441,18 +497,34 @@ int main(int argc, char **argv) parser.setApplicationDescription(QObject::tr("SLXmix Volume Control")); parser.addHelpOption(); QCommandLineOption selectOption(QStringList() << QStringLiteral("output") << QStringLiteral("o"), - QObject::tr("Select a specific output configuration and quit. Will select the Profile/Sink/Port combo that best matches the list of given keywords, e.g. 'HDMI 1 5.1'"), + QObject::tr("Select a specific output configuration and quit. Will select the Profile/Sink/Port combo" + " that best matches the list of given keywords, e.g. 'HDMI 1 5.1'"), QStringLiteral("keywords")); + QCommandLineOption workerOption(QStringList() << QStringLiteral("worker") << QStringLiteral("w"), + QObject::tr("Run invisible worker that sets every port to 100% and unmuted the first time it's set default")); parser.addOption(selectOption); + parser.addOption(workerOption); parser.process(a); // Select default output and exit if (parser.isSet(selectOption)) { + if (parser.isSet(workerOption)) { + printf("Cannot set both -w and -o at the same time.\n"); + return 1; + } QString what = parser.value(selectOption); QTimer::singleShot(100, [what]() { setDefaultOutput(what); }); return a.exec(); } + if (parser.isSet(workerOption)) { + if (parser.isSet(selectOption)) { + printf("Cannot set both -w and -o at the same time.\n"); + return 1; + } + QTimer::singleShot(100, &setupAutoVolume); + return a.exec(); + } // There's no signal, or no way to check if we're connected to PA, so // just wait a bit and hope for the best. -- cgit v1.2.3-55-g7522