From c48cebd620d3f5330c104d85ac32f0aaffadaa14 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 18 Aug 2022 20:27:25 +0200 Subject: Replace everything with new "slxmix" (work in progress) --- src/main.cpp | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 src/main.cpp (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..a06f6f5 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,306 @@ +#include "main.h" +#include "mainwindow.h" +#include "slxoutput.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// libkf5pulseaudioqt-dev + +// Public + +/** Ignore any signals from GUI elements when this is true. Set when we're updating the GUI */ +bool g_IgnoreGui; + +// Private + +/** If not empty, on profile change, if profile belings to this card, make its sink default */ +static QString _pendingCardDefault; + +static QSet _donePorts; + +static QTimer _updateDelay; + +static MainWindow *_mainWindow; + +static void queueGuiUpdate(int ms = 50) +{ + _updateDelay.start(ms); +} + +static void updateActiveOutput() +{ + g_IgnoreGui = true; + _mainWindow->mark(); + auto *i = PulseAudioQt::Context::instance(); + //QSet usedCards; + auto cards = i->cards(); + printf(".--------------------------------------------.\n"); + for (auto *sink : i->sinks()) { + QString cardName = sink->cardIndex() < cards.size() ? cards.at(sink->cardIndex())->name() : QString(); + int portIndex = -1; + //usedCards.insert(sink->cardIndex()); + for (auto *port : sink->ports()) { + portIndex++; + //if (port->availability() == PulseAudioQt::Port::Unavailable) + // continue; + bool active = (sink->isDefault() && portIndex == sink->activePortIndex()); + printf("[%c] Output: '%s %s', volume: %d, mute: %d\n", + active ? 'x' : ' ', + sink->description().toLocal8Bit().constData(), port->description().toLocal8Bit().constData(), + (int)sink->volume(), (int)sink->isMuted()); + qint64 volume = sink->volume(); + QString id = cardName + sink->name() + port->name(); + if (active) { + if (!_donePorts.contains(id)) { + _donePorts.insert(id); + if (volume < 60000) { + volume = 65535; + sink->setVolume(volume); + } + } + } + QString title = sink->description() + ", " + port->description(); + _mainWindow->getOutput(id, true, title)->updateOutput(title, + active, sink->isMuted(), sink->isVolumeWritable() ? sink->volume() : -1, QString(), sink->name(), port->name()); + } + } + for (auto *card : cards) { + QString cardDescription = card->description(); + int profIndex = -1; + for (auto *profile : card->profiles()) { + profIndex++; + if (profIndex == card->activeProfileIndex() || profile->availability() == PulseAudioQt::Profile::Unavailable) + continue; + if (profile->sinks() == 0) + continue; + printf("[ ] Output: '%s', sinks: %d\n", + profile->description().toLocal8Bit().constData(), profile->sinks()); + QString id = card->name() + profile->name(); + QString title = cardDescription + ", " + profile->description(); + _mainWindow->getOutput(id, false, title)->updateOutput(title, + false, false, -1, card->name(), QString(), profile->name()); + } + } + printf("`--------------------------------------------ยด\n"); + _mainWindow->sweep(); + g_IgnoreGui = false; +} + +static void checkShouldSetDefault() +{ + if (_pendingCardDefault.isEmpty()) + return; + printf("Pending card default to %s\n", _pendingCardDefault.toLocal8Bit().constData()); + auto *i = PulseAudioQt::Context::instance(); + int cardIdx = -1; + for (auto *card : i->cards()) { + cardIdx++; + if (card->name() == _pendingCardDefault && !card->ports().isEmpty()) + break; + } + for (auto *sink : i->sinks()) { + if (sink->cardIndex() == cardIdx) { + printf("MATCH SET!\n"); + sink->setDefault(true); + sink->setMuted(false); + _pendingCardDefault.clear(); + } + } +} + +static void newCardAppeared(PulseAudioQt::Card *card) +{ + //if (_doneCards.contains(card->name())) + // return; + auto *i = PulseAudioQt::Context::instance(); + QCoreApplication::connect(card, &PulseAudioQt::Card::profilesChanged, [=]() { + printf("Card %p profiles changed\n", card); + }); + QCoreApplication::connect(card, &PulseAudioQt::Card::activeProfileIndexChanged, [=]() { + printf("Card %p active profile index changed\n", card); + checkShouldSetDefault(); + queueGuiUpdate(); + }); + QCoreApplication::connect(card, &PulseAudioQt::Card::portsChanged, [=]() { + printf("Card %p ports changed\n", card); + checkShouldSetDefault(); + queueGuiUpdate(); + }); + /* + QCoreApplication::connect(card, &PulseAudioQt::Card::sinksChanged, [=]() { + printf("Card %p sinks changed\n", card); + }); + */ +} + +static void newSinkAppeared(PulseAudioQt::Sink *sink) +{ + for (auto *port : sink->ports()) { + printf(" Port: %s\n", port->name().toLocal8Bit().constData()); + } + QCoreApplication::connect(sink, &PulseAudioQt::Sink::activePortIndexChanged, [=]() { + printf("Sink %p changed active port\n", sink); + queueGuiUpdate(); + }); + QCoreApplication::connect(sink, &PulseAudioQt::Sink::defaultChanged, [=]() { + printf("Sink %p changed default\n", sink); + queueGuiUpdate(); + }); + QCoreApplication::connect(sink, &PulseAudioQt::Sink::volumeChanged, [=]() { + queueGuiUpdate(); + }); + QCoreApplication::connect(sink, &PulseAudioQt::Sink::isVolumeWritableChanged, [=]() { + queueGuiUpdate(); + }); + queueGuiUpdate(); +} + +void setMuted(const QString &sink, bool muted) +{ + auto *i = PulseAudioQt::Context::instance(); + + for (auto *sp : i->sinks()) { + if (sp->name() == sink) { + sp->setMuted(muted); + } + } + queueGuiUpdate(); +} + +void setSinkVolume(const QString &sink, int volume) +{ + auto *i = PulseAudioQt::Context::instance(); + + for (auto *sp : i->sinks()) { + if (sp->name() == sink) { + sp->setVolume(volume); + queueGuiUpdate(250); + } + } +} + +void enableCard(const QString &card, const QString &profile) +{ + auto *i = PulseAudioQt::Context::instance(); + PulseAudioQt::Card *matchingCard = nullptr; + int profileIdx = -1; + int cardIdx = -1; + + _pendingCardDefault.clear(); + for (auto *cp : i->cards()) { + cardIdx++; + if (cp->name() != card) + continue; + int i = -1; + int exactProfileIdx = -1; + for (auto *pp : cp->profiles()) { + i++; + if (pp->availability() == PulseAudioQt::Profile::Unavailable) + continue; + if (pp->description().contains(QLatin1String("Duplex"))) { + // Prefer Duplex mode for analog outputs, it's usually listed after output only + profileIdx = i; + } + if (profileIdx == -1) { + // Otherwise default to first one in list + profileIdx = i; + } + if (pp->name() == profile) { + exactProfileIdx = i; + } + } + if (exactProfileIdx != -1) { + profileIdx = exactProfileIdx; + } + if (profileIdx != -1) { + matchingCard = cp; + break; + } + } + if (matchingCard != nullptr && profileIdx < matchingCard->profiles().size()) { + if (matchingCard->activeProfileIndex() == profileIdx) { + for (auto *sink : i->sinks()) { + if (sink->cardIndex() == cardIdx) { + sink->setMuted(false); + sink->setDefault(true); + } + } + } else { + matchingCard->setActiveProfileIndex(profileIdx); + _pendingCardDefault = matchingCard->name(); + } + } + queueGuiUpdate(); +} + +void enableSink(const QString &sink, const QString &port) +{ + auto *i = PulseAudioQt::Context::instance(); + + _pendingCardDefault.clear(); + for (auto *sp : i->sinks()) { + if (sp->name() != sink) + continue; + int i = -1; + for (auto *pp : sp->ports()) { + i++; + if (pp->name() == port) { + sp->setDefault(true); + sp->setMuted(false); + sp->setActivePortIndex(i); + } + } + } + queueGuiUpdate(); +} + +int main(int argc, char **argv) +{ + QApplication a(argc, argv); + printf("Muh\n"); + auto *i = PulseAudioQt::Context::instance(); + printf("Pa is %p = %d\n", i, (int)i->isValid()); + printf("Cards: %d\n", (int)i->cards().size()); + + QTimer::singleShot(100, [=]() { + for (auto *card : i->cards()) { + newCardAppeared(card); + printf("Card: %s (index: %d)\n", card->name().toLocal8Bit().constData(), (int)card->index()); + for (auto *profile : card->profiles()) { + printf(" Profile: %s\n", profile->name().toLocal8Bit().constData()); + } + } + for (auto *sink : i->sinks()) { + printf("Sink: %s (for card index %d)\n", sink->name().toLocal8Bit().constData(), sink->cardIndex()); + newSinkAppeared(sink); + } + QCoreApplication::connect(i, &PulseAudioQt::Context::cardAdded, &newCardAppeared); + QCoreApplication::connect(i, &PulseAudioQt::Context::sinkAdded, &newSinkAppeared); + printf("Initial output\n"); + queueGuiUpdate(); + }); + + QCoreApplication::connect(&_updateDelay, &QTimer::timeout, &updateActiveOutput); + _updateDelay.setInterval(50); + _updateDelay.setSingleShot(true); + + _mainWindow = new MainWindow; + _mainWindow->show(); + + return a.exec(); +} -- cgit v1.2.3-55-g7522