pulse-server: handle special device names in play/record

@DEFAULT_MONITOR@ finds the default sink but returns is_monitor true.

Always lookup the device based on the name and index. This transform
the special device names like @DEFAULT_XXX@ to the default device.

Always use the found device name as the target. Make sure to set the
CAPTURE_SINK property when dealing with a monitor.

Fixes #3284
This commit is contained in:
Wim Taymans 2023-06-11 18:33:13 +02:00
parent b52be160ab
commit 8eb6c0ec33

View file

@ -1586,6 +1586,8 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
const struct spa_pod *params[MAX_FORMATS]; const struct spa_pod *params[MAX_FORMATS];
uint8_t buffer[4096]; uint8_t buffer[4096];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
struct pw_manager_object *o;
bool is_monitor;
props = pw_properties_copy(client->props); props = pw_properties_copy(client->props);
if (props == NULL) if (props == NULL)
@ -1632,15 +1634,11 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
TAG_INVALID) < 0) TAG_INVALID) < 0)
goto error_protocol; goto error_protocol;
} }
o = find_device(client, sink_index, sink_name, true, &is_monitor);
spa_zero(fix_ss); spa_zero(fix_ss);
spa_zero(fix_map); spa_zero(fix_map);
if (fix_format || fix_rate || fix_channels) { if ((fix_format || fix_rate || fix_channels) && o != NULL) {
struct pw_manager_object *o;
bool is_monitor;
o = find_device(client, sink_index, sink_name, true, &is_monitor);
if (o != NULL) {
struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT); struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT);
collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs); collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs);
fix_ss.format = fix_format ? dev_info.ss.format : 0; fix_ss.format = fix_format ? dev_info.ss.format : 0;
@ -1648,7 +1646,6 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
fix_ss.channels = fix_channels ? dev_info.ss.channels : 0; fix_ss.channels = fix_channels ? dev_info.ss.channels : 0;
fix_map = dev_info.map; fix_map = dev_info.map;
} }
}
if (client->version >= 13) { if (client->version >= 13) {
if (message_get(m, if (message_get(m,
@ -1772,6 +1769,9 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
flags |= PW_STREAM_FLAG_DONT_RECONNECT; flags |= PW_STREAM_FLAG_DONT_RECONNECT;
if (sink_name != NULL) { if (sink_name != NULL) {
if (o != NULL)
sink_name = pw_properties_get(o->props,
PW_KEY_NODE_NAME);
pw_properties_set(props, pw_properties_set(props,
PW_KEY_TARGET_OBJECT, sink_name); PW_KEY_TARGET_OBJECT, sink_name);
} else if (sink_index != SPA_ID_INVALID && sink_index != 0) { } else if (sink_index != SPA_ID_INVALID && sink_index != 0) {
@ -1858,6 +1858,8 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
const struct spa_pod *params[MAX_FORMATS]; const struct spa_pod *params[MAX_FORMATS];
uint8_t buffer[4096]; uint8_t buffer[4096];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
struct pw_manager_object *o;
bool is_monitor = false;
props = pw_properties_copy(client->props); props = pw_properties_copy(client->props);
if (props == NULL) if (props == NULL)
@ -1922,15 +1924,11 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
TAG_INVALID) < 0) TAG_INVALID) < 0)
goto error_protocol; goto error_protocol;
} }
o = find_device(client, source_index, source_name, false, &is_monitor);
spa_zero(fix_ss); spa_zero(fix_ss);
spa_zero(fix_map); spa_zero(fix_map);
if (fix_format || fix_rate || fix_channels) { if ((fix_format || fix_rate || fix_channels) && o != NULL) {
struct pw_manager_object *o;
bool is_monitor;
o = find_device(client, source_index, source_name, false, &is_monitor);
if (o != NULL) {
struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT); struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT);
collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs); collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs);
fix_ss.format = fix_format ? dev_info.ss.format : 0; fix_ss.format = fix_format ? dev_info.ss.format : 0;
@ -1938,7 +1936,6 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
fix_ss.channels = fix_channels ? dev_info.ss.channels : 0; fix_ss.channels = fix_channels ? dev_info.ss.channels : 0;
fix_map = dev_info.map; fix_map = dev_info.map;
} }
}
if (client->version >= 22) { if (client->version >= 22) {
if (message_get(m, if (message_get(m,
@ -2048,16 +2045,21 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
pw_properties_setf(props, pw_properties_setf(props,
PW_KEY_TARGET_OBJECT, "%u", source_index); PW_KEY_TARGET_OBJECT, "%u", source_index);
} else if (source_name != NULL) { } else if (source_name != NULL) {
if (o != NULL)
source_name = pw_properties_get(o->props,
PW_KEY_NODE_NAME);
if (spa_strendswith(source_name, ".monitor")) { if (spa_strendswith(source_name, ".monitor")) {
is_monitor = true;
pw_properties_setf(props, pw_properties_setf(props,
PW_KEY_TARGET_OBJECT, PW_KEY_TARGET_OBJECT,
"%.*s", (int)strlen(source_name)-8, source_name); "%.*s", (int)strlen(source_name)-8, source_name);
pw_properties_set(props,
PW_KEY_STREAM_CAPTURE_SINK, "true");
} else { } else {
pw_properties_set(props, pw_properties_set(props,
PW_KEY_TARGET_OBJECT, source_name); PW_KEY_TARGET_OBJECT, source_name);
} }
if (is_monitor)
pw_properties_set(props,
PW_KEY_STREAM_CAPTURE_SINK, "true");
} }
stream->stream = pw_stream_new(client->core, name, props); stream->stream = pw_stream_new(client->core, name, props);
@ -2453,6 +2455,7 @@ static struct pw_manager_object *find_device(struct client *client,
return NULL; return NULL;
sink = true; sink = true;
find_default = true; find_default = true;
monitor = true;
} else if (spa_streq(name, DEFAULT_SOURCE)) { } else if (spa_streq(name, DEFAULT_SOURCE)) {
if (sink) if (sink)
return NULL; return NULL;