[pulseaudio-discuss] [PATCH 3/3] devicewidget: Add a latency offset spinbutton

poljar (Damir Jelić) poljarinho at gmail.com
Thu Jul 26 06:42:11 PDT 2012


From: "poljar (Damir Jelić)" <poljarinho at gmail.com>

This change adds the ability to change the latency offset of a port with
pavucontrol.
---
 src/devicewidget.cc   | 48 ++++++++++++++++++++++++++--
 src/devicewidget.h    |  9 ++++--
 src/mainwindow.cc     | 59 ++++++++++++++++++++++++++++++++++
 src/pavucontrol.glade | 87 +++++++++++++++++++++++++++++++++++++++++----------
 4 files changed, 182 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..b981542 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -252,6 +252,18 @@ 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;
+    PortInfo *activePort;
+
+    it = ports.find(w->activePort);
+
+    if (it != ports.end()) {
+        activePort = &(it->second);
+        w->setLatencyOffset(activePort->latency_offset);
+    }
+}
+
 void MainWindow::updateCard(const pa_card_info &info) {
     CardWidget *w;
     bool is_new = false;
@@ -304,6 +316,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 +359,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 +406,13 @@ bool MainWindow::updateSink(const pa_sink_info &info) {
 
     w->activePort = info.active_port ? info.active_port->name : "";
 
+    if (info.card) {
+        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 +514,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 +563,13 @@ void MainWindow::updateSource(const pa_source_info &info) {
 
     w->activePort = info.active_port ? info.active_port->name : "";
 
+    if (info.card) {
+        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"><b>Latency offset:</b></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>
-- 
1.7.11.3



More information about the pulseaudio-discuss mailing list