summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpoljar (Damir Jelić) <poljarinho@gmail.com>2012-07-26 15:42:11 +0200
committerTanu Kaskinen <tanuk@iki.fi>2012-07-27 09:25:14 +0300
commitd03f9ffac22a867c746015cf84d3e87fef3ec5ee (patch)
tree45bac51b1d04d6a91cd3cf2c19c9afdb483dafd3
parent8af6520c602afd75418ac5b33f75f40a4706dcb5 (diff)
devicewidget: Add a latency offset spinbutton
This change adds the ability to change the latency offset of a port with pavucontrol.
-rw-r--r--src/devicewidget.cc48
-rw-r--r--src/devicewidget.h9
-rw-r--r--src/mainwindow.cc54
-rw-r--r--src/pavucontrol.glade87
4 files changed, 177 insertions, 21 deletions
diff --git a/src/devicewidget.cc b/src/devicewidget.cc
index dda1763..ba08cc8 100644
--- a/src/devicewidget.cc
+++ b/src/devicewidget.cc
@@ -32,13 +32,16 @@
/*** DeviceWidget ***/
DeviceWidget::DeviceWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& x) :
- MinimalStreamWidget(cobject, x) {
+ MinimalStreamWidget(cobject, x),
+ offsetButtonEnabled(false) {
x->get_widget("lockToggleButton", lockToggleButton);
x->get_widget("muteToggleButton", muteToggleButton);
x->get_widget("defaultToggleButton", defaultToggleButton);
x->get_widget("portSelect", portSelect);
x->get_widget("portList", portList);
+ x->get_widget("offsetSelect", offsetSelect);
+ x->get_widget("offsetButton", offsetButton);
this->signal_button_press_event().connect(sigc::mem_fun(*this, &DeviceWidget::onContextTriggerEvent));
muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &DeviceWidget::onMuteToggleButton));
@@ -54,9 +57,13 @@ DeviceWidget::DeviceWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Buil
portList->pack_start(portModel.desc);
portList->signal_changed().connect(sigc::mem_fun(*this, &DeviceWidget::onPortChange));
+ offsetButton->signal_value_changed().connect(sigc::mem_fun(*this, &DeviceWidget::onOffsetChange));
for (unsigned i = 0; i < PA_CHANNELS_MAX; i++)
channelWidgets[i] = NULL;
+
+ offsetAdjustment = Gtk::Adjustment::create(0.0, -2000.0, 2000.0, 10.0, 50.0, 0.0);
+ offsetButton->configure(offsetAdjustment, 0, 2);
}
void DeviceWidget::init(MainWindow* mainWindow, Glib::ustring deviceType) {
@@ -120,6 +127,27 @@ void DeviceWidget::onMuteToggleButton() {
void DeviceWidget::onDefaultToggleButton() {
}
+void DeviceWidget::onOffsetChange() {
+ pa_operation *o;
+ int64_t offset;
+ std::ostringstream card_stream;
+ Glib::ustring card_name;
+
+ if (!offsetButtonEnabled)
+ return;
+
+ offset = offsetButton->get_value() * 1000.0;
+ card_stream << card_index;
+ card_name = card_stream.str();
+
+ if (!(o = pa_context_set_port_latency_offset(get_context(),
+ card_name.c_str(), activePort.c_str(), offset, NULL, NULL))) {
+ show_error(_("pa_context_set_port_latency_offset() failed"));
+ return;
+ }
+ pa_operation_unref(o);
+}
+
void DeviceWidget::setDefault(bool isDefault) {
defaultToggleButton->set_active(isDefault);
/*defaultToggleButton->set_sensitive(!isDefault);*/
@@ -133,6 +161,12 @@ bool DeviceWidget::timeoutEvent() {
void DeviceWidget::executeVolumeUpdate() {
}
+void DeviceWidget::setLatencyOffset(int64_t offset) {
+ offsetButtonEnabled = false;
+ offsetButton->set_value(offset / 1000.0);
+ offsetButtonEnabled = true;
+}
+
void DeviceWidget::setBaseVolume(pa_volume_t v) {
for (int i = 0; i < channelMap.channels; i++)
@@ -157,10 +191,18 @@ void DeviceWidget::prepareMenu() {
if (active_idx >= 0)
portList->set_active(active_idx);
- if (ports.size() > 0)
+ if (ports.size() > 0) {
portSelect->show();
- else
+
+ if (pa_context_get_server_protocol_version(get_context()) >= 27)
+ offsetSelect->show();
+ else
+ offsetSelect->hide();
+
+ } else {
portSelect->hide();
+ offsetSelect->hide();
+ }
}
bool DeviceWidget::onContextTriggerEvent(GdkEventButton* event) {
diff --git a/src/devicewidget.h b/src/devicewidget.h
index 94f14e6..f099e6e 100644
--- a/src/devicewidget.h
+++ b/src/devicewidget.h
@@ -42,6 +42,9 @@ public:
uint32_t index, card_index;
Gtk::ToggleButton *lockToggleButton, *muteToggleButton, *defaultToggleButton;
+ Gtk::SpinButton *offsetButton;
+
+ bool offsetButtonEnabled;
pa_channel_map channelMap;
pa_cvolume volume;
@@ -52,6 +55,8 @@ public:
virtual void onDefaultToggleButton();
virtual void setDefault(bool isDefault);
virtual bool onContextTriggerEvent(GdkEventButton*);
+ virtual void setLatencyOffset(int64_t offset);
+ void onOffsetChange();
sigc::connection timeoutConnection;
@@ -75,7 +80,6 @@ protected:
Gtk::Menu contextMenu;
Gtk::MenuItem rename;
-
/* Tree model columns */
class ModelColumns : public Gtk::TreeModel::ColumnRecord
{
@@ -90,9 +94,10 @@ protected:
ModelColumns portModel;
- Gtk::HBox *portSelect;
+ Gtk::HBox *portSelect, *offsetSelect;
Gtk::ComboBox *portList;
Glib::RefPtr<Gtk::ListStore> treeModel;
+ Glib::RefPtr<Gtk::Adjustment> offsetAdjustment;
private:
Glib::ustring mDeviceType;
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index fe085ef..ac5f916 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -252,6 +252,17 @@ static void set_icon_name_fallback(Gtk::Image *i, const char *name, Gtk::IconSiz
}
}
+static void updatePorts(DeviceWidget *w, std::map<Glib::ustring, PortInfo> &ports) {
+ std::map<Glib::ustring, PortInfo>::iterator it;
+
+ it = ports.find(w->activePort);
+
+ if (it != ports.end()) {
+ PortInfo &activePort = it->second;
+ w->setLatencyOffset(activePort.latency_offset);
+ }
+}
+
void MainWindow::updateCard(const pa_card_info &info) {
CardWidget *w;
bool is_new = false;
@@ -304,6 +315,37 @@ void MainWindow::updateCard(const pa_card_info &info) {
w->ports[p.name] = p;
}
+ /* Because the port info for sinks and sources is discontinued we need
+ * to update the port info for them here. */
+
+ if (w->hasSinks) {
+ std::map<uint32_t, SinkWidget*>::iterator it;
+
+ for (it = sinkWidgets.begin() ; it != sinkWidgets.end(); it++) {
+ SinkWidget *sw = (*it).second;
+
+ if (sw->card_index == w->index) {
+ sw->updating = true;
+ updatePorts(sw, w->ports);
+ sw->updating = false;
+ }
+ }
+ }
+
+ if (w->hasSources) {
+ std::map<uint32_t, SourceWidget*>::iterator it;
+
+ for (it = sourceWidgets.begin() ; it != sourceWidgets.end(); it++) {
+ SourceWidget *sw = (*it).second;
+
+ if (sw->card_index == w->index) {
+ sw->updating = true;
+ updatePorts(sw, w->ports);
+ sw->updating = false;
+ }
+ }
+ }
+
w->updating = false;
w->prepareMenu();
@@ -316,6 +358,7 @@ bool MainWindow::updateSink(const pa_sink_info &info) {
SinkWidget *w;
bool is_new = false;
const char *icon;
+ std::map<uint32_t, CardWidget*>::iterator cw;
std::set<pa_sink_port_info,sink_port_prio_compare> port_priorities;
if (sinkWidgets.count(info.index))
@@ -362,6 +405,11 @@ bool MainWindow::updateSink(const pa_sink_info &info) {
w->activePort = info.active_port ? info.active_port->name : "";
+ cw = cardWidgets.find(info.card);
+
+ if (cw != cardWidgets.end())
+ updatePorts(w, cw->second->ports);
+
#ifdef PA_SINK_SET_FORMATS
w->setDigital(info.flags & PA_SINK_SET_FORMATS);
#endif
@@ -463,6 +511,7 @@ void MainWindow::updateSource(const pa_source_info &info) {
SourceWidget *w;
bool is_new = false;
const char *icon;
+ std::map<uint32_t, CardWidget*>::iterator cw;
std::set<pa_source_port_info,source_port_prio_compare> port_priorities;
if (sourceWidgets.count(info.index))
@@ -511,6 +560,11 @@ void MainWindow::updateSource(const pa_source_info &info) {
w->activePort = info.active_port ? info.active_port->name : "";
+ cw = cardWidgets.find(info.card);
+
+ if (cw != cardWidgets.end())
+ updatePorts(w, cw->second->ports);
+
w->updating = false;
w->prepareMenu();
diff --git a/src/pavucontrol.glade b/src/pavucontrol.glade
index e569ba6..befdee0 100644
--- a/src/pavucontrol.glade
+++ b/src/pavucontrol.glade
@@ -277,11 +277,11 @@
<property name="spacing">3</property>
<child>
<object class="GtkToggleButton" id="muteToggleButton">
+ <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Mute audio</property>
- <property name="use_action_appearance">False</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image20">
@@ -300,11 +300,11 @@
</child>
<child>
<object class="GtkToggleButton" id="lockToggleButton">
+ <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Lock channels together</property>
- <property name="use_action_appearance">False</property>
<property name="relief">none</property>
<property name="active">True</property>
<child>
@@ -324,11 +324,11 @@
</child>
<child>
<object class="GtkToggleButton" id="defaultToggleButton">
+ <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Set as fallback</property>
- <property name="use_action_appearance">False</property>
<child>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
@@ -395,18 +395,76 @@
</packing>
</child>
<child>
+ <object class="GtkHBox" id="offsetSelect">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">&lt;b&gt;Latency offset:&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="offsetButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</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>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">ms</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </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>
+ <placeholder/>
+ </child>
+ <child>
<object class="GtkCheckButton" id="encodingFormatPCM">
<property name="label" translatable="yes">PCM</property>
+ <property name="use_action_appearance">False</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>
@@ -414,10 +472,10 @@
<child>
<object class="GtkCheckButton" id="encodingFormatAC3">
<property name="label" translatable="yes">AC3</property>
+ <property name="use_action_appearance">False</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>
@@ -428,10 +486,10 @@
<child>
<object class="GtkCheckButton" id="encodingFormatDTS">
<property name="label" translatable="yes">DTS</property>
+ <property name="use_action_appearance">False</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>
@@ -442,10 +500,10 @@
<child>
<object class="GtkCheckButton" id="encodingFormatEAC3">
<property name="label" translatable="yes">EAC3</property>
+ <property name="use_action_appearance">False</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>
@@ -456,10 +514,10 @@
<child>
<object class="GtkCheckButton" id="encodingFormatMPEG">
<property name="label" translatable="yes">MPEG</property>
+ <property name="use_action_appearance">False</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>
@@ -469,14 +527,11 @@
<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>
+ <property name="position">3</property>
</packing>
</child>
<child>
@@ -494,7 +549,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">3</property>
+ <property name="position">4</property>
</packing>
</child>
</object>
@@ -1316,10 +1371,10 @@
<child>
<object class="GtkButton" id="deviceButton">
<property name="label" translatable="yes">Device</property>
+ <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <property name="use_action_appearance">False</property>
<property name="relief">half</property>
<property name="xalign">0</property>
</object>
@@ -1344,11 +1399,11 @@
<property name="spacing">3</property>
<child>
<object class="GtkToggleButton" id="muteToggleButton">
+ <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Mute audio</property>
- <property name="use_action_appearance">False</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image20">
@@ -1367,11 +1422,11 @@
</child>
<child>
<object class="GtkToggleButton" id="lockToggleButton">
+ <property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Lock channels together</property>
- <property name="use_action_appearance">False</property>
<property name="relief">none</property>
<property name="active">True</property>
<child>