diff options
author | Colin Guthrie <colin@mageia.org> | 2011-08-09 02:02:39 +0200 |
---|---|---|
committer | Colin Guthrie <colin@mageia.org> | 2011-08-10 14:22:55 +0200 |
commit | 479e7bcd6eb283750ee13d2270610d6d814add08 (patch) | |
tree | e3f3c58aefc0f4ab6f7af94125c8d10a7ce6b117 | |
parent | 546e67904788639d6c27a173f57f29bcc46ea410 (diff) |
Add UI to select the formats supported by the receiver attached to a digitial sink
-rw-r--r-- | src/mainwindow.cc | 42 | ||||
-rw-r--r-- | src/mainwindow.h | 9 | ||||
-rw-r--r-- | src/pavucontrol.cc | 63 | ||||
-rw-r--r-- | src/pavucontrol.glade | 93 | ||||
-rw-r--r-- | src/pavucontrol.h | 1 | ||||
-rw-r--r-- | src/sinkwidget.cc | 76 | ||||
-rw-r--r-- | src/sinkwidget.h | 19 |
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 |