From 70f80cdee60dfebaa93d16ec0fbbaa2728ea8a23 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 25 Aug 2022 11:35:19 +0200 Subject: Add comments --- src/main.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++---------- src/mainwindow.cpp | 7 ++++- src/slxoutput.cpp | 3 +- 3 files changed, 81 insertions(+), 18 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 _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 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); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4860f2b..9ae66d3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -12,7 +12,6 @@ MainWindow::~MainWindow() } -// Need to pass newSink as new widget's sink isn't set here yet, so always empty SlxOutput* MainWindow::getOutput(const QString &id, bool isSink, const QString &newTitle) { SlxOutput* w = _widgets.value(id, nullptr); @@ -52,6 +51,9 @@ SlxOutput* MainWindow::getOutput(const QString &id, bool isSink, const QString & return w; } +/** + * Mark all entries as unused. + */ void MainWindow::mark() { for (auto *w : _widgets) { @@ -59,6 +61,9 @@ void MainWindow::mark() } } +/** + * Remove all entries marked as unused. + */ void MainWindow::sweep() { for (QMutableMapIterator it(_widgets); it.hasNext(); ) { diff --git a/src/slxoutput.cpp b/src/slxoutput.cpp index d46b0e9..0ac38b1 100644 --- a/src/slxoutput.cpp +++ b/src/slxoutput.cpp @@ -50,6 +50,7 @@ void SlxOutput::volumeSliderChanged(int value) { if (g_IgnoreGui) return; + // Update slider every 100ms if (_volumeTimer.isActive()) return; _volumeTimer.start(); @@ -78,5 +79,5 @@ void SlxOutput::updateOutput(const QString &name, bool isDefault, bool isMuted, volumeSlider->setEnabled(isSink()); } muteToggleButton->setEnabled(isSink()); - unused = false; + unused = false; // Entry was updated, so it's being used } -- cgit v1.2.3-55-g7522 > 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
#!/bin/ash
# Copyright (c) 2003..2006 - RZ Uni Freiburg
# Copyright (c) 2006..2008 - OpenSLX GmbH
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your feedback to feedback@openslx.org
#
# General information about OpenSLX can be found under http://openslx.org
#
# universal (distro independent) configuration script for OpenSLX linux
# diskless clients (executed in stage3 within initial ramfs). The file-
# system setup is completed when servconfig starts

#############################################################################
# check for configuration files to source

# functions common for all distros, messages contains all error and
# info output
. /etc/messages
. /etc/functions
# load distro specific configuration functions. Distro specific functions may
# overwrite functions defined in /etc/functions
. /etc/distro-functions
. /etc/slxsystem.conf

# script run timer
[ $DEBUGLEVEL -eq 8 ] && echo "** SW setup started at $(sysup)"

# heavy debugging output in level 3 and below 8 ...
[ $DEBUGLEVEL -gt 3 -a $DEBUGLEVEL -lt 8 -o $DEBUGLEVEL -eq 12 ] && \
  set -x

#############################################################################
# read and unify configuration options - default configuration file, from
# dhcp, ldap ...
# wait for the appearance of configuration from several sources
cfgcomplete
. /etc/initramfs-setup
[ $DEBUGLEVEL -eq 8 ] && echo "** Config info is complete at $(sysup)"

# copy additional configuration and var files and directories
# admins can place there files in /var/lib/openslx/config/...
# to be packed during stage2 into (/srv/dxs)/tftpboot/client-config...)
cp -a /rootfs/* /mnt 2>/dev/null

# copy passwd file for temporarily (within stage3 configuration) use by chown
cp /mnt/etc/passwd /etc

# set greeting and add information on booted system
len=$(expr length ${SLXVERSION}${SYSTEM_NAME})
if [ $len -le 28 ] ; then
  vdstr="Stateless Workstation (V${SLXVERSION}/${SYSTEM_NAME})"
  smax=28
else
  vdstr="V${SLXVERSION}/${SYSTEM_NAME}"
  smax=52
fi
while [ $len -le $smax ] ; do
  vdstr="$vdstr "
  len=$(($len + 1))
done
len=$(expr length ${host_name})
while [ $len -le 30 ] ; do
  space="$space "
  len=$(($len + 1))
done
echo "
   WELCOME TO                 $space        \n (\l)
           _____  ______  ______ __    __    _______ __     __    __
          /  _   |   _   |   ___|  |  |  |  |   ____|  |   |  |  |  |
         |  | |  |  |_|  |  |_  |   |    |  |  |___ |  |        /  /
         |  | |  |   ___/|   _|      |   |   ____   |  |     |    |
         |  |_|  |  |    |  |___|  |  |  |   ____|  |  |___ /  /
           _____/|__|    |______|__|  |__|  |_______|______|__|  |__|

   $vdstr (c) <OpenSLX.ORG>
" >/mnt/etc/issue

#############################################################################
# set localization and add entries to initialize keytable and consolefont to
# boot.slx
if [ -z &q