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

poljar (Damir Jelić) poljarinho at gmail.com
Sun Jul 22 06:23:26 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   | 47 ++++++++++++++++++++++++++--
 src/devicewidget.h    | 10 ++++--
 src/mainwindow.cc     | 35 +++++++++++++++++++++
 src/pavucontrol.glade | 87 +++++++++++++++++++++++++++++++++++++++++----------
 4 files changed, 159 insertions(+), 20 deletions(-)

diff --git a/src/devicewidget.cc b/src/devicewidget.cc
index dda1763..bb30c0d 100644
--- a/src/devicewidget.cc
+++ b/src/devicewidget.cc
@@ -39,6 +39,8 @@ DeviceWidget::DeviceWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Buil
     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 +56,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 +126,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 +160,14 @@ bool DeviceWidget::timeoutEvent() {
 void DeviceWidget::executeVolumeUpdate() {
 }
 
+void DeviceWidget::updatePorts(std::map<Glib::ustring, PortInfo> &ports) {
+    if (pa_context_get_server_protocol_version(get_context()) >= 27) {
+        offsetButtonEnabled = false;
+        offsetButton->set_value(ports.find(activePort)->second.latency_offset / 1000.0);
+        offsetButtonEnabled = true;
+    }
+}
+
 void DeviceWidget::setBaseVolume(pa_volume_t v) {
 
     for (int i = 0; i < channelMap.channels; i++)
@@ -157,10 +192,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..2d66204 100644
--- a/src/devicewidget.h
+++ b/src/devicewidget.h
@@ -24,6 +24,7 @@
 #include "pavucontrol.h"
 
 #include "minimalstreamwidget.h"
+#include "cardwidget.h"
 
 class MainWindow;
 class ChannelWidget;
@@ -42,6 +43,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 +56,8 @@ public:
     virtual void onDefaultToggleButton();
     virtual void setDefault(bool isDefault);
     virtual bool onContextTriggerEvent(GdkEventButton*);
+    virtual void updatePorts(std::map<Glib::ustring, PortInfo> &ports);
+    void onOffsetChange();
 
     sigc::connection timeoutConnection;
 
@@ -75,7 +81,6 @@ protected:
     Gtk::Menu contextMenu;
     Gtk::MenuItem rename;
 
-
     /* Tree model columns */
     class ModelColumns : public Gtk::TreeModel::ColumnRecord
     {
@@ -90,9 +95,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 b167943..add797e 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -309,6 +309,37 @@ void MainWindow::updateCard(const pa_card_info &info) {
         }
     }
 
+    /* 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;
+                sw->updatePorts(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;
+                sw->updatePorts(w->ports);
+                sw->updating = false;
+            }
+        }
+    }
+
     w->updating = false;
 
     w->prepareMenu();
@@ -367,6 +398,8 @@ bool MainWindow::updateSink(const pa_sink_info &info) {
 
     w->activePort = info.active_port ? info.active_port->name : "";
 
+    w->updatePorts(cardWidgets[info.card]->ports);
+
 #ifdef PA_SINK_SET_FORMATS
     w->setDigital(info.flags & PA_SINK_SET_FORMATS);
 #endif
@@ -516,6 +549,8 @@ void MainWindow::updateSource(const pa_source_info &info) {
 
     w->activePort = info.active_port ? info.active_port->name : "";
 
+    w->updatePorts(cardWidgets[info.card]->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.2



More information about the pulseaudio-discuss mailing list