summaryrefslogtreecommitdiffstats
path: root/src/pavucontrol.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/pavucontrol.cc')
-rw-r--r--src/pavucontrol.cc172
1 files changed, 143 insertions, 29 deletions
diff --git a/src/pavucontrol.cc b/src/pavucontrol.cc
index f012d08..4b1d502 100644
--- a/src/pavucontrol.cc
+++ b/src/pavucontrol.cc
@@ -31,6 +31,7 @@
// #include <canberra-gtk.h>
+#include "helper.h"
#include "pavucontrol.h"
#include "minimalstreamwidget.h"
#include "channel.h"
@@ -50,6 +51,9 @@
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QString>
+#include <QRegularExpression>
+
+#include <unistd.h>
static pa_context* context = nullptr;
static pa_mainloop_api* api = nullptr;
@@ -57,6 +61,7 @@ static int n_outstanding = 0;
static int default_tab = 0;
static bool retry = false;
static int reconnect_timeout = 1;
+static QRegularExpression select_output;
void show_error(const char *txt) {
char buf[256];
@@ -77,7 +82,7 @@ static void dec_outstanding(MainWindow *w) {
}
}
-void card_cb(pa_context *, const pa_card_info *i, int eol, void *userdata) {
+static void card_cb(pa_context *, const pa_card_info *i, int eol, void *userdata) {
MainWindow *w = static_cast<MainWindow*>(userdata);
if (eol < 0) {
@@ -96,6 +101,69 @@ void card_cb(pa_context *, const pa_card_info *i, int eol, void *userdata) {
w->updateCard(*i);
}
+static void card_cb_setdef(pa_context * ctx, const pa_card_info *i, int eol, void *) {
+ if (eol < 0) {
+ if (pa_context_errno(context) == PA_ERR_NOENTITY)
+ return;
+
+ show_error(QObject::tr("Card callback failure").toUtf8().constData());
+ return;
+ }
+
+ if (eol > 0) {
+ return;
+ }
+
+ // TODO Check stuff
+
+ std::set<pa_card_profile_info2 *, profile_prio_compare> profile_priorities;
+ std::map<QByteArray, PortInfo> ports;
+ QMap<QString, ProfileGroup> profiles;
+
+ profile_priorities.clear();
+ for (pa_card_profile_info2 ** p_profile = i->profiles2; p_profile && *p_profile != nullptr; ++p_profile) {
+ profile_priorities.insert(*p_profile);
+ }
+
+ populatePorts(*i, ports);
+ groupProfiles(profile_priorities, ports, profiles);
+
+ ProfileGroup *best = nullptr;
+ for (auto &p : profiles) {
+ if (p.getProfileName().contains(select_output)) {
+ // Maybe we should track per-profile availability too and scan the list...
+ if (best == nullptr || p.available) {
+ best = &p;
+ if (p.available)
+ break;
+ }
+ }
+ }
+
+ if (best != nullptr) {
+ // Can we do this inside the callback?
+ pa_operation* o;
+ const auto *entry = best->entries.first().id.constData();
+ printf("Selecting profile %s\n", entry);
+ if (!(o = pa_context_set_card_profile_by_index(ctx, i->index, entry, nullptr, nullptr))) {
+ printf("pa_context_set_card_profile_by_index() failed\n");
+ return;
+ }
+ pa_operation_unref(o);
+ }
+}
+
+static void context_state_callback_setdef(pa_context *c, void *) {
+ if (pa_context_get_state(c) == PA_CONTEXT_READY) {
+ pa_operation *o;
+ if (!(o = pa_context_get_card_info_list(c, card_cb_setdef, nullptr))) {
+ show_error(QObject::tr("pa_context_get_card_info_list() failed").toUtf8().constData());
+ return;
+ }
+ pa_operation_unref(o);
+ }
+}
+
#if HAVE_EXT_DEVICE_RESTORE_API
static void ext_device_restore_subscribe_cb(pa_context *c, pa_device_type_t type, uint32_t idx, void *userdata);
#endif
@@ -597,12 +665,7 @@ pa_context* get_context(void) {
return context;
}
-gboolean connect_to_pulse(gpointer userdata) {
- MainWindow *w = static_cast<MainWindow*>(userdata);
-
- if (context)
- return false;
-
+void connectToPulse(void) {
pa_proplist *proplist = pa_proplist_new();
pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, QObject::tr("PulseAudio Volume Control").toUtf8().constData());
pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "org.PulseAudio.pavucontrol");
@@ -613,6 +676,15 @@ gboolean connect_to_pulse(gpointer userdata) {
g_assert(context);
pa_proplist_free(proplist);
+}
+
+gboolean connect_to_pulse(gpointer userdata) {
+ MainWindow *w = static_cast<MainWindow*>(userdata);
+
+ if (context)
+ return false;
+
+ connectToPulse();
pa_context_set_state_callback(context, context_state_callback, w);
@@ -643,6 +715,7 @@ gboolean connect_to_pulse(gpointer userdata) {
}
int main(int argc, char *argv[]) {
+ int exit_code = 0, have_regex = 0;
signal(SIGPIPE, SIG_IGN);
@@ -678,35 +751,76 @@ int main(int argc, char *argv[]) {
QCommandLineOption maximizeOption(QStringList() << QStringLiteral("maximize") << QStringLiteral("m"), QObject::tr("Maximize the window."));
parser.addOption(maximizeOption);
+ QCommandLineOption selectOption(QStringList() << QStringLiteral("output") << QStringLiteral("o"), QObject::tr("Select a specific output configuration and quit."), QStringLiteral("regex"));
+ parser.addOption(selectOption);
+
parser.process(app);
default_tab = parser.value(tabOption).toInt();
retry = parser.isSet(retryOption);
+ if (parser.isSet(selectOption)) {
+ select_output = QRegularExpression(parser.value(selectOption));
+ if (!select_output.isValid()) {
+ select_output = QRegularExpression(QRegularExpression::escape(parser.value(selectOption)));
+ }
+ have_regex = select_output.isValid();
+ }
- // ca_context_set_driver(ca_gtk_context_get(), "pulse");
-
- MainWindow* mainWindow = new MainWindow();
- if(parser.isSet(maximizeOption))
- mainWindow->showMaximized();
-
- pa_glib_mainloop *m = pa_glib_mainloop_new(g_main_context_default());
- g_assert(m);
- api = pa_glib_mainloop_get_api(m);
- g_assert(api);
+ if (have_regex) {
+ pa_mainloop *m = pa_mainloop_new();
+ g_assert(m);
+ api = pa_mainloop_get_api(m);
+ g_assert(api);
+
+ connectToPulse();
+ pa_context_set_state_callback(context, context_state_callback_setdef, nullptr);
+ if (pa_context_connect(context, nullptr, PA_CONTEXT_NOFAIL, nullptr) >= 0) {
+ if (pa_context_errno(context) == PA_ERR_INVALID) {
+ printf("pa_context_errno = PA_ERR_INVALID\n");
+ exit_code = 1;
+ } else {
+ int evs;
+ int tries = 10;
+ exit_code = 100;
+ // WTF
+ while ((evs = pa_mainloop_iterate(m, 0, &exit_code)) >= 0) {
+ if (evs == 0) {
+ if (--tries == 0)
+ break;
+ usleep(100000);
+ }
+ }
+ printf("Exit: %d\n", exit_code);
+ }
+ }
- connect_to_pulse(mainWindow);
- if (reconnect_timeout >= 0) {
- mainWindow->show();
- app.exec();
- }
+ if (context)
+ pa_context_unref(context);
+ pa_mainloop_free(m);
+ } else {
+ MainWindow* mainWindow = new MainWindow();
+ if(parser.isSet(maximizeOption))
+ mainWindow->showMaximized();
+
+ pa_glib_mainloop *m = pa_glib_mainloop_new(g_main_context_default());
+ g_assert(m);
+ api = pa_glib_mainloop_get_api(m);
+ g_assert(api);
+
+ connect_to_pulse(mainWindow);
+ if (reconnect_timeout >= 0) {
+ mainWindow->show();
+ app.exec();
+ }
- if (reconnect_timeout < 0)
- show_error(QObject::tr("Fatal Error: Unable to connect to PulseAudio").toUtf8().constData());
+ if (reconnect_timeout < 0)
+ show_error(QObject::tr("Fatal Error: Unable to connect to PulseAudio").toUtf8().constData());
- delete mainWindow;
+ delete mainWindow;
- if (context)
- pa_context_unref(context);
- pa_glib_mainloop_free(m);
+ if (context)
+ pa_context_unref(context);
+ pa_glib_mainloop_free(m);
+ }
- return 0;
+ return exit_code;
}