devicewidget: Add a latency offset spinbutton
This change adds the ability to change the latency offset of a port with pavucontrol.
This commit is contained in:
parent
8af6520c60
commit
d03f9ffac2
|
@ -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();
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
@ -394,19 +394,77 @@
|
|||
<property name="position">1</property>
|
||||
</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>
|
||||
|
|
Loading…
Reference in New Issue