2006-04-21 14:51:33 +00:00
|
|
|
/***
|
|
|
|
This file is part of pavucontrol.
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2008-08-05 17:42:21 +00:00
|
|
|
Copyright 2006-2008 Lennart Poettering
|
2008-04-20 22:13:20 +00:00
|
|
|
Copyright 2008 Sjoerd Simons <sjoerd@luon.net>
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
pavucontrol is free software; you can redistribute it and/or modify
|
2008-08-05 17:42:21 +00:00
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
pavucontrol is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
General Public License for more details.
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2007-05-23 23:34:52 +00:00
|
|
|
You should have received a copy of the GNU General Public License
|
2008-08-05 17:42:21 +00:00
|
|
|
along with pavucontrol. If not, see <http://www.gnu.org/licenses/>.
|
2006-04-21 14:51:33 +00:00
|
|
|
***/
|
|
|
|
|
2009-03-18 20:58:17 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2009-08-27 03:41:11 +00:00
|
|
|
#include <pulse/pulseaudio.h>
|
2006-06-20 23:48:27 +00:00
|
|
|
#include <pulse/glib-mainloop.h>
|
2008-08-05 17:05:33 +00:00
|
|
|
#include <pulse/ext-stream-restore.h>
|
2009-06-28 14:57:59 +00:00
|
|
|
#include <pulse/ext-device-manager.h>
|
2006-04-21 14:51:33 +00:00
|
|
|
|
2009-08-27 03:41:11 +00:00
|
|
|
#include <canberra-gtk.h>
|
|
|
|
|
|
|
|
#include "pavucontrol.h"
|
2008-08-05 18:45:24 +00:00
|
|
|
#include "i18n.h"
|
2009-03-15 12:42:45 +00:00
|
|
|
#include "minimalstreamwidget.h"
|
2009-03-15 12:54:56 +00:00
|
|
|
#include "channelwidget.h"
|
|
|
|
#include "streamwidget.h"
|
2009-03-15 13:32:28 +00:00
|
|
|
#include "cardwidget.h"
|
2009-03-16 12:41:02 +00:00
|
|
|
#include "sinkwidget.h"
|
2009-03-16 12:45:53 +00:00
|
|
|
#include "sourcewidget.h"
|
2009-03-16 12:59:01 +00:00
|
|
|
#include "sinkinputwidget.h"
|
2009-03-16 13:05:58 +00:00
|
|
|
#include "sourceoutputwidget.h"
|
2009-03-16 13:13:34 +00:00
|
|
|
#include "rolewidget.h"
|
2009-03-16 12:59:01 +00:00
|
|
|
#include "mainwindow.h"
|
2008-08-05 18:45:24 +00:00
|
|
|
|
2010-04-20 18:06:01 +00:00
|
|
|
static pa_context* context = NULL;
|
|
|
|
static pa_mainloop_api* api = NULL;
|
2006-08-07 13:50:02 +00:00
|
|
|
static int n_outstanding = 0;
|
2006-08-07 13:29:46 +00:00
|
|
|
|
2006-04-21 19:24:32 +00:00
|
|
|
void show_error(const char *txt) {
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "%s: %s", txt, pa_strerror(pa_context_errno(context)));
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 19:24:32 +00:00
|
|
|
Gtk::MessageDialog dialog(buf, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true);
|
|
|
|
dialog.run();
|
|
|
|
|
|
|
|
Gtk::Main::quit();
|
|
|
|
}
|
|
|
|
|
2006-08-07 13:50:02 +00:00
|
|
|
static void dec_outstanding(MainWindow *w) {
|
2006-08-07 15:26:52 +00:00
|
|
|
if (n_outstanding <= 0)
|
|
|
|
return;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2010-04-20 19:22:38 +00:00
|
|
|
if (--n_outstanding <= 0) {
|
2006-08-07 13:50:02 +00:00
|
|
|
w->get_window()->set_cursor();
|
2010-04-20 19:22:38 +00:00
|
|
|
w->setConnectionState(true);
|
|
|
|
}
|
2006-08-07 13:50:02 +00:00
|
|
|
}
|
|
|
|
|
2009-02-28 17:11:41 +00:00
|
|
|
void card_cb(pa_context *, const pa_card_info *i, int eol, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
|
|
|
if (eol < 0) {
|
|
|
|
if (pa_context_errno(context) == PA_ERR_NOENTITY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
show_error(_("Card callback failure"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eol > 0) {
|
|
|
|
dec_outstanding(w);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateCard(*i);
|
|
|
|
}
|
|
|
|
|
2006-04-21 19:24:32 +00:00
|
|
|
void sink_cb(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
|
2006-04-21 14:51:33 +00:00
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol < 0) {
|
2008-08-19 15:36:18 +00:00
|
|
|
if (pa_context_errno(context) == PA_ERR_NOENTITY)
|
|
|
|
return;
|
|
|
|
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("Sink callback failure"));
|
2006-04-21 14:51:33 +00:00
|
|
|
return;
|
2006-08-07 13:50:02 +00:00
|
|
|
}
|
2006-04-21 14:51:33 +00:00
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol > 0) {
|
|
|
|
dec_outstanding(w);
|
2006-04-21 14:51:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateSink(*i);
|
|
|
|
}
|
|
|
|
|
2006-04-21 19:24:32 +00:00
|
|
|
void source_cb(pa_context *, const pa_source_info *i, int eol, void *userdata) {
|
2006-04-21 14:51:33 +00:00
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol < 0) {
|
2008-08-19 15:36:18 +00:00
|
|
|
if (pa_context_errno(context) == PA_ERR_NOENTITY)
|
|
|
|
return;
|
|
|
|
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("Source callback failure"));
|
2006-04-21 14:51:33 +00:00
|
|
|
return;
|
2006-08-07 13:50:02 +00:00
|
|
|
}
|
2006-04-21 14:51:33 +00:00
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol > 0) {
|
|
|
|
dec_outstanding(w);
|
2006-04-21 14:51:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateSource(*i);
|
|
|
|
}
|
|
|
|
|
2006-04-21 19:24:32 +00:00
|
|
|
void sink_input_cb(pa_context *, const pa_sink_input_info *i, int eol, void *userdata) {
|
2006-04-21 14:51:33 +00:00
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol < 0) {
|
2008-08-19 15:36:18 +00:00
|
|
|
if (pa_context_errno(context) == PA_ERR_NOENTITY)
|
|
|
|
return;
|
|
|
|
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("Sink input callback failure"));
|
2006-04-21 14:51:33 +00:00
|
|
|
return;
|
2006-08-07 13:50:02 +00:00
|
|
|
}
|
2006-04-21 14:51:33 +00:00
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol > 0) {
|
|
|
|
dec_outstanding(w);
|
2006-04-21 14:51:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateSinkInput(*i);
|
|
|
|
}
|
|
|
|
|
2008-04-20 22:13:20 +00:00
|
|
|
void source_output_cb(pa_context *, const pa_source_output_info *i, int eol, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol < 0) {
|
2008-08-19 15:36:18 +00:00
|
|
|
if (pa_context_errno(context) == PA_ERR_NOENTITY)
|
|
|
|
return;
|
|
|
|
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("Source output callback failure"));
|
2008-08-05 17:05:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eol > 0) {
|
2008-06-17 20:24:54 +00:00
|
|
|
|
|
|
|
if (n_outstanding > 0) {
|
|
|
|
/* At this point all notebook pages have been populated, so
|
|
|
|
* let's open one that isn't empty */
|
|
|
|
|
|
|
|
if (w->sinkInputWidgets.size() > 0)
|
|
|
|
w->notebook->set_current_page(0);
|
|
|
|
else if (w->sourceOutputWidgets.size() > 0)
|
|
|
|
w->notebook->set_current_page(1);
|
|
|
|
else if (w->sourceWidgets.size() > 0 && w->sinkWidgets.size() == 0)
|
|
|
|
w->notebook->set_current_page(3);
|
|
|
|
else
|
|
|
|
w->notebook->set_current_page(2);
|
|
|
|
}
|
2008-05-15 23:07:40 +00:00
|
|
|
|
2008-04-20 22:13:20 +00:00
|
|
|
dec_outstanding(w);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateSourceOutput(*i);
|
|
|
|
}
|
|
|
|
|
2006-05-20 17:28:50 +00:00
|
|
|
void client_cb(pa_context *, const pa_client_info *i, int eol, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol < 0) {
|
2008-08-19 15:36:18 +00:00
|
|
|
if (pa_context_errno(context) == PA_ERR_NOENTITY)
|
|
|
|
return;
|
|
|
|
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("Client callback failure"));
|
2006-05-20 17:28:50 +00:00
|
|
|
return;
|
2006-08-07 13:50:02 +00:00
|
|
|
}
|
2006-05-20 17:28:50 +00:00
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
if (eol > 0) {
|
|
|
|
dec_outstanding(w);
|
2006-05-20 17:28:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateClient(*i);
|
|
|
|
}
|
|
|
|
|
2007-09-02 23:38:55 +00:00
|
|
|
void server_info_cb(pa_context *, const pa_server_info *i, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
|
|
|
if (!i) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("Server info callback failure"));
|
2007-09-02 23:38:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateServer(*i);
|
|
|
|
dec_outstanding(w);
|
|
|
|
}
|
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
void ext_stream_restore_read_cb(
|
2009-03-25 21:06:33 +00:00
|
|
|
pa_context *,
|
2008-08-05 17:05:33 +00:00
|
|
|
const pa_ext_stream_restore_info *i,
|
|
|
|
int eol,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
|
|
|
if (eol < 0) {
|
2009-04-08 02:09:38 +00:00
|
|
|
dec_outstanding(w);
|
|
|
|
g_debug(_("Failed to initialize stream_restore extension: %s"), pa_strerror(pa_context_errno(context)));
|
2008-08-05 17:05:33 +00:00
|
|
|
w->deleteEventRoleWidget();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eol > 0) {
|
|
|
|
dec_outstanding(w);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->updateRole(*i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ext_stream_restore_subscribe_cb(pa_context *c, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
pa_operation *o;
|
|
|
|
|
|
|
|
if (!(o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_ext_stream_restore_read() failed"));
|
2008-08-05 17:05:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
|
2009-06-28 14:57:59 +00:00
|
|
|
void ext_device_manager_read_cb(
|
|
|
|
pa_context *,
|
|
|
|
const pa_ext_device_manager_info *,
|
|
|
|
int eol,
|
|
|
|
void *userdata) {
|
|
|
|
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
|
|
|
if (eol < 0) {
|
|
|
|
dec_outstanding(w);
|
|
|
|
g_debug(_("Failed to initialize device manager extension: %s"), pa_strerror(pa_context_errno(context)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->canRenameDevices = true;
|
|
|
|
|
|
|
|
if (eol > 0) {
|
|
|
|
dec_outstanding(w);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do something with a widget when this part is written */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ext_device_manager_subscribe_cb(pa_context *c, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
pa_operation *o;
|
|
|
|
|
|
|
|
if (!(o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, w))) {
|
|
|
|
show_error(_("pa_ext_device_manager_read() failed"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
|
|
|
switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
|
|
|
|
case PA_SUBSCRIPTION_EVENT_SINK:
|
|
|
|
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
|
|
|
w->removeSink(index);
|
|
|
|
else {
|
|
|
|
pa_operation *o;
|
|
|
|
if (!(o = pa_context_get_sink_info_by_index(c, index, sink_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_sink_info_by_index() failed"));
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
break;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
case PA_SUBSCRIPTION_EVENT_SOURCE:
|
|
|
|
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
|
|
|
w->removeSource(index);
|
|
|
|
else {
|
|
|
|
pa_operation *o;
|
|
|
|
if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_source_info_by_index() failed"));
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
break;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
|
|
|
|
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
|
|
|
w->removeSinkInput(index);
|
|
|
|
else {
|
|
|
|
pa_operation *o;
|
|
|
|
if (!(o = pa_context_get_sink_input_info(c, index, sink_input_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_sink_input_info() failed"));
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
break;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2008-04-20 22:13:20 +00:00
|
|
|
case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
|
|
|
|
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
|
|
|
w->removeSourceOutput(index);
|
|
|
|
else {
|
|
|
|
pa_operation *o;
|
|
|
|
if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_sink_input_info() failed"));
|
2008-04-20 22:13:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2006-05-20 17:28:50 +00:00
|
|
|
case PA_SUBSCRIPTION_EVENT_CLIENT:
|
|
|
|
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
|
|
|
w->removeClient(index);
|
|
|
|
else {
|
|
|
|
pa_operation *o;
|
|
|
|
if (!(o = pa_context_get_client_info(c, index, client_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_client_info() failed"));
|
2006-05-20 17:28:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
break;
|
2007-09-02 23:38:55 +00:00
|
|
|
|
|
|
|
case PA_SUBSCRIPTION_EVENT_SERVER: {
|
2009-02-28 17:11:41 +00:00
|
|
|
pa_operation *o;
|
|
|
|
if (!(o = pa_context_get_server_info(c, server_info_cb, w))) {
|
|
|
|
show_error(_("pa_context_get_server_info() failed"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2007-09-02 23:38:55 +00:00
|
|
|
}
|
2009-02-28 17:11:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PA_SUBSCRIPTION_EVENT_CARD:
|
|
|
|
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
|
|
|
w->removeCard(index);
|
|
|
|
else {
|
|
|
|
pa_operation *o;
|
|
|
|
if (!(o = pa_context_get_card_info_by_index(c, index, card_cb, w))) {
|
|
|
|
show_error(_("pa_context_get_card_info_by_index() failed"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
/* Forward Declaration */
|
|
|
|
gboolean connect_to_pulse(gpointer userdata);
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
void context_state_callback(pa_context *c, void *userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
g_assert(c);
|
|
|
|
|
|
|
|
switch (pa_context_get_state(c)) {
|
|
|
|
case PA_CONTEXT_UNCONNECTED:
|
|
|
|
case PA_CONTEXT_CONNECTING:
|
|
|
|
case PA_CONTEXT_AUTHORIZING:
|
|
|
|
case PA_CONTEXT_SETTING_NAME:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PA_CONTEXT_READY: {
|
|
|
|
pa_operation *o;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2010-04-20 18:06:01 +00:00
|
|
|
/* Create event widget immediately so it's first in the list */
|
|
|
|
w->createEventRoleWidget();
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
pa_context_set_subscribe_callback(c, subscribe_cb, w);
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2007-09-02 23:38:55 +00:00
|
|
|
if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)
|
|
|
|
(PA_SUBSCRIPTION_MASK_SINK|
|
|
|
|
PA_SUBSCRIPTION_MASK_SOURCE|
|
|
|
|
PA_SUBSCRIPTION_MASK_SINK_INPUT|
|
2008-04-20 22:13:20 +00:00
|
|
|
PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
|
2007-09-02 23:38:55 +00:00
|
|
|
PA_SUBSCRIPTION_MASK_CLIENT|
|
2009-02-28 17:11:41 +00:00
|
|
|
PA_SUBSCRIPTION_MASK_SERVER|
|
|
|
|
PA_SUBSCRIPTION_MASK_CARD), NULL, NULL))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_subscribe() failed"));
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
|
|
|
|
2009-03-18 21:01:03 +00:00
|
|
|
/* Keep track of the outstanding callbacks for UI tweaks */
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding = 0;
|
|
|
|
|
2007-09-02 23:38:55 +00:00
|
|
|
if (!(o = pa_context_get_server_info(c, server_info_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_server_info() failed"));
|
2007-09-02 23:38:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding++;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-05-20 17:28:50 +00:00
|
|
|
if (!(o = pa_context_get_client_info_list(c, client_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_client_info_list() failed"));
|
2006-05-20 17:28:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding++;
|
2006-05-20 17:28:50 +00:00
|
|
|
|
2009-02-28 17:11:41 +00:00
|
|
|
if (!(o = pa_context_get_card_info_list(c, card_cb, w))) {
|
|
|
|
show_error(_("pa_context_get_card_info_list() failed"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding++;
|
2009-02-28 17:11:41 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
if (!(o = pa_context_get_sink_info_list(c, sink_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_sink_info_list() failed"));
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding++;
|
2006-04-21 14:51:33 +00:00
|
|
|
|
|
|
|
if (!(o = pa_context_get_source_info_list(c, source_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_source_info_list() failed"));
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding++;
|
2006-04-21 14:51:33 +00:00
|
|
|
|
|
|
|
if (!(o = pa_context_get_sink_input_info_list(c, sink_input_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_sink_input_info_list() failed"));
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding++;
|
2006-08-07 13:50:02 +00:00
|
|
|
|
2008-04-20 22:13:20 +00:00
|
|
|
if (!(o = pa_context_get_source_output_info_list(c, source_output_cb, w))) {
|
2008-08-05 18:45:24 +00:00
|
|
|
show_error(_("pa_context_get_source_output_info_list() failed"));
|
2008-04-20 22:13:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
pa_operation_unref(o);
|
2009-02-28 20:37:44 +00:00
|
|
|
n_outstanding++;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2009-06-28 14:57:59 +00:00
|
|
|
/* These calls are not always supported */
|
2008-08-05 17:05:33 +00:00
|
|
|
if ((o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, w))) {
|
|
|
|
pa_operation_unref(o);
|
|
|
|
n_outstanding++;
|
|
|
|
|
|
|
|
pa_ext_stream_restore_set_subscribe_cb(c, ext_stream_restore_subscribe_cb, w);
|
|
|
|
|
|
|
|
if ((o = pa_ext_stream_restore_subscribe(c, 1, NULL, NULL)))
|
|
|
|
pa_operation_unref(o);
|
|
|
|
|
|
|
|
} else
|
2009-04-08 02:09:38 +00:00
|
|
|
g_debug(_("Failed to initialize stream_restore extension: %s"), pa_strerror(pa_context_errno(context)));
|
|
|
|
|
2009-06-28 14:57:59 +00:00
|
|
|
if ((o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, w))) {
|
|
|
|
pa_operation_unref(o);
|
|
|
|
n_outstanding++;
|
|
|
|
|
|
|
|
pa_ext_device_manager_set_subscribe_cb(c, ext_device_manager_subscribe_cb, w);
|
|
|
|
|
|
|
|
if ((o = pa_ext_device_manager_subscribe(c, 1, NULL, NULL)))
|
|
|
|
pa_operation_unref(o);
|
|
|
|
|
|
|
|
} else
|
|
|
|
g_debug(_("Failed to initialize device manager extension: %s"), pa_strerror(pa_context_errno(context)));
|
|
|
|
|
2008-08-05 17:05:33 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
case PA_CONTEXT_FAILED:
|
2010-04-20 19:01:39 +00:00
|
|
|
g_debug(_("Connection failed, attempting reconnect"));
|
|
|
|
|
2010-04-20 19:22:38 +00:00
|
|
|
w->setConnectionState(false);
|
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
w->removeAllWidgets();
|
|
|
|
w->updateDeviceVisibility();
|
|
|
|
pa_context_unref(context);
|
|
|
|
context = NULL;
|
|
|
|
|
|
|
|
g_timeout_add_seconds(1, connect_to_pulse, w);
|
2006-04-21 19:24:32 +00:00
|
|
|
return;
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
case PA_CONTEXT_TERMINATED:
|
|
|
|
default:
|
2006-04-21 19:24:32 +00:00
|
|
|
Gtk::Main::quit();
|
|
|
|
return;
|
2006-04-21 14:51:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
pa_context* get_context(void) {
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean connect_to_pulse(gpointer userdata) {
|
|
|
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
return false;
|
2010-04-20 18:06:01 +00:00
|
|
|
|
|
|
|
pa_proplist *proplist = pa_proplist_new();
|
|
|
|
pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, _("PulseAudio Volume Control"));
|
|
|
|
pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "org.PulseAudio.pavucontrol");
|
|
|
|
pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "audio-card");
|
|
|
|
pa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
|
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
context = pa_context_new_with_proplist(api, NULL, proplist);
|
|
|
|
g_assert(context);
|
2010-04-20 18:06:01 +00:00
|
|
|
|
|
|
|
pa_proplist_free(proplist);
|
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
pa_context_set_state_callback(context, context_state_callback, w);
|
2010-04-20 18:06:01 +00:00
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
if (pa_context_connect(context, NULL, PA_CONTEXT_NOFAIL, NULL) < 0) {
|
|
|
|
show_error(_("Fatal Error: Unable to connect context"));
|
|
|
|
Gtk::Main::quit();
|
|
|
|
return false;
|
|
|
|
}
|
2010-04-20 18:06:01 +00:00
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
return false;
|
2009-03-15 13:32:28 +00:00
|
|
|
}
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
int main(int argc, char *argv[]) {
|
2008-08-05 18:45:24 +00:00
|
|
|
|
|
|
|
/* Initialize the i18n stuff */
|
|
|
|
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
|
|
|
|
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
|
|
|
textdomain(GETTEXT_PACKAGE);
|
|
|
|
|
2006-04-22 18:21:12 +00:00
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
Gtk::Main kit(argc, argv);
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2008-08-19 15:36:18 +00:00
|
|
|
ca_context_set_driver(ca_gtk_context_get(), "pulse");
|
|
|
|
|
2009-03-21 10:28:42 +00:00
|
|
|
MainWindow* mainWindow = MainWindow::create();
|
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
pa_glib_mainloop *m = pa_glib_mainloop_new(g_main_context_default());
|
|
|
|
g_assert(m);
|
2010-04-20 18:06:01 +00:00
|
|
|
api = pa_glib_mainloop_get_api(m);
|
2006-04-21 14:51:33 +00:00
|
|
|
g_assert(api);
|
2008-06-12 11:26:06 +00:00
|
|
|
|
2010-04-20 19:01:39 +00:00
|
|
|
connect_to_pulse(mainWindow);
|
2007-11-20 02:14:59 +00:00
|
|
|
|
2006-04-21 14:51:33 +00:00
|
|
|
Gtk::Main::run(*mainWindow);
|
|
|
|
delete mainWindow;
|
|
|
|
|
2006-04-21 19:24:32 +00:00
|
|
|
finish:
|
2006-04-21 14:51:33 +00:00
|
|
|
pa_context_unref(context);
|
|
|
|
pa_glib_mainloop_free(m);
|
|
|
|
}
|