mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
pulse-server: track and set monitor volume on monitor sources
This commit is contained in:
parent
664df03bbb
commit
620c863b6d
3 changed files with 71 additions and 39 deletions
|
|
@ -253,11 +253,11 @@ struct device_info {
|
|||
}
|
||||
|
||||
static void collect_device_info(struct pw_manager_object *device,
|
||||
struct pw_manager_object *card, struct device_info *dev_info)
|
||||
struct pw_manager_object *card, struct device_info *dev_info, bool monitor)
|
||||
{
|
||||
struct pw_manager_param *p;
|
||||
|
||||
if (card) {
|
||||
if (card && !monitor) {
|
||||
spa_list_for_each(p, &card->param_list, link) {
|
||||
uint32_t id, device;
|
||||
struct spa_pod *props;
|
||||
|
|
@ -275,7 +275,7 @@ static void collect_device_info(struct pw_manager_object *device,
|
|||
continue;
|
||||
dev_info->active_port = id;
|
||||
if (props) {
|
||||
volume_parse_param(props, &dev_info->volume_info);
|
||||
volume_parse_param(props, &dev_info->volume_info, monitor);
|
||||
dev_info->have_volume = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -297,7 +297,7 @@ static void collect_device_info(struct pw_manager_object *device,
|
|||
|
||||
case SPA_PARAM_Props:
|
||||
if (!dev_info->have_volume) {
|
||||
volume_parse_param(p->param, &dev_info->volume_info);
|
||||
volume_parse_param(p->param, &dev_info->volume_info, monitor);
|
||||
dev_info->have_volume = true;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -641,7 +641,7 @@ static int send_object_event(struct client *client, struct pw_manager_object *o,
|
|||
}
|
||||
|
||||
static struct pw_manager_object *find_device(struct client *client,
|
||||
uint32_t id, const char *name, bool sink);
|
||||
uint32_t id, const char *name, bool sink, bool *is_monitor);
|
||||
|
||||
static int64_t get_node_latency_offset(struct pw_manager_object *o)
|
||||
{
|
||||
|
|
@ -704,7 +704,7 @@ static void send_default_change_subscribe_event(struct client *client, bool sink
|
|||
bool changed = false;
|
||||
|
||||
if (sink) {
|
||||
def = find_device(client, SPA_ID_INVALID, NULL, true);
|
||||
def = find_device(client, SPA_ID_INVALID, NULL, true, NULL);
|
||||
if (client->prev_default_sink != def) {
|
||||
client->prev_default_sink = def;
|
||||
changed = true;
|
||||
|
|
@ -712,7 +712,7 @@ static void send_default_change_subscribe_event(struct client *client, bool sink
|
|||
}
|
||||
|
||||
if (source) {
|
||||
def = find_device(client, SPA_ID_INVALID, NULL, false);
|
||||
def = find_device(client, SPA_ID_INVALID, NULL, false, NULL);
|
||||
if (client->prev_default_source != def) {
|
||||
client->prev_default_source = def;
|
||||
changed = true;
|
||||
|
|
@ -2588,10 +2588,11 @@ static const char *get_default(struct client *client, bool sink)
|
|||
}
|
||||
|
||||
static struct pw_manager_object *find_device(struct client *client,
|
||||
uint32_t id, const char *name, bool sink)
|
||||
uint32_t id, const char *name, bool sink, bool *is_monitor)
|
||||
{
|
||||
struct selector sel;
|
||||
const char *def;
|
||||
bool monitor = false;
|
||||
|
||||
if (id == 0)
|
||||
id = SPA_ID_INVALID;
|
||||
|
|
@ -2599,18 +2600,22 @@ static struct pw_manager_object *find_device(struct client *client,
|
|||
if (name != NULL && !sink) {
|
||||
if (pw_endswith(name, ".monitor")) {
|
||||
name = strndupa(name, strlen(name)-8);
|
||||
sink = true;
|
||||
monitor = true;
|
||||
} else if (strcmp(name, DEFAULT_MONITOR) == 0) {
|
||||
name = NULL;
|
||||
sink = true;
|
||||
monitor = true;
|
||||
}
|
||||
}
|
||||
if (id != SPA_ID_INVALID && !sink) {
|
||||
if (id & MONITOR_FLAG) {
|
||||
sink = true;
|
||||
monitor = true;
|
||||
id &= ~MONITOR_FLAG;
|
||||
}
|
||||
}
|
||||
if (monitor)
|
||||
sink = true;
|
||||
if (is_monitor)
|
||||
*is_monitor = monitor;
|
||||
|
||||
spa_zero(sel);
|
||||
sel.id = id;
|
||||
|
|
@ -2741,7 +2746,7 @@ static int do_play_sample(struct client *client, uint32_t command, uint32_t tag,
|
|||
if (sink_index != SPA_ID_INVALID && sink_name != NULL)
|
||||
goto error_inval;
|
||||
|
||||
o = find_device(client, sink_index, sink_name, PW_DIRECTION_OUTPUT);
|
||||
o = find_device(client, sink_index, sink_name, PW_DIRECTION_OUTPUT, NULL);
|
||||
if (o == NULL)
|
||||
goto error_noent;
|
||||
|
||||
|
|
@ -2907,29 +2912,38 @@ static int do_flush_trigger_prebuf_stream(struct client *client, uint32_t comman
|
|||
}
|
||||
|
||||
static int set_node_volume_mute(struct pw_manager_object *o,
|
||||
struct volume *vol, bool *mute)
|
||||
struct volume *vol, bool *mute, bool is_monitor)
|
||||
{
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
struct spa_pod_frame f[1];
|
||||
struct spa_pod *param;
|
||||
uint32_t volprop, muteprop;
|
||||
|
||||
if (!SPA_FLAG_IS_SET(o->permissions, PW_PERM_W | PW_PERM_X))
|
||||
return -EACCES;
|
||||
if (o->proxy == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (is_monitor) {
|
||||
volprop = SPA_PROP_monitorVolumes;
|
||||
muteprop = SPA_PROP_monitorMute;
|
||||
} else {
|
||||
volprop = SPA_PROP_channelVolumes;
|
||||
muteprop = SPA_PROP_mute;
|
||||
}
|
||||
|
||||
spa_pod_builder_push_object(&b, &f[0],
|
||||
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
|
||||
if (vol)
|
||||
spa_pod_builder_add(&b,
|
||||
SPA_PROP_channelVolumes, SPA_POD_Array(sizeof(float),
|
||||
volprop, SPA_POD_Array(sizeof(float),
|
||||
SPA_TYPE_Float,
|
||||
vol->channels,
|
||||
vol->values), 0);
|
||||
if (mute)
|
||||
spa_pod_builder_add(&b,
|
||||
SPA_PROP_mute, SPA_POD_Bool(*mute), 0);
|
||||
muteprop, SPA_POD_Bool(*mute), 0);
|
||||
param = spa_pod_builder_pop(&b, &f[0]);
|
||||
|
||||
pw_node_set_param((struct pw_node*)o->proxy,
|
||||
|
|
@ -3047,7 +3061,7 @@ static int do_set_stream_volume(struct client *client, uint32_t command, uint32_
|
|||
if (o == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if ((res = set_node_volume_mute(o, &volume, NULL)) < 0)
|
||||
if ((res = set_node_volume_mute(o, &volume, NULL, false)) < 0)
|
||||
return res;
|
||||
}
|
||||
done:
|
||||
|
|
@ -3098,7 +3112,7 @@ static int do_set_stream_mute(struct client *client, uint32_t command, uint32_t
|
|||
if (o == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if ((res = set_node_volume_mute(o, NULL, &mute)) < 0)
|
||||
if ((res = set_node_volume_mute(o, NULL, &mute, false)) < 0)
|
||||
return res;
|
||||
}
|
||||
done:
|
||||
|
|
@ -3117,6 +3131,7 @@ static int do_set_volume(struct client *client, uint32_t command, uint32_t tag,
|
|||
int res;
|
||||
struct device_info dev_info;
|
||||
enum pw_direction direction;
|
||||
bool is_monitor;
|
||||
|
||||
if ((res = message_get(m,
|
||||
TAG_U32, &id,
|
||||
|
|
@ -3137,7 +3152,7 @@ static int do_set_volume(struct client *client, uint32_t command, uint32_t tag,
|
|||
else
|
||||
direction = PW_DIRECTION_INPUT;
|
||||
|
||||
o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT);
|
||||
o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, &is_monitor);
|
||||
if (o == NULL || (info = o->info) == NULL || info->props == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
|
@ -3151,17 +3166,17 @@ static int do_set_volume(struct client *client, uint32_t command, uint32_t tag,
|
|||
struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
|
||||
card = select_object(manager, &sel);
|
||||
}
|
||||
collect_device_info(o, card, &dev_info);
|
||||
collect_device_info(o, card, &dev_info, is_monitor);
|
||||
|
||||
if (dev_info.have_volume &&
|
||||
volume_compare(&dev_info.volume_info.volume, &volume) == 0)
|
||||
goto done;
|
||||
|
||||
if (card != NULL && dev_info.active_port != SPA_ID_INVALID)
|
||||
if (card != NULL && !is_monitor && dev_info.active_port != SPA_ID_INVALID)
|
||||
res = set_card_volume_mute_delay(card, dev_info.active_port,
|
||||
dev_info.device, &volume, NULL, NULL);
|
||||
else
|
||||
res = set_node_volume_mute(o, &volume, NULL);
|
||||
res = set_node_volume_mute(o, &volume, NULL, is_monitor);
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
|
@ -3182,6 +3197,7 @@ static int do_set_mute(struct client *client, uint32_t command, uint32_t tag, st
|
|||
int res;
|
||||
struct device_info dev_info;
|
||||
enum pw_direction direction;
|
||||
bool is_monitor;
|
||||
|
||||
if ((res = message_get(m,
|
||||
TAG_U32, &id,
|
||||
|
|
@ -3202,7 +3218,7 @@ static int do_set_mute(struct client *client, uint32_t command, uint32_t tag, st
|
|||
else
|
||||
direction = PW_DIRECTION_INPUT;
|
||||
|
||||
o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT);
|
||||
o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, &is_monitor);
|
||||
if (o == NULL || (info = o->info) == NULL || info->props == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
|
@ -3216,17 +3232,17 @@ static int do_set_mute(struct client *client, uint32_t command, uint32_t tag, st
|
|||
struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
|
||||
card = select_object(manager, &sel);
|
||||
}
|
||||
collect_device_info(o, card, &dev_info);
|
||||
collect_device_info(o, card, &dev_info, is_monitor);
|
||||
|
||||
if (dev_info.have_volume &&
|
||||
dev_info.volume_info.mute == mute)
|
||||
goto done;
|
||||
|
||||
if (card != NULL && dev_info.active_port != SPA_ID_INVALID)
|
||||
if (card != NULL && !is_monitor && dev_info.active_port != SPA_ID_INVALID)
|
||||
res = set_card_volume_mute_delay(card, dev_info.active_port,
|
||||
dev_info.device, NULL, &mute, NULL);
|
||||
else
|
||||
res = set_node_volume_mute(o, NULL, &mute);
|
||||
res = set_node_volume_mute(o, NULL, &mute, is_monitor);
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
|
@ -3265,7 +3281,7 @@ static int do_set_port(struct client *client, uint32_t command, uint32_t tag, st
|
|||
else
|
||||
direction = PW_DIRECTION_INPUT;
|
||||
|
||||
o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT);
|
||||
o = find_device(client, id, name, direction == PW_DIRECTION_OUTPUT, NULL);
|
||||
if (o == NULL || (info = o->info) == NULL || info->props == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
|
@ -3595,11 +3611,9 @@ static int do_lookup(struct client *client, uint32_t command, uint32_t tag, stru
|
|||
|
||||
pw_log_info(NAME" %p: [%s] LOOKUP tag:%u name:'%s'", impl, client->name, tag, name);
|
||||
|
||||
if ((o = find_device(client, SPA_ID_INVALID, name, is_sink)) == NULL)
|
||||
if ((o = find_device(client, SPA_ID_INVALID, name, is_sink, &is_monitor)) == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
is_monitor = !is_sink && pw_manager_object_is_monitor(o);
|
||||
|
||||
reply = reply_new(client, tag);
|
||||
message_put(reply,
|
||||
TAG_U32, is_monitor ? o->id | MONITOR_FLAG : o->id,
|
||||
|
|
@ -3931,7 +3945,7 @@ static int fill_sink_info(struct client *client, struct message *m,
|
|||
if (card)
|
||||
collect_card_info(card, &card_info);
|
||||
|
||||
collect_device_info(o, card, &dev_info);
|
||||
collect_device_info(o, card, &dev_info, false);
|
||||
|
||||
if (!sample_spec_valid(&dev_info.ss) ||
|
||||
!channel_map_valid(&dev_info.map) ||
|
||||
|
|
@ -4075,7 +4089,7 @@ static int fill_source_info(struct client *client, struct message *m,
|
|||
if (card)
|
||||
collect_card_info(card, &card_info);
|
||||
|
||||
collect_device_info(o, card, &dev_info);
|
||||
collect_device_info(o, card, &dev_info, is_monitor);
|
||||
|
||||
if (!sample_spec_valid(&dev_info.ss) ||
|
||||
!channel_map_valid(&dev_info.map) ||
|
||||
|
|
@ -4198,7 +4212,7 @@ static int fill_sink_input_info(struct client *client, struct message *m,
|
|||
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
|
||||
client_id = (uint32_t)atoi(str);
|
||||
|
||||
collect_device_info(o, NULL, &dev_info);
|
||||
collect_device_info(o, NULL, &dev_info, false);
|
||||
|
||||
if (!sample_spec_valid(&dev_info.ss) ||
|
||||
!channel_map_valid(&dev_info.map) ||
|
||||
|
|
@ -4269,7 +4283,7 @@ static int fill_source_output_info(struct client *client, struct message *m,
|
|||
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
|
||||
client_id = (uint32_t)atoi(str);
|
||||
|
||||
collect_device_info(o, NULL, &dev_info);
|
||||
collect_device_info(o, NULL, &dev_info, false);
|
||||
|
||||
if (!sample_spec_valid(&dev_info.ss) ||
|
||||
!channel_map_valid(&dev_info.map) ||
|
||||
|
|
@ -4819,7 +4833,7 @@ static int do_set_default(struct client *client, uint32_t command, uint32_t tag,
|
|||
pw_log_info(NAME" %p: [%s] %s tag:%u name:%s", impl, client->name,
|
||||
commands[command].name, tag, name);
|
||||
|
||||
if (name != NULL && (o = find_device(client, SPA_ID_INVALID, name, sink)) == NULL)
|
||||
if (name != NULL && (o = find_device(client, SPA_ID_INVALID, name, sink, NULL)) == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (name != NULL) {
|
||||
|
|
@ -4863,7 +4877,7 @@ static int do_suspend(struct client *client, uint32_t command, uint32_t tag, str
|
|||
pw_log_info(NAME" %p: [%s] %s tag:%u id:%u name:%s", impl, client->name,
|
||||
commands[command].name, tag, id, name);
|
||||
|
||||
if ((o = find_device(client, id, name, sink)) == NULL)
|
||||
if ((o = find_device(client, id, name, sink, NULL)) == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (o->proxy == NULL)
|
||||
|
|
@ -4909,7 +4923,7 @@ static int do_move_stream(struct client *client, uint32_t command, uint32_t tag,
|
|||
if (o == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if ((dev = find_device(client, id_device, name_device, sink)) == NULL)
|
||||
if ((dev = find_device(client, id_device, name_device, sink, NULL)) == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if ((res = pw_manager_set_metadata(manager, client->metadata_default,
|
||||
|
|
@ -4918,7 +4932,7 @@ static int do_move_stream(struct client *client, uint32_t command, uint32_t tag,
|
|||
SPA_TYPE_INFO_BASE"Id", "%d", dev->id)) < 0)
|
||||
return res;
|
||||
|
||||
dev_default = find_device(client, SPA_ID_INVALID, NULL, sink);
|
||||
dev_default = find_device(client, SPA_ID_INVALID, NULL, sink, NULL);
|
||||
if (dev == dev_default) {
|
||||
/*
|
||||
* When moving streams to a node that is equal to the default,
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ static inline int volume_compare(struct volume *vol, struct volume *other)
|
|||
}
|
||||
for (i = 0; i < vol->channels; i++) {
|
||||
if (vol->values[i] != other->values[i]) {
|
||||
pw_log_info("val %f<>%f", vol->values[i], other->values[i]);
|
||||
pw_log_info("%d: val %f<>%f", i, vol->values[i], other->values[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ struct volume_info {
|
|||
}
|
||||
|
||||
|
||||
static int volume_parse_param(const struct spa_pod *param, struct volume_info *info)
|
||||
static int volume_parse_param(const struct spa_pod *param, struct volume_info *info, bool monitor)
|
||||
{
|
||||
struct spa_pod_object *obj = (struct spa_pod_object *) param;
|
||||
struct spa_pod_prop *prop;
|
||||
|
|
@ -89,17 +89,35 @@ static int volume_parse_param(const struct spa_pod *param, struct volume_info *i
|
|||
|
||||
break;
|
||||
case SPA_PROP_mute:
|
||||
if (monitor)
|
||||
continue;
|
||||
if (spa_pod_get_bool(&prop->value, &info->mute) < 0)
|
||||
continue;
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_HW_MUTE,
|
||||
prop->flags & SPA_POD_PROP_FLAG_HARDWARE);
|
||||
break;
|
||||
case SPA_PROP_channelVolumes:
|
||||
if (monitor)
|
||||
continue;
|
||||
info->volume.channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
info->volume.values, SPA_AUDIO_MAX_CHANNELS);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_HW_VOLUME,
|
||||
prop->flags & SPA_POD_PROP_FLAG_HARDWARE);
|
||||
break;
|
||||
case SPA_PROP_monitorMute:
|
||||
if (!monitor)
|
||||
continue;
|
||||
if (spa_pod_get_bool(&prop->value, &info->mute) < 0)
|
||||
continue;
|
||||
SPA_FLAG_CLEAR(info->flags, VOLUME_HW_MUTE);
|
||||
break;
|
||||
case SPA_PROP_monitorVolumes:
|
||||
if (!monitor)
|
||||
continue;
|
||||
info->volume.channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
info->volume.values, SPA_AUDIO_MAX_CHANNELS);
|
||||
SPA_FLAG_CLEAR(info->flags, VOLUME_HW_VOLUME);
|
||||
break;
|
||||
case SPA_PROP_volumeBase:
|
||||
if (spa_pod_get_float(&prop->value, &info->base) < 0)
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue