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 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 - +#if HAVE_EXT_DEVICE_RESTORE_API +# include +#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(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(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(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 @@ -392,6 +392,91 @@ 1 + + + False + 2 + 3 + + + PCM + True + False + True + False + False + True + True + + + + + AC3 + True + True + False + False + True + + + 1 + 2 + + + + + DTS + True + True + False + False + True + + + 1 + 2 + + + + + EAC3 + True + True + False + False + True + + + 2 + 3 + + + + + MPEG + True + True + False + False + True + + + 1 + 2 + 1 + 2 + + + + + + + + False + False + 2 + + True @@ -407,7 +492,7 @@ False False - 2 + 3 @@ -1069,7 +1154,7 @@ False - ... + ... True @@ -1130,6 +1215,10 @@ True 60 + False + False + True + True True 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 #endif -#include - #include "sinkwidget.h" +#include +#if HAVE_EXT_DEVICE_RESTORE_API +# include +# include +#endif + #include "i18n.h" SinkWidget::SinkWidget(BaseObjectType* cobject, const Glib::RefPtr& 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 + +# 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& 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