diff options
Diffstat (limited to 'src/setdefault.cpp')
-rw-r--r-- | src/setdefault.cpp | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/setdefault.cpp b/src/setdefault.cpp new file mode 100644 index 0000000..21b368e --- /dev/null +++ b/src/setdefault.cpp @@ -0,0 +1,151 @@ +#include "setdefault.h" + +#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 <QRegularExpression> +#include <QDebug> +#include <QCoreApplication> +#include <QTimer> + +static const QRegularExpression _splitter("[() \t-]"); + +static int countMatches(const QStringList &find, const QString &haystack); + +static void setDefaultSink(const QString &bestCardId, const QStringList &words); + +void setDefaultOutput(const QString &name) +{ + auto *ctx = PulseAudioQt::Context::instance(); + const QStringList words = name.toLower().split(_splitter, QString::SkipEmptyParts); + int bestNum = -1000; + int bestProfileIdx = -1; + PulseAudioQt::Card *bestCard = nullptr; + for (auto *card : ctx->cards()) { + int i = -1; + for (auto *profile : card->profiles()) { + ++i; + if (profile->sinks() == 0) + continue; + int matches = countMatches(words, profile->description()); + // Prefer Duplex + if (profile->description().contains(QLatin1String("Duplex"))) { + matches += 2; + } + // Penaltize unavailable profiles + if (profile->availability() != PulseAudioQt::Profile::Available) { + matches -= 11; + } + qDebug() << matches << "Profile" << profile->description(); + if (matches > bestNum) { + bestNum = matches; + bestCard = card; + bestProfileIdx = i; + } + } + } + if (bestCard == nullptr) { + qDebug() << "No match found"; + qApp->quit(); + return; + } + QString bestCardId = bestCard->name(); + if (bestCard->activeProfileIndex() == bestProfileIdx) { + setDefaultSink(bestCardId, words); + return; + } + QObject::connect(bestCard, &PulseAudioQt::Card::activeProfileIndexChanged, [bestCardId, words]() { + QTimer::singleShot(10, [bestCardId, words]() { + setDefaultSink(bestCardId, words); + }); + }); + qDebug() << "Switching card's profile..."; + bestCard->setActiveProfileIndex(bestProfileIdx); + // Wait for switch - add safety timeout + QTimer::singleShot(1000, []() { + qDebug() << "WARNING - timeout reached, exiting..."; + qApp->exit(1); + }); +} + +static void setDefaultSink(const QString &bestCardId, const QStringList &words) +{ + auto *ctx = PulseAudioQt::Context::instance(); + int idx = -1; + int bestCardIdx = -1; + for (auto *card : ctx->cards()) { + idx++; + if (card->name() == bestCardId) { + bestCardIdx = idx; + break; + } + } + int bestNum = -1000; + int bestPortIdx = -1; + PulseAudioQt::Sink *bestSink = nullptr; + for (auto *sink : ctx->sinks()) { + if (bestCardIdx != -1 && sink->cardIndex() != bestCardIdx) + continue; // Not sink of card + int sinkMatchVal = countMatches(words, sink->description()); + int pi = -1; + for (auto *port : sink->ports()) { + pi++; + int portMatchVal = sinkMatchVal + countMatches(words, port->description()); + qDebug() << portMatchVal << "SinkPort" << sink->description() << port->description(); + if (portMatchVal > bestNum) { + bestNum = portMatchVal; + bestSink = sink; + bestPortIdx = pi; + } + + } + } + if (bestSink == nullptr) { + qDebug() << "No match found"; + qApp->exit(1); + } + if (bestPortIdx != -1 && bestSink->activePortIndex() != bestPortIdx) { + qDebug() << "Selecting port"; + bestSink->setActivePortIndex(bestPortIdx); + } + QTimer::singleShot(10, [bestSink]() { + qDebug() << "Unmuting sink and selecting as default:" << bestSink->description(); + bestSink->setDefault(true); + bestSink->setMuted(false); + bestSink->setVolume(65535); + }); + QTimer::singleShot(20, []() { + qDebug() << "Done"; + qApp->quit(); + }); +} + +static int countMatches(const QStringList &find, const QString &haystack) +{ + int ret = 0; + QStringList hayList = haystack.toLower().split(_splitter, QString::SkipEmptyParts); + qDebug() << "Comparing" << hayList; + // Look for all the words we want to find + for (const QString &word : find) { + if (hayList.contains(word)) { + ret += 10; + } + } + if (ret == 0) { + // If not a single word matched, bail out + return -1000; + } + // Penaltize additonal words in haystack that we don't want to find + for (const QString &word : hayList) { + if (!find.contains(word)) { + ret -= 1; + } + } + return ret; +} |