add a special track for controlling event sound volume
This commit is contained in:
parent
7eacc12bfc
commit
a32b21a417
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
#include <pulse/glib-mainloop.h>
|
#include <pulse/glib-mainloop.h>
|
||||||
|
#include <pulse/ext-stream-restore.h>
|
||||||
|
|
||||||
#ifndef GLADE_FILE
|
#ifndef GLADE_FILE
|
||||||
#define GLADE_FILE "pavucontrol.glade"
|
#define GLADE_FILE "pavucontrol.glade"
|
||||||
|
@ -258,6 +259,18 @@ public:
|
||||||
virtual void prepareMenu();
|
virtual void prepareMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RoleWidget : public StreamWidget {
|
||||||
|
public:
|
||||||
|
RoleWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
|
||||||
|
static RoleWidget* create();
|
||||||
|
|
||||||
|
Glib::ustring role;
|
||||||
|
Glib::ustring device;
|
||||||
|
|
||||||
|
virtual void onMuteToggleButton();
|
||||||
|
virtual void executeVolumeUpdate();
|
||||||
|
};
|
||||||
|
|
||||||
class MainWindow : public Gtk::Window {
|
class MainWindow : public Gtk::Window {
|
||||||
public:
|
public:
|
||||||
MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
|
MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
|
||||||
|
@ -271,6 +284,7 @@ public:
|
||||||
void updateClient(const pa_client_info &info);
|
void updateClient(const pa_client_info &info);
|
||||||
void updateServer(const pa_server_info &info);
|
void updateServer(const pa_server_info &info);
|
||||||
void updateVolumeMeter(uint32_t source_index, uint32_t sink_input_index, double v);
|
void updateVolumeMeter(uint32_t source_index, uint32_t sink_input_index, double v);
|
||||||
|
void updateRole(const pa_ext_stream_restore_info &info);
|
||||||
|
|
||||||
void removeSink(uint32_t index);
|
void removeSink(uint32_t index);
|
||||||
void removeSource(uint32_t index);
|
void removeSource(uint32_t index);
|
||||||
|
@ -300,11 +314,17 @@ public:
|
||||||
virtual void onSourceTypeComboBoxChanged();
|
virtual void onSourceTypeComboBoxChanged();
|
||||||
|
|
||||||
void updateDeviceVisibility();
|
void updateDeviceVisibility();
|
||||||
|
void reallyUpdateDeviceVisibility();
|
||||||
void createMonitorStreamForSource(uint32_t source_idx);
|
void createMonitorStreamForSource(uint32_t source_idx);
|
||||||
void createMonitorStreamForSinkInput(uint32_t sink_input_idx, uint32_t sink_idx);
|
void createMonitorStreamForSinkInput(uint32_t sink_input_idx, uint32_t sink_idx);
|
||||||
|
|
||||||
void setIconFromProplist(Gtk::Image *icon, pa_proplist *l, const char *name);
|
void setIconFromProplist(Gtk::Image *icon, pa_proplist *l, const char *name);
|
||||||
|
|
||||||
|
RoleWidget *eventRoleWidget;
|
||||||
|
|
||||||
|
bool createEventRoleWidget();
|
||||||
|
void deleteEventRoleWidget();
|
||||||
|
|
||||||
Glib::ustring defaultSinkName, defaultSourceName;
|
Glib::ustring defaultSinkName, defaultSourceName;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -332,6 +352,8 @@ ChannelWidget::ChannelWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::
|
||||||
x->get_widget("volumeLabel", volumeLabel);
|
x->get_widget("volumeLabel", volumeLabel);
|
||||||
x->get_widget("volumeScale", volumeScale);
|
x->get_widget("volumeScale", volumeScale);
|
||||||
|
|
||||||
|
volumeScale->set_value(100);
|
||||||
|
|
||||||
volumeScale->signal_value_changed().connect(sigc::mem_fun(*this, &ChannelWidget::onVolumeScaleValueChanged));
|
volumeScale->signal_value_changed().connect(sigc::mem_fun(*this, &ChannelWidget::onVolumeScaleValueChanged));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,11 +424,12 @@ MinimalStreamWidget::MinimalStreamWidget(BaseObjectType* cobject, const Glib::Re
|
||||||
|
|
||||||
peakProgressBar.set_size_request(-1, 10);
|
peakProgressBar.set_size_request(-1, 10);
|
||||||
channelsVBox->pack_end(peakProgressBar, false, false);
|
channelsVBox->pack_end(peakProgressBar, false, false);
|
||||||
peakProgressBar.hide();
|
|
||||||
|
|
||||||
streamToggleButton->set_active(false);
|
streamToggleButton->set_active(false);
|
||||||
streamToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onStreamToggleButton));
|
streamToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onStreamToggleButton));
|
||||||
menu.signal_deactivate().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onMenuDeactivated));
|
menu.signal_deactivate().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onMenuDeactivated));
|
||||||
|
|
||||||
|
peakProgressBar.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinimalStreamWidget::prepareMenu(void) {
|
void MinimalStreamWidget::prepareMenu(void) {
|
||||||
|
@ -469,6 +492,8 @@ void MinimalStreamWidget::updatePeak(double v) {
|
||||||
peakProgressBar.set_sensitive(FALSE);
|
peakProgressBar.set_sensitive(FALSE);
|
||||||
peakProgressBar.set_fraction(0);
|
peakProgressBar.set_fraction(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableVolumeMeter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinimalStreamWidget::enableVolumeMeter() {
|
void MinimalStreamWidget::enableVolumeMeter() {
|
||||||
|
@ -850,6 +875,49 @@ void SourceOutputWidget::SourceMenuItem::onToggle() {
|
||||||
pa_operation_unref(o);
|
pa_operation_unref(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoleWidget::RoleWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
||||||
|
StreamWidget(cobject, x) {
|
||||||
|
|
||||||
|
lockToggleButton->hide();
|
||||||
|
streamToggleButton->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
RoleWidget* RoleWidget::create() {
|
||||||
|
RoleWidget* w;
|
||||||
|
Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "streamWidget");
|
||||||
|
x->get_widget_derived("streamWidget", w);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoleWidget::onMuteToggleButton() {
|
||||||
|
StreamWidget::onMuteToggleButton();
|
||||||
|
|
||||||
|
executeVolumeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoleWidget::executeVolumeUpdate() {
|
||||||
|
pa_ext_stream_restore_info info;
|
||||||
|
|
||||||
|
if (updating)
|
||||||
|
return;
|
||||||
|
|
||||||
|
info.name = role.c_str();
|
||||||
|
info.channel_map.channels = 1;
|
||||||
|
info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
|
||||||
|
info.volume = volume;
|
||||||
|
info.device = device.c_str();
|
||||||
|
info.mute = muteToggleButton->get_active();
|
||||||
|
|
||||||
|
pa_operation* o;
|
||||||
|
if (!(o = pa_ext_stream_restore_write(context, PA_UPDATE_REPLACE, &info, 1, TRUE, NULL, NULL))) {
|
||||||
|
show_error("pa_ext_stream_restore_write() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_operation_unref(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*** MainWindow ***/
|
/*** MainWindow ***/
|
||||||
|
|
||||||
MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
||||||
|
@ -857,7 +925,8 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
|
||||||
showSinkInputType(SINK_INPUT_CLIENT),
|
showSinkInputType(SINK_INPUT_CLIENT),
|
||||||
showSinkType(SINK_ALL),
|
showSinkType(SINK_ALL),
|
||||||
showSourceOutputType(SOURCE_OUTPUT_CLIENT),
|
showSourceOutputType(SOURCE_OUTPUT_CLIENT),
|
||||||
showSourceType(SOURCE_NO_MONITOR) {
|
showSourceType(SOURCE_NO_MONITOR),
|
||||||
|
eventRoleWidget(NULL){
|
||||||
|
|
||||||
x->get_widget("streamsVBox", streamsVBox);
|
x->get_widget("streamsVBox", streamsVBox);
|
||||||
x->get_widget("recsVBox", recsVBox);
|
x->get_widget("recsVBox", recsVBox);
|
||||||
|
@ -943,10 +1012,10 @@ void MainWindow::updateSink(const pa_sink_info &info) {
|
||||||
|
|
||||||
w->defaultMenuItem.set_active(w->name == defaultSinkName);
|
w->defaultMenuItem.set_active(w->name == defaultSinkName);
|
||||||
|
|
||||||
|
w->updating = false;
|
||||||
|
|
||||||
if (is_new)
|
if (is_new)
|
||||||
updateDeviceVisibility();
|
updateDeviceVisibility();
|
||||||
|
|
||||||
w->updating = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void suspended_callback(pa_stream *s, void *userdata) {
|
static void suspended_callback(pa_stream *s, void *userdata) {
|
||||||
|
@ -1083,10 +1152,10 @@ void MainWindow::updateSource(const pa_source_info &info) {
|
||||||
|
|
||||||
w->defaultMenuItem.set_active(w->name == defaultSourceName);
|
w->defaultMenuItem.set_active(w->name == defaultSourceName);
|
||||||
|
|
||||||
|
w->updating = false;
|
||||||
|
|
||||||
if (is_new)
|
if (is_new)
|
||||||
updateDeviceVisibility();
|
updateDeviceVisibility();
|
||||||
|
|
||||||
w->updating = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setIconFromProplist(Gtk::Image *icon, pa_proplist *l, const char *def) {
|
void MainWindow::setIconFromProplist(Gtk::Image *icon, pa_proplist *l, const char *def) {
|
||||||
|
@ -1171,16 +1240,16 @@ void MainWindow::updateSinkInput(const pa_sink_input_info &info) {
|
||||||
w->setVolume(info.volume);
|
w->setVolume(info.volume);
|
||||||
w->muteToggleButton->set_active(info.mute);
|
w->muteToggleButton->set_active(info.mute);
|
||||||
|
|
||||||
|
w->updating = false;
|
||||||
|
|
||||||
if (is_new)
|
if (is_new)
|
||||||
updateDeviceVisibility();
|
updateDeviceVisibility();
|
||||||
|
|
||||||
w->updating = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateSourceOutput(const pa_source_output_info &info) {
|
void MainWindow::updateSourceOutput(const pa_source_output_info &info) {
|
||||||
SourceOutputWidget *w;
|
SourceOutputWidget *w;
|
||||||
bool is_new = false;
|
|
||||||
const char *app;
|
const char *app;
|
||||||
|
bool is_new = false;
|
||||||
|
|
||||||
if ((app = pa_proplist_gets(info.proplist, PA_PROP_APPLICATION_ID)))
|
if ((app = pa_proplist_gets(info.proplist, PA_PROP_APPLICATION_ID)))
|
||||||
if (strcmp(app, "org.PulseAudio.pavucontrol") == 0)
|
if (strcmp(app, "org.PulseAudio.pavucontrol") == 0)
|
||||||
|
@ -1194,7 +1263,6 @@ void MainWindow::updateSourceOutput(const pa_source_output_info &info) {
|
||||||
w->index = info.index;
|
w->index = info.index;
|
||||||
w->clientIndex = info.client;
|
w->clientIndex = info.client;
|
||||||
w->mainWindow = this;
|
w->mainWindow = this;
|
||||||
is_new = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w->updating = true;
|
w->updating = true;
|
||||||
|
@ -1216,10 +1284,10 @@ void MainWindow::updateSourceOutput(const pa_source_output_info &info) {
|
||||||
|
|
||||||
setIconFromProplist(w->iconImage, info.proplist, "audio-input-microphone");
|
setIconFromProplist(w->iconImage, info.proplist, "audio-input-microphone");
|
||||||
|
|
||||||
|
w->updating = false;
|
||||||
|
|
||||||
if (is_new)
|
if (is_new)
|
||||||
updateDeviceVisibility();
|
updateDeviceVisibility();
|
||||||
|
|
||||||
w->updating = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateClient(const pa_client_info &info) {
|
void MainWindow::updateClient(const pa_client_info &info) {
|
||||||
|
@ -1269,6 +1337,73 @@ void MainWindow::updateServer(const pa_server_info &info) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::createEventRoleWidget() {
|
||||||
|
if (eventRoleWidget)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pa_channel_map cm = {
|
||||||
|
1, { PA_CHANNEL_POSITION_MONO }
|
||||||
|
};
|
||||||
|
|
||||||
|
eventRoleWidget = RoleWidget::create();
|
||||||
|
streamsVBox->pack_start(*eventRoleWidget, false, false, 0);
|
||||||
|
eventRoleWidget->role = "sink-input-by-media-role:event";
|
||||||
|
eventRoleWidget->setChannelMap(cm, true);
|
||||||
|
|
||||||
|
eventRoleWidget->boldNameLabel->set_text("");
|
||||||
|
eventRoleWidget->nameLabel->set_label("System Sounds");
|
||||||
|
|
||||||
|
eventRoleWidget->iconImage->set_from_icon_name("multimedia-volume-control", Gtk::ICON_SIZE_SMALL_TOOLBAR);
|
||||||
|
|
||||||
|
eventRoleWidget->device = "";
|
||||||
|
|
||||||
|
eventRoleWidget->updating = true;
|
||||||
|
|
||||||
|
pa_cvolume volume;
|
||||||
|
volume.channels = 1;
|
||||||
|
volume.values[0] = PA_VOLUME_NORM;
|
||||||
|
|
||||||
|
eventRoleWidget->setVolume(volume);
|
||||||
|
eventRoleWidget->muteToggleButton->set_active(false);
|
||||||
|
|
||||||
|
eventRoleWidget->updating = false;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteEventRoleWidget() {
|
||||||
|
|
||||||
|
if (eventRoleWidget)
|
||||||
|
delete eventRoleWidget;
|
||||||
|
|
||||||
|
eventRoleWidget = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateRole(const pa_ext_stream_restore_info &info) {
|
||||||
|
pa_cvolume volume;
|
||||||
|
bool is_new = false;
|
||||||
|
|
||||||
|
if (strcmp(info.name, "sink-input-by-media-role:event") != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
is_new = createEventRoleWidget();
|
||||||
|
|
||||||
|
eventRoleWidget->updating = true;
|
||||||
|
|
||||||
|
eventRoleWidget->device = info.device;
|
||||||
|
|
||||||
|
volume.channels = 1;
|
||||||
|
volume.values[0] = pa_cvolume_avg(&info.volume);
|
||||||
|
|
||||||
|
eventRoleWidget->setVolume(volume);
|
||||||
|
eventRoleWidget->muteToggleButton->set_active(info.mute);
|
||||||
|
|
||||||
|
eventRoleWidget->updating = false;
|
||||||
|
|
||||||
|
if (is_new)
|
||||||
|
updateDeviceVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateVolumeMeter(uint32_t source_index, uint32_t sink_input_idx, double v) {
|
void MainWindow::updateVolumeMeter(uint32_t source_index, uint32_t sink_input_idx, double v) {
|
||||||
|
|
||||||
if (sink_input_idx != PA_INVALID_INDEX) {
|
if (sink_input_idx != PA_INVALID_INDEX) {
|
||||||
|
@ -1304,25 +1439,42 @@ void MainWindow::updateVolumeMeter(uint32_t source_index, uint32_t sink_input_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateDeviceVisibility() {
|
static guint idle_source = 0;
|
||||||
streamsVBox->hide_all();
|
|
||||||
recsVBox->hide_all();
|
|
||||||
sourcesVBox->hide_all();
|
|
||||||
sinksVBox->hide_all();
|
|
||||||
|
|
||||||
|
gboolean idle_cb(gpointer data) {
|
||||||
|
((MainWindow*) data)->reallyUpdateDeviceVisibility();
|
||||||
|
idle_source = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateDeviceVisibility() {
|
||||||
|
|
||||||
|
if (idle_source)
|
||||||
|
return;
|
||||||
|
|
||||||
|
idle_source = g_idle_add(idle_cb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::reallyUpdateDeviceVisibility() {
|
||||||
bool is_empty = true;
|
bool is_empty = true;
|
||||||
|
|
||||||
for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) {
|
for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) {
|
||||||
SinkInputWidget* w = i->second;
|
SinkInputWidget* w = i->second;
|
||||||
|
|
||||||
if (showSinkInputType == SINK_INPUT_ALL || w->type == showSinkInputType) {
|
if (showSinkInputType == SINK_INPUT_ALL || w->type == showSinkInputType) {
|
||||||
w->show_all();
|
w->show();
|
||||||
is_empty = false;
|
is_empty = false;
|
||||||
|
} else
|
||||||
|
w->hide();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (eventRoleWidget)
|
||||||
|
is_empty = false;
|
||||||
|
|
||||||
if (is_empty)
|
if (is_empty)
|
||||||
noStreamsLabel->show();
|
noStreamsLabel->show();
|
||||||
|
else
|
||||||
|
noStreamsLabel->hide();
|
||||||
|
|
||||||
is_empty = true;
|
is_empty = true;
|
||||||
|
|
||||||
|
@ -1330,13 +1482,16 @@ void MainWindow::updateDeviceVisibility() {
|
||||||
SourceOutputWidget* w = i->second;
|
SourceOutputWidget* w = i->second;
|
||||||
|
|
||||||
if (showSourceOutputType == SOURCE_OUTPUT_ALL || w->type == showSourceOutputType) {
|
if (showSourceOutputType == SOURCE_OUTPUT_ALL || w->type == showSourceOutputType) {
|
||||||
w->show_all();
|
w->show();
|
||||||
is_empty = false;
|
is_empty = false;
|
||||||
}
|
} else
|
||||||
|
w->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_empty)
|
if (is_empty)
|
||||||
noRecsLabel->show();
|
noRecsLabel->show();
|
||||||
|
else
|
||||||
|
noRecsLabel->hide();
|
||||||
|
|
||||||
is_empty = true;
|
is_empty = true;
|
||||||
|
|
||||||
|
@ -1344,13 +1499,16 @@ void MainWindow::updateDeviceVisibility() {
|
||||||
SinkWidget* w = i->second;
|
SinkWidget* w = i->second;
|
||||||
|
|
||||||
if (showSinkType == SINK_ALL || w->type == showSinkType) {
|
if (showSinkType == SINK_ALL || w->type == showSinkType) {
|
||||||
w->show_all();
|
w->show();
|
||||||
is_empty = false;
|
is_empty = false;
|
||||||
}
|
} else
|
||||||
|
w->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_empty)
|
if (is_empty)
|
||||||
noSinksLabel->show();
|
noSinksLabel->show();
|
||||||
|
else
|
||||||
|
noSinksLabel->hide();
|
||||||
|
|
||||||
is_empty = true;
|
is_empty = true;
|
||||||
|
|
||||||
|
@ -1360,18 +1518,27 @@ void MainWindow::updateDeviceVisibility() {
|
||||||
if (showSourceType == SOURCE_ALL ||
|
if (showSourceType == SOURCE_ALL ||
|
||||||
w->type == showSourceType ||
|
w->type == showSourceType ||
|
||||||
(showSourceType == SOURCE_NO_MONITOR && w->type != SOURCE_MONITOR)) {
|
(showSourceType == SOURCE_NO_MONITOR && w->type != SOURCE_MONITOR)) {
|
||||||
w->show_all();
|
w->show();
|
||||||
is_empty = false;
|
is_empty = false;
|
||||||
}
|
} else
|
||||||
|
w->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_empty)
|
if (is_empty)
|
||||||
noSourcesLabel->show();
|
noSourcesLabel->show();
|
||||||
|
else
|
||||||
|
noSourcesLabel->hide();
|
||||||
|
|
||||||
sourcesVBox->show();
|
/* Hmm, if I don't call hide()/show() here some widgets will never
|
||||||
recsVBox->show();
|
* get their proper space allocated */
|
||||||
|
sinksVBox->hide();
|
||||||
sinksVBox->show();
|
sinksVBox->show();
|
||||||
|
sourcesVBox->hide();
|
||||||
|
sourcesVBox->show();
|
||||||
|
streamsVBox->hide();
|
||||||
streamsVBox->show();
|
streamsVBox->show();
|
||||||
|
recsVBox->hide();
|
||||||
|
recsVBox->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::removeSink(uint32_t index) {
|
void MainWindow::removeSink(uint32_t index) {
|
||||||
|
@ -1462,13 +1629,13 @@ static void dec_outstanding(MainWindow *w) {
|
||||||
void sink_cb(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
|
void sink_cb(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
|
||||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
|
||||||
if (eol) {
|
if (eol < 0) {
|
||||||
dec_outstanding(w);
|
show_error("Sink callback failure");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!i) {
|
if (eol > 0) {
|
||||||
show_error("Sink callback failure");
|
dec_outstanding(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1478,13 +1645,13 @@ void sink_cb(pa_context *, const pa_sink_info *i, int eol, void *userdata) {
|
||||||
void source_cb(pa_context *, const pa_source_info *i, int eol, void *userdata) {
|
void source_cb(pa_context *, const pa_source_info *i, int eol, void *userdata) {
|
||||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
|
||||||
if (eol) {
|
if (eol < 0) {
|
||||||
dec_outstanding(w);
|
show_error("Source callback failure");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!i) {
|
if (eol > 0) {
|
||||||
show_error("Source callback failure");
|
dec_outstanding(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1494,13 +1661,13 @@ void source_cb(pa_context *, const pa_source_info *i, int eol, void *userdata) {
|
||||||
void sink_input_cb(pa_context *, const pa_sink_input_info *i, int eol, void *userdata) {
|
void sink_input_cb(pa_context *, const pa_sink_input_info *i, int eol, void *userdata) {
|
||||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
|
||||||
if (eol) {
|
if (eol < 0) {
|
||||||
dec_outstanding(w);
|
show_error("Sink input callback failure");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!i) {
|
if (eol > 0) {
|
||||||
show_error("Sink input callback failure");
|
dec_outstanding(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1510,7 +1677,12 @@ void sink_input_cb(pa_context *, const pa_sink_input_info *i, int eol, void *use
|
||||||
void source_output_cb(pa_context *, const pa_source_output_info *i, int eol, void *userdata) {
|
void source_output_cb(pa_context *, const pa_source_output_info *i, int eol, void *userdata) {
|
||||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
|
||||||
if (eol) {
|
if (eol < 0) {
|
||||||
|
show_error("Source output callback failure");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eol > 0) {
|
||||||
|
|
||||||
if (n_outstanding > 0) {
|
if (n_outstanding > 0) {
|
||||||
/* At this point all notebook pages have been populated, so
|
/* At this point all notebook pages have been populated, so
|
||||||
|
@ -1530,24 +1702,19 @@ void source_output_cb(pa_context *, const pa_source_output_info *i, int eol, voi
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!i) {
|
|
||||||
show_error("Source output callback failure");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
w->updateSourceOutput(*i);
|
w->updateSourceOutput(*i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_cb(pa_context *, const pa_client_info *i, int eol, void *userdata) {
|
void client_cb(pa_context *, const pa_client_info *i, int eol, void *userdata) {
|
||||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
|
||||||
if (eol) {
|
if (eol < 0) {
|
||||||
dec_outstanding(w);
|
show_error("Client callback failure");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!i) {
|
if (eol > 0) {
|
||||||
show_error("Client callback failure");
|
dec_outstanding(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1566,6 +1733,42 @@ void server_info_cb(pa_context *, const pa_server_info *i, void *userdata) {
|
||||||
dec_outstanding(w);
|
dec_outstanding(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ext_stream_restore_read_cb(
|
||||||
|
pa_context *c,
|
||||||
|
const pa_ext_stream_restore_info *i,
|
||||||
|
int eol,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
|
||||||
|
if (eol < 0) {
|
||||||
|
g_debug("Failed to initialized stream_restore extension: %s", pa_strerror(pa_context_errno(context)));
|
||||||
|
w->deleteEventRoleWidget();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
w->createEventRoleWidget();
|
||||||
|
|
||||||
|
if (eol > 0) {
|
||||||
|
dec_outstanding(w);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
w->updateRole(*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ext_stream_restore_subscribe_cb(pa_context *c, void *userdata) {
|
||||||
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
pa_operation *o;
|
||||||
|
|
||||||
|
if (!(o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, w))) {
|
||||||
|
show_error("pa_ext_stream_restore_read() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_operation_unref(o);
|
||||||
|
}
|
||||||
|
|
||||||
void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) {
|
void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata) {
|
||||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||||
|
|
||||||
|
@ -1713,6 +1916,19 @@ void context_state_callback(pa_context *c, void *userdata) {
|
||||||
|
|
||||||
n_outstanding = 6;
|
n_outstanding = 6;
|
||||||
|
|
||||||
|
/* This call is not always supported */
|
||||||
|
if ((o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, w))) {
|
||||||
|
pa_operation_unref(o);
|
||||||
|
n_outstanding++;
|
||||||
|
|
||||||
|
pa_ext_stream_restore_set_subscribe_cb(c, ext_stream_restore_subscribe_cb, w);
|
||||||
|
|
||||||
|
if ((o = pa_ext_stream_restore_subscribe(c, 1, NULL, NULL)))
|
||||||
|
pa_operation_unref(o);
|
||||||
|
|
||||||
|
} else
|
||||||
|
g_debug("Failed to initialized stream_restore extension: %s", pa_strerror(pa_context_errno(context)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue