summaryrefslogtreecommitdiffstats
path: root/src/setdefault.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/setdefault.cpp')
-rw-r--r--src/setdefault.cpp151
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;
+}