summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Guthrie <colin@mageia.org>2011-08-09 02:02:39 +0200
committerColin Guthrie <colin@mageia.org>2011-08-10 14:22:55 +0200
commit479e7bcd6eb283750ee13d2270610d6d814add08 (patch)
treee3f3c58aefc0f4ab6f7af94125c8d10a7ce6b117
parent546e67904788639d6c27a173f57f29bcc46ea410 (diff)
Add UI to select the formats supported by the receiver attached to a digitial sink
-rw-r--r--src/mainwindow.cc42
-rw-r--r--src/mainwindow.h9
-rw-r--r--src/pavucontrol.cc63
-rw-r--r--src/pavucontrol.glade93
-rw-r--r--src/pavucontrol.h1
-rw-r--r--src/sinkwidget.cc76
-rw-r--r--src/sinkwidget.h19
7 files changed, 293 insertions, 10 deletions
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index 7e49e36..906a5d9 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -298,10 +298,10 @@ void MainWindow::updateCard(const pa_card_info &info) {
updateDeviceVisibility();
}
-void MainWindow::updateSink(const pa_sink_info &info) {
+bool MainWindow::updateSink(const pa_sink_info &info) {
SinkWidget *w;
bool is_new = false;
- const char *icon;
+ const char *icon, *profile;
std::set<pa_sink_port_info,sink_port_prio_compare> port_priorities;
if (sinkWidgets.count(info.index))
@@ -348,12 +348,18 @@ void MainWindow::updateSink(const pa_sink_info &info) {
w->activePort = info.active_port ? info.active_port->name : "";
+ /* Can we do digital? This is a hack just now... we should expose some nice properties to indicate we can do digitial*/
+ profile = pa_proplist_gets(info.proplist, "device.profile.name");
+ w->setDigital(profile && 0 == strncmp("iec958", profile, 6));
+
w->updating = false;
w->prepareMenu();
if (is_new)
updateDeviceVisibility();
+
+ return is_new;
}
static void suspended_callback(pa_stream *s, void *userdata) {
@@ -760,6 +766,38 @@ void MainWindow::updateRole(const pa_ext_stream_restore_info &info) {
updateDeviceVisibility();
}
+#if HAVE_EXT_DEVICE_RESTORE_API
+void MainWindow::updateDeviceInfo(const pa_ext_device_restore_info &info) {
+
+ if (sinkWidgets.count(info.index)) {
+ SinkWidget *w;
+ pa_format_info *format;
+
+ w = sinkWidgets[info.index];
+
+ w->updating = true;
+
+ /* Unselect everything */
+ for (int j = 1; j < PAVU_NUM_ENCODINGS; ++j)
+ w->encodings[j].widget->set_active(false);
+
+
+ for (uint8_t i = 0; i < info.n_formats; ++i) {
+ format = info.formats[i];
+ for (int j = 1; j < PAVU_NUM_ENCODINGS; ++j) {
+ if (format->encoding == w->encodings[j].encoding) {
+ w->encodings[j].widget->set_active(true);
+ break;
+ }
+ }
+ }
+
+ w->updating = false;
+ }
+}
+#endif
+
+
void MainWindow::updateVolumeMeter(uint32_t source_index, uint32_t sink_input_idx, double v) {
if (sink_input_idx != PA_INVALID_INDEX) {
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 559b639..dd8df6c 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -23,7 +23,9 @@
#include "pavucontrol.h"
#include <pulse/ext-stream-restore.h>
-
+#if HAVE_EXT_DEVICE_RESTORE_API
+# include <pulse/ext-device-restore.h>
+#endif
class CardWidget;
class SinkWidget;
@@ -39,7 +41,7 @@ public:
virtual ~MainWindow();
void updateCard(const pa_card_info &info);
- void updateSink(const pa_sink_info &info);
+ bool updateSink(const pa_sink_info &info);
void updateSource(const pa_source_info &info);
void updateSinkInput(const pa_sink_input_info &info);
void updateSourceOutput(const pa_source_output_info &info);
@@ -47,6 +49,9 @@ public:
void updateServer(const pa_server_info &info);
void updateVolumeMeter(uint32_t source_index, uint32_t sink_input_index, double v);
void updateRole(const pa_ext_stream_restore_info &info);
+#if HAVE_EXT_DEVICE_RESTORE_API
+ void updateDeviceInfo(const pa_ext_device_restore_info &info);
+#endif
void removeCard(uint32_t index);
void removeSink(uint32_t index);
diff --git a/src/pavucontrol.cc b/src/pavucontrol.cc
index 4270fa7..4f2f0e5 100644
--- a/src/pavucontrol.cc
+++ b/src/pavucontrol.cc
@@ -88,7 +88,11 @@ void card_cb(pa_context *, const pa_card_info *i, int eol, void *userdata) {
w->updateCard(*i);
}
-void sink_cb(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
+#if HAVE_EXT_DEVICE_RESTORE_API
+static void ext_device_restore_subscribe_cb(pa_context *c, uint32_t idx, void *userdata);
+#endif
+
+void sink_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) {
MainWindow *w = static_cast<MainWindow*>(userdata);
if (eol < 0) {
@@ -104,7 +108,12 @@ void sink_cb(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
return;
}
+#if HAVE_EXT_DEVICE_RESTORE_API
+ if (w->updateSink(*i))
+ ext_device_restore_subscribe_cb(c, i->index, w);
+#else
w->updateSink(*i);
+#endif
}
void source_cb(pa_context *, const pa_source_info *i, int eol, void *userdata) {
@@ -251,6 +260,43 @@ static void ext_stream_restore_subscribe_cb(pa_context *c, void *userdata) {
pa_operation_unref(o);
}
+#if HAVE_EXT_DEVICE_RESTORE_API
+void ext_device_restore_read_cb(
+ pa_context *,
+ const pa_ext_device_restore_info *i,
+ int eol,
+ void *userdata) {
+
+ MainWindow *w = static_cast<MainWindow*>(userdata);
+
+ if (eol < 0) {
+ dec_outstanding(w);
+ g_debug(_("Failed to initialize device restore extension: %s"), pa_strerror(pa_context_errno(context)));
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding(w);
+ return;
+ }
+
+ /* Do something with a widget when this part is written */
+ w->updateDeviceInfo(*i);
+}
+
+static void ext_device_restore_subscribe_cb(pa_context *c, uint32_t idx, void *userdata) {
+ MainWindow *w = static_cast<MainWindow*>(userdata);
+ pa_operation *o;
+
+ if (!(o = pa_ext_device_restore_read_sink_formats(c, idx, ext_device_restore_read_cb, w))) {
+ show_error(_("pa_ext_device_restore_read_sink_formats() failed"));
+ return;
+ }
+
+ pa_operation_unref(o);
+}
+#endif
+
void ext_device_manager_read_cb(
pa_context *,
const pa_ext_device_manager_info *,
@@ -485,6 +531,21 @@ void context_state_callback(pa_context *c, void *userdata) {
} else
g_debug(_("Failed to initialize stream_restore extension: %s"), pa_strerror(pa_context_errno(context)));
+#if HAVE_EXT_DEVICE_RESTORE_API
+ /* TODO Change this to just the test function */
+ if ((o = pa_ext_device_restore_read_sink_formats_all(c, ext_device_restore_read_cb, w))) {
+ pa_operation_unref(o);
+ n_outstanding++;
+
+ pa_ext_device_restore_set_subscribe_cb(c, ext_device_restore_subscribe_cb, w);
+
+ if ((o = pa_ext_device_restore_subscribe(c, 1, NULL, NULL)))
+ pa_operation_unref(o);
+
+ } else
+ g_debug(_("Failed to initialize device restore extension: %s"), pa_strerror(pa_context_errno(context)));
+#endif
+
if ((o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, w))) {
pa_operation_unref(o);
n_outstanding++;
diff --git a/src/pavucontrol.glade b/src/pavucontrol.glade
index c8b5a02..1d14f81 100644
--- a/src/pavucontrol.glade
+++ b/src/pavucontrol.glade
@@ -393,6 +393,91 @@
</packing>
</child>
<child>
+ <object class="GtkTable" id="encodingSelect">
+ <property name="can_focus">False</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <child>
+ <object class="GtkCheckButton" id="encodingFormatPCM">
+ <property name="label" translatable="yes">PCM</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="encodingFormatAC3">
+ <property name="label" translatable="yes">AC3</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="encodingFormatDTS">
+ <property name="label" translatable="yes">DTS</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="encodingFormatEAC3">
+ <property name="label" translatable="yes">EAC3</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="encodingFormatMPEG">
+ <property name="label" translatable="yes">MPEG</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkVBox" id="channelsVBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -407,7 +492,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
@@ -1069,7 +1154,7 @@
<child>
<object class="GtkLabel" id="connectingLabel">
<property name="can_focus">False</property>
- <property name="label" translatable="no">...</property>
+ <property name="label">...</property>
<property name="use_markup">True</property>
</object>
<packing>
@@ -1130,6 +1215,10 @@
<property name="invisible_char">●</property>
<property name="activates_default">True</property>
<property name="width_chars">60</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="expand">True</property>
diff --git a/src/pavucontrol.h b/src/pavucontrol.h
index e16c20e..65cb913 100644
--- a/src/pavucontrol.h
+++ b/src/pavucontrol.h
@@ -40,6 +40,7 @@
#endif
#define HAVE_SOURCE_OUTPUT_VOLUMES PA_CHECK_VERSION(0,99,0)
+#define HAVE_EXT_DEVICE_RESTORE_API PA_CHECK_VERSION(0,99,0)
enum SinkInputType {
SINK_INPUT_ALL,
diff --git a/src/sinkwidget.cc b/src/sinkwidget.cc
index c797e68..6b5e86f 100644
--- a/src/sinkwidget.cc
+++ b/src/sinkwidget.cc
@@ -22,14 +22,47 @@
#include <config.h>
#endif
-#include <canberra-gtk.h>
-
#include "sinkwidget.h"
+#include <canberra-gtk.h>
+#if HAVE_EXT_DEVICE_RESTORE_API
+# include <pulse/format.h>
+# include <pulse/ext-device-restore.h>
+#endif
+
#include "i18n.h"
SinkWidget::SinkWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& x) :
DeviceWidget(cobject, x) {
+#if HAVE_EXT_DEVICE_RESTORE_API
+ uint8_t i = 0;
+
+ x->get_widget("encodingSelect", encodingSelect);
+
+ encodings[i].encoding = PA_ENCODING_PCM;
+ x->get_widget("encodingFormatPCM", encodings[i].widget);
+ encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange));
+
+ ++i;
+ encodings[i].encoding = PA_ENCODING_AC3_IEC61937;
+ x->get_widget("encodingFormatAC3", encodings[i].widget);
+ encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange));
+
+ ++i;
+ encodings[i].encoding = PA_ENCODING_EAC3_IEC61937;
+ x->get_widget("encodingFormatEAC3", encodings[i].widget);
+ encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange));
+
+ ++i;
+ encodings[i].encoding = PA_ENCODING_MPEG_IEC61937;
+ x->get_widget("encodingFormatMPEG", encodings[i].widget);
+ encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange));
+
+ ++i;
+ encodings[i].encoding = PA_ENCODING_DTS_IEC61937;
+ x->get_widget("encodingFormatDTS", encodings[i].widget);
+ encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange));
+#endif
}
SinkWidget* SinkWidget::create(MainWindow* mainWindow) {
@@ -120,3 +153,42 @@ void SinkWidget::onPortChange() {
}
}
}
+
+void SinkWidget::setDigital(bool digital) {
+#if HAVE_EXT_DEVICE_RESTORE_API
+ if (digital)
+ encodingSelect->show();
+ else
+ encodingSelect->hide();
+#endif
+}
+
+void SinkWidget::onEncodingsChange() {
+#if HAVE_EXT_DEVICE_RESTORE_API
+ pa_operation* o;
+ uint8_t n_formats = 0;
+ pa_format_info **formats;
+
+ if (updating)
+ return;
+
+ formats = (pa_format_info**)malloc(sizeof(pa_format_info*) * PAVU_NUM_ENCODINGS);
+
+ for (int i = 0; i < PAVU_NUM_ENCODINGS; ++i) {
+ if (encodings[i].widget->get_active()) {
+ formats[n_formats] = pa_format_info_new();
+ formats[n_formats]->encoding = encodings[i].encoding;
+ ++n_formats;
+ }
+ }
+
+ if (!(o = pa_ext_device_restore_save_sink_formats(get_context(), index, n_formats, formats, NULL, NULL))) {
+ show_error(_("pa_ext_device_restore_save_sink_formats() failed"));
+ free(formats);
+ return;
+ }
+
+ free(formats);
+ pa_operation_unref(o);
+#endif
+} \ No newline at end of file
diff --git a/src/sinkwidget.h b/src/sinkwidget.h
index 3fbd7aa..4b79879 100644
--- a/src/sinkwidget.h
+++ b/src/sinkwidget.h
@@ -22,9 +22,19 @@
#define sinkwidget_h
#include "pavucontrol.h"
-
#include "devicewidget.h"
+#if HAVE_EXT_DEVICE_RESTORE_API
+# include <pulse/format.h>
+
+# define PAVU_NUM_ENCODINGS 5
+
+typedef struct {
+ pa_encoding encoding;
+ Gtk::CheckButton *widget;
+} encodingList;
+#endif
+
class SinkWidget : public DeviceWidget {
public:
SinkWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& x);
@@ -34,12 +44,19 @@ public:
uint32_t index, monitor_index, card_index;
bool can_decibel;
+#if HAVE_EXT_DEVICE_RESTORE_API
+ encodingList encodings[PAVU_NUM_ENCODINGS];
+ Gtk::Table *encodingSelect;
+#endif
+
virtual void onMuteToggleButton();
virtual void executeVolumeUpdate();
virtual void onDefaultToggleButton();
+ void setDigital(bool);
protected:
virtual void onPortChange();
+ virtual void onEncodingsChange();
};
#endif