summaryrefslogtreecommitdiffstats
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp89
1 files changed, 73 insertions, 16 deletions
diff --git a/src/main.cpp b/src/main.cpp
index a06f6f5..bf22453 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -31,47 +31,64 @@ bool g_IgnoreGui;
/** If not empty, on profile change, if profile belings to this card, make its sink default */
static QString _pendingCardDefault;
+/** While running, we want to set each port's volume to 100% the first time we see it. Unfortunately
+ * a port only startes to exist once its according profile is selected, so there is no way to have
+ * a simple "set everything to 100%" method run on startup, at least not without switching through
+ * all profiles on all cards, which sounds like it could be annoying and buggy. So do it this way
+ * for now.
+ */
static QSet<QString> _donePorts;
+/** Whe something changes, (re)start a short timeout first before actually updating the GUI, to
+ * avoid multiple updates in rapid succession, for example when changing the active profile.
+ */
static QTimer _updateDelay;
static MainWindow *_mainWindow;
+/**
+ * Queue a GUI update. By default, delay it by 50ms. If the timer is already active but hasn't
+ * expired yet, it will be restarted with the given timeout.
+ */
static void queueGuiUpdate(int ms = 50)
{
_updateDelay.start(ms);
}
+/**
+ * The actual GUI update logic. Iterate over all sinks and their ports, and add them to the GUI.
+ * Then iterate over all non-selected profiles, and add them to the GUI too, so we have a simple, flat
+ * list of "outputs" to select, which should be a bit more easy to grasp for a non-technical person
+ * trying to make the computer go beep. (Hopefully)
+ */
static void updateActiveOutput()
{
- g_IgnoreGui = true;
- _mainWindow->mark();
+ g_IgnoreGui = true; // Block GUI updates
+ _mainWindow->mark(); // Mark all items in the lists as unused
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());
+ qint64 volume = sink->volume();
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();
+ (int)volume, (int)sink->isMuted());
QString id = cardName + sink->name() + port->name();
- if (active) {
- if (!_donePorts.contains(id)) {
- _donePorts.insert(id);
- if (volume < 60000) {
- volume = 65535;
- sink->setVolume(volume);
- }
+ // Only once, update port volume to be 100% if it's low
+ if (active && !_donePorts.contains(id)) {
+ _donePorts.insert(id);
+ if (volume < 60000) {
+ volume = 65535;
+ sink->setVolume(volume);
}
}
QString title = sink->description() + ", " + port->description();
@@ -79,13 +96,16 @@ static void updateActiveOutput()
active, sink->isMuted(), sink->isVolumeWritable() ? sink->volume() : -1, QString(), sink->name(), port->name());
}
}
+ // Now find all the profiles from all cards that are not active and add an entry to the list for each one
for (auto *card : cards) {
QString cardDescription = card->description();
int profIndex = -1;
for (auto *profile : card->profiles()) {
profIndex++;
+ // Ignore the active profile, and profiles that are unavailable
if (profIndex == card->activeProfileIndex() || profile->availability() == PulseAudioQt::Profile::Unavailable)
continue;
+ // No point in selecting something that doesn't have any way to output sound
if (profile->sinks() == 0)
continue;
printf("[ ] Output: '%s', sinks: %d\n",
@@ -97,25 +117,34 @@ static void updateActiveOutput()
}
}
printf("`--------------------------------------------ยด\n");
- _mainWindow->sweep();
- g_IgnoreGui = false;
+ _mainWindow->sweep(); // Removes all items from the list that are still marked unused, i.e. updateOutput() was not called on those
+ g_IgnoreGui = false; // Allow GUI updates again
}
+/**
+ * Called after the user set a GUI entry as default that represents a profile, after the active profile
+ * or the list of available ports changed. Only after this happened can we actually set as default the sink/port
+ * that was created from selecting that profile as the default sink.
+ */
static void checkShouldSetDefault()
{
- if (_pendingCardDefault.isEmpty())
+ if (_pendingCardDefault.isEmpty()) // No switch actually pending
return;
+ // Otherwise, it's the ID of the card that the profile belongs to that the user wants to set as default
printf("Pending card default to %s\n", _pendingCardDefault.toLocal8Bit().constData());
auto *i = PulseAudioQt::Context::instance();
int cardIdx = -1;
+ // Find the current index of that card
for (auto *card : i->cards()) {
cardIdx++;
if (card->name() == _pendingCardDefault && !card->ports().isEmpty())
break;
}
+ // Then iterate over all sinks until we find one that belongs to the card
for (auto *sink : i->sinks()) {
if (sink->cardIndex() == cardIdx) {
printf("MATCH SET!\n");
+ // Set as default, unmute, and clear the pending switch
sink->setDefault(true);
sink->setMuted(false);
_pendingCardDefault.clear();
@@ -123,6 +152,9 @@ static void checkShouldSetDefault()
}
}
+/**
+ * Called when PA tells us about a new card; start listening to signals we're interesed in.
+ */
static void newCardAppeared(PulseAudioQt::Card *card)
{
//if (_doneCards.contains(card->name()))
@@ -148,6 +180,9 @@ static void newCardAppeared(PulseAudioQt::Card *card)
*/
}
+/**
+ * Called when PA tells us about a new sink; start listening to signals we're interested in.
+ */
static void newSinkAppeared(PulseAudioQt::Sink *sink)
{
for (auto *port : sink->ports()) {
@@ -170,6 +205,9 @@ static void newSinkAppeared(PulseAudioQt::Sink *sink)
queueGuiUpdate();
}
+/**
+ * Mute/unmute sink by its string identifier.
+ */
void setMuted(const QString &sink, bool muted)
{
auto *i = PulseAudioQt::Context::instance();
@@ -182,6 +220,9 @@ void setMuted(const QString &sink, bool muted)
queueGuiUpdate();
}
+/**
+ * Set a sink's volume, by its string identifier.
+ */
void setSinkVolume(const QString &sink, int volume)
{
auto *i = PulseAudioQt::Context::instance();
@@ -194,6 +235,12 @@ void setSinkVolume(const QString &sink, int volume)
}
}
+/**
+ * Set the given card as default, preferably enabling the given profile
+ * on it. If this card doesn't have a profile with the given ID, try
+ * to use a profile that contains the string "Duplex" in its name,
+ * otherwise, just use the first profile available.
+ */
void enableCard(const QString &card, const QString &profile)
{
auto *i = PulseAudioQt::Context::instance();
@@ -242,12 +289,20 @@ void enableCard(const QString &card, const QString &profile)
}
} else {
matchingCard->setActiveProfileIndex(profileIdx);
+ // Remember the ID of the card we switched to; we need this as only after PA is done
+ // switching to the desired profile will we see any sink belonging to it, so we can only
+ // set the according sink as fallback after that happens. See checkShouldSetDefault().
_pendingCardDefault = matchingCard->name();
}
}
queueGuiUpdate();
}
+/**
+ * Set given sink as default sink, unmute it, and switch to its
+ * port as passed to this function. If the sink doesn't have a
+ * port with this ID, nothing happens.
+ */
void enableSink(const QString &sink, const QString &port)
{
auto *i = PulseAudioQt::Context::instance();
@@ -277,6 +332,8 @@ int main(int argc, char **argv)
printf("Pa is %p = %d\n", i, (int)i->isValid());
printf("Cards: %d\n", (int)i->cards().size());
+ // There's no signal, or no way to check if we're connected to PA, so
+ // just wait a bit and hope for the best.
QTimer::singleShot(100, [=]() {
for (auto *card : i->cards()) {
newCardAppeared(card);