If two ports have different default volumes, and module-device-restore doesn't have an opinion on the port volume, we should change the sink/source volume to the new port's default volume when switching ports, instead of keeping the volume at whatever it happened to be when the old port was active. This introduces pa_sink/source_port_changed_hook_data, because I wanted to call pa_sink/source_set_volume() only once in pa_sink/source_set_port(), instead of calling it also in module-device-restore's hook callback. The extended hook data allows module-device-restore to communicate to the core that the volume should be set to a non-default value. --- src/modules/dbus/iface-device.c | 4 ++-- src/modules/module-device-restore.c | 32 ++++++++++++++------------------ src/pulsecore/sink.c | 8 +++++++- src/pulsecore/sink.h | 10 ++++++++++ src/pulsecore/source.c | 8 +++++++- src/pulsecore/source.h | 10 ++++++++++ 6 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/modules/dbus/iface-device.c b/src/modules/dbus/iface-device.c index 2c370a8..911890d 100644 --- a/src/modules/dbus/iface-device.c +++ b/src/modules/dbus/iface-device.c @@ -1190,8 +1190,8 @@ static pa_hook_result_t port_changed_cb(void *hook_data, void *call_data, void * DBusMessage *signal_msg = NULL; pa_device_port *new_active_port = NULL; - if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) || - (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data)) + if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != ((pa_sink_port_changed_hook_data *) call_data)->sink) || + (d->type == PA_DEVICE_TYPE_SOURCE && d->source != ((pa_source_port_changed_hook_data *) call_data)->source)) return PA_HOOK_OK; new_active_port = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->active_port : d->source->active_port; diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index 8d7b34b..ced2a14 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -798,28 +798,26 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data * return PA_HOOK_OK; } -static pa_hook_result_t sink_port_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) { +static pa_hook_result_t sink_port_hook_callback(pa_core *c, pa_sink_port_changed_hook_data *data, struct userdata *u) { + pa_sink *sink; char *name; struct perportentry *e; pa_assert(c); - pa_assert(sink); + pa_assert(data); pa_assert(u); pa_assert(u->restore_volume || u->restore_muted); + sink = data->sink; name = pa_sprintf_malloc("sink:%s", sink->name); if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) { if (u->restore_volume && e->volume_valid) { - pa_cvolume v; - pa_log_info("Restoring volume for sink %s.", sink->name); - v = e->volume; - pa_cvolume_remap(&v, &e->channel_map, &sink->channel_map); - pa_sink_set_volume(sink, &v, true, false); - - sink->save_volume = true; + data->volume = e->volume; + pa_cvolume_remap(&data->volume, &e->channel_map, &sink->channel_map); + data->save_volume = true; } if (u->restore_muted && e->muted_valid) { @@ -940,28 +938,26 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da return PA_HOOK_OK; } -static pa_hook_result_t source_port_hook_callback(pa_core *c, pa_source *source, struct userdata *u) { +static pa_hook_result_t source_port_hook_callback(pa_core *c, pa_source_port_changed_hook_data *data, struct userdata *u) { + pa_source *source; char *name; struct perportentry *e; pa_assert(c); - pa_assert(source); + pa_assert(data); pa_assert(u); pa_assert(u->restore_volume || u->restore_muted); + source = data->source; name = pa_sprintf_malloc("source:%s", source->name); if ((e = perportentry_read(u, name, (source->active_port ? source->active_port->name : NULL)))) { if (u->restore_volume && e->volume_valid) { - pa_cvolume v; - pa_log_info("Restoring volume for source %s.", source->name); - v = e->volume; - pa_cvolume_remap(&v, &e->channel_map, &source->channel_map); - pa_source_set_volume(source, &v, true, false); - - source->save_volume = true; + data->volume = e->volume; + pa_cvolume_remap(&data->volume, &e->channel_map, &source->channel_map); + data->save_volume = true; } if (u->restore_muted && e->muted_valid) { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 3776a5a..652401d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -3310,6 +3310,7 @@ size_t pa_sink_get_max_request(pa_sink *s) { int pa_sink_set_port(pa_sink *s, const char *name, bool save) { pa_device_port *port; int ret; + pa_sink_port_changed_hook_data hook_data; pa_sink_assert_ref(s); pa_assert_ctl_context(); @@ -3350,7 +3351,12 @@ int pa_sink_set_port(pa_sink *s, const char *name, bool save) { pa_sink_set_latency_offset(s, s->active_port->latency_offset); - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s); + hook_data.sink = s; + pa_cvolume_set(&hook_data.volume, s->sample_spec.channels, port->default_volume); + hook_data.save_volume = false; + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], &hook_data); + + pa_sink_set_volume(s, &hook_data.volume, true, hook_data.save_volume); return 0; } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index cb32782..4150c5a3 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -337,6 +337,16 @@ typedef enum pa_sink_message { PA_SINK_MESSAGE_MAX } pa_sink_message_t; +typedef struct { + pa_sink *sink; + + /* This will be the new volume for the sink. If the hook callback wants to + * set the sink volume, it should do that by setting these variables + * instead of calling pa_sink_set_volume(). */ + pa_cvolume volume; + bool save_volume; +} pa_sink_port_changed_hook_data; + typedef struct pa_sink_new_data { pa_suspend_cause_t suspend_cause; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index b06e7fa..17dd9a1 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -2589,6 +2589,7 @@ size_t pa_source_get_max_rewind(pa_source *s) { int pa_source_set_port(pa_source *s, const char *name, bool save) { pa_device_port *port; int ret; + pa_source_port_changed_hook_data hook_data; pa_source_assert_ref(s); pa_assert_ctl_context(); @@ -2627,7 +2628,12 @@ int pa_source_set_port(pa_source *s, const char *name, bool save) { s->active_port = port; s->save_port = save; - pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], s); + hook_data.source = s; + pa_cvolume_set(&hook_data.volume, s->sample_spec.channels, port->default_volume); + hook_data.save_volume = false; + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], &hook_data); + + pa_source_set_volume(s, &hook_data.volume, true, hook_data.save_volume); return 0; } diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 7555a9f..b6e9d0e 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -274,6 +274,16 @@ typedef enum pa_source_message { PA_SOURCE_MESSAGE_MAX } pa_source_message_t; +typedef struct { + pa_source *source; + + /* This will be the new volume for the source. If the hook callback wants + * to set the source volume, it should do that by setting these variables + * instead of calling pa_source_set_volume(). */ + pa_cvolume volume; + bool save_volume; +} pa_source_port_changed_hook_data; + typedef struct pa_source_new_data { pa_suspend_cause_t suspend_cause; -- 1.9.3