#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;
}