summaryrefslogtreecommitdiffstats
path: root/src/main.cpp
diff options
context:
space:
mode:
authorSimon Rettberg2022-08-18 20:27:25 +0200
committerSimon Rettberg2022-08-18 20:27:25 +0200
commitc48cebd620d3f5330c104d85ac32f0aaffadaa14 (patch)
tree8fc74d8aa05fcdc75bfcdf93fdc89c0f071692eb /src/main.cpp
parentWhen changing default output of card, also set default sink (diff)
downloadpavucontrol-slx-c48cebd620d3f5330c104d85ac32f0aaffadaa14.tar.gz
pavucontrol-slx-c48cebd620d3f5330c104d85ac32f0aaffadaa14.tar.xz
pavucontrol-slx-c48cebd620d3f5330c104d85ac32f0aaffadaa14.zip
Replace everything with new "slxmix" (work in progress)
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp306
1 files changed, 306 insertions, 0 deletions
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 <cstdio>
+#include <cstring>
+#include <cstddef>
+#include <QVector>
+#include <QGuiApplication>
+#include <QTimer>
+#include <PulseAudioQt/Context>
+#include <PulseAudioQt/Server>
+#include <PulseAudioQt/Profile>
+#include <PulseAudioQt/PulseObject>
+#include <PulseAudioQt/SinkInput>
+#include <PulseAudioQt/Sink>
+#include <PulseAudioQt/Card>
+#include <PulseAudioQt/Port>
+#include <QList>
+#include <QSet>
+#include <QTimer>
+// 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<QString> _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<int> 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();
+}