mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
keys: add PW_KEY_STREAM_CAPTURE_SINK
Add a property for capture stream to signal that they would like to capture the output (monitor) of the default sink instead of the default source. Check the desired device we would like to capture from and handle the capture from the sink by monitoring the monitor source.
This commit is contained in:
parent
37b39135e9
commit
d55bc1eb86
3 changed files with 91 additions and 43 deletions
|
|
@ -98,6 +98,7 @@ struct node {
|
|||
unsigned int dont_remix:1;
|
||||
unsigned int monitor:1;
|
||||
unsigned int moving:1;
|
||||
unsigned int capture_sink:1;
|
||||
};
|
||||
|
||||
static bool find_format(struct node *node)
|
||||
|
|
@ -434,7 +435,8 @@ static int find_node(void *data, struct node *node)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (node->direction == find->target->direction) {
|
||||
if ((find->target->capture_sink && node->direction != PW_DIRECTION_INPUT) ||
|
||||
(!find->target->capture_sink && node->direction == find->target->direction)) {
|
||||
pw_log_debug(".. same direction");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -581,12 +583,16 @@ static int rescan_node(struct impl *impl, struct node *n)
|
|||
info = n->obj->info;
|
||||
props = info->props;
|
||||
|
||||
if ((str = spa_dict_lookup(props, PW_KEY_STREAM_DONT_REMIX)) != NULL)
|
||||
if ((str = spa_dict_lookup(props, PW_KEY_STREAM_DONT_REMIX)) != NULL)
|
||||
n->dont_remix = pw_properties_parse_bool(str);
|
||||
|
||||
if ((str = spa_dict_lookup(props, PW_KEY_STREAM_MONITOR)) != NULL)
|
||||
if ((str = spa_dict_lookup(props, PW_KEY_STREAM_MONITOR)) != NULL)
|
||||
n->monitor = pw_properties_parse_bool(str);
|
||||
|
||||
if (n->direction == PW_DIRECTION_INPUT &&
|
||||
(str = spa_dict_lookup(props, PW_KEY_STREAM_CAPTURE_SINK)) != NULL)
|
||||
n->capture_sink = pw_properties_parse_bool(str);
|
||||
|
||||
autoconnect = false;
|
||||
if ((str = spa_dict_lookup(props, PW_KEY_NODE_AUTOCONNECT)) != NULL)
|
||||
autoconnect = pw_properties_parse_bool(str);
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ struct stream {
|
|||
struct cvolume volume;
|
||||
bool muted;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
uint32_t drain_tag;
|
||||
unsigned int corked:1;
|
||||
unsigned int volume_set:1;
|
||||
|
|
@ -702,7 +704,6 @@ static void fix_playback_buffer_attr(struct stream *s, struct buffer_attr *attr)
|
|||
static int reply_create_playback_stream(struct stream *stream)
|
||||
{
|
||||
struct client *client = stream->client;
|
||||
struct impl *impl = client->impl;
|
||||
struct message *reply;
|
||||
uint32_t size;
|
||||
struct spa_dict_item items[1];
|
||||
|
|
@ -741,8 +742,8 @@ static int reply_create_playback_stream(struct stream *stream)
|
|||
message_put(reply,
|
||||
TAG_SAMPLE_SPEC, &stream->ss,
|
||||
TAG_CHANNEL_MAP, &stream->map,
|
||||
TAG_U32, impl->default_sink.index, /* sink index */
|
||||
TAG_STRING, impl->default_sink.name, /* sink name */
|
||||
TAG_U32, stream->dev->index, /* sink index */
|
||||
TAG_STRING, stream->dev->name, /* sink name */
|
||||
TAG_BOOLEAN, false, /* sink suspended state */
|
||||
TAG_INVALID);
|
||||
}
|
||||
|
|
@ -794,7 +795,6 @@ static void fix_record_buffer_attr(struct stream *s, struct buffer_attr *attr)
|
|||
static int reply_create_record_stream(struct stream *stream)
|
||||
{
|
||||
struct client *client = stream->client;
|
||||
struct impl *impl = client->impl;
|
||||
struct message *reply;
|
||||
struct spa_dict_item items[1];
|
||||
char latency[32];
|
||||
|
|
@ -825,8 +825,8 @@ static int reply_create_record_stream(struct stream *stream)
|
|||
message_put(reply,
|
||||
TAG_SAMPLE_SPEC, &stream->ss,
|
||||
TAG_CHANNEL_MAP, &stream->map,
|
||||
TAG_U32, impl->default_source.index, /* source index */
|
||||
TAG_STRING, impl->default_source.name, /* source name */
|
||||
TAG_U32, stream->dev->index, /* source index */
|
||||
TAG_STRING, stream->dev->name, /* source name */
|
||||
TAG_BOOLEAN, false, /* source suspended state */
|
||||
TAG_INVALID);
|
||||
}
|
||||
|
|
@ -1085,6 +1085,40 @@ static const struct pw_stream_events stream_events =
|
|||
.drained = stream_drained,
|
||||
};
|
||||
|
||||
static struct device *find_device_by_name(struct impl *impl, const char *name)
|
||||
{
|
||||
struct device *dev;
|
||||
if (strcmp(name, impl->default_source.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_SOURCE@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_source.index)
|
||||
dev = &impl->default_source;
|
||||
else if (strcmp(name, impl->default_sink.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_SINK@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_sink.index)
|
||||
dev = &impl->default_sink;
|
||||
else if (strcmp(name, impl->default_monitor.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_MONITOR@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_monitor.index)
|
||||
dev = &impl->default_monitor;
|
||||
else
|
||||
dev = NULL;
|
||||
return dev;
|
||||
}
|
||||
|
||||
static struct device *find_device_by_index(struct impl *impl, uint32_t index)
|
||||
{
|
||||
struct device *dev;
|
||||
if (impl->default_source.index == index)
|
||||
dev = &impl->default_source;
|
||||
else if (impl->default_sink.index == index)
|
||||
dev = &impl->default_sink;
|
||||
else if (impl->default_monitor.index == index)
|
||||
dev = &impl->default_monitor;
|
||||
else
|
||||
dev = NULL;
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void fix_stream_properties(struct stream *stream, struct pw_properties *props)
|
||||
{
|
||||
const char *str;
|
||||
|
|
@ -1150,6 +1184,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
|
|||
const struct spa_pod *params[32];
|
||||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
struct device *dev = NULL;
|
||||
|
||||
props = pw_properties_new(NULL, NULL);
|
||||
if (props == NULL) {
|
||||
|
|
@ -1185,6 +1220,22 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
|
|||
pw_log_info(NAME" %p: CREATE_PLAYBACK_STREAM corked:%u sink-name:%s sink-idx:%u",
|
||||
impl, corked, sink_name, sink_index);
|
||||
|
||||
if (sink_index != SPA_ID_INVALID && sink_name != NULL) {
|
||||
res = -EINVAL;
|
||||
goto error;
|
||||
} else if ((sink_index != SPA_ID_INVALID || sink_name != NULL)) {
|
||||
if (sink_index != SPA_ID_INVALID)
|
||||
dev = find_device_by_index(impl, sink_index);
|
||||
else if (sink_name != NULL)
|
||||
dev = find_device_by_name(impl, sink_name);
|
||||
if (dev == NULL) {
|
||||
res = -ENOENT;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
dev = &impl->default_sink;
|
||||
}
|
||||
|
||||
if (client->version >= 12) {
|
||||
if ((res = message_get(m,
|
||||
TAG_BOOLEAN, &no_remap,
|
||||
|
|
@ -1295,6 +1346,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
|
|||
stream->muted = muted;
|
||||
stream->muted_set = muted_set;
|
||||
stream->attr = attr;
|
||||
stream->dev = dev;
|
||||
|
||||
flags = 0;
|
||||
if (no_move)
|
||||
|
|
@ -1330,40 +1382,6 @@ error:
|
|||
return res;
|
||||
}
|
||||
|
||||
static struct device *find_device_by_name(struct impl *impl, const char *name)
|
||||
{
|
||||
struct device *dev;
|
||||
if (strcmp(name, impl->default_source.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_SOURCE@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_source.index)
|
||||
dev = &impl->default_source;
|
||||
else if (strcmp(name, impl->default_sink.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_SINK@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_sink.index)
|
||||
dev = &impl->default_sink;
|
||||
else if (strcmp(name, impl->default_monitor.name) == 0 ||
|
||||
strcmp(name, "@DEFAULT_MONITOR@") == 0 ||
|
||||
(uint32_t)atoi(name) == impl->default_monitor.index)
|
||||
dev = &impl->default_monitor;
|
||||
else
|
||||
dev = NULL;
|
||||
return dev;
|
||||
}
|
||||
|
||||
static struct device *find_device_by_index(struct impl *impl, uint32_t index)
|
||||
{
|
||||
struct device *dev;
|
||||
if (impl->default_source.index == index)
|
||||
dev = &impl->default_source;
|
||||
else if (impl->default_sink.index == index)
|
||||
dev = &impl->default_sink;
|
||||
else if (impl->default_monitor.index == index)
|
||||
dev = &impl->default_monitor;
|
||||
else
|
||||
dev = NULL;
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int do_create_record_stream(struct client *client, uint32_t command, uint32_t tag, struct message *m)
|
||||
{
|
||||
struct impl *impl = client->impl;
|
||||
|
|
@ -1401,6 +1419,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
|
|||
const struct spa_pod *params[32];
|
||||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
struct device *dev = NULL;
|
||||
|
||||
props = pw_properties_new(NULL, NULL);
|
||||
if (props == NULL) {
|
||||
|
|
@ -1432,6 +1451,26 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
|
|||
pw_log_info(NAME" %p: CREATE_RECORD_STREAM corked:%u source-name:%s source-index:%u",
|
||||
impl, corked, source_name, source_index);
|
||||
|
||||
if (source_index != SPA_ID_INVALID && source_name != NULL) {
|
||||
res = -EINVAL;
|
||||
goto error;
|
||||
} else if ((source_index != SPA_ID_INVALID || source_name != NULL)) {
|
||||
if (source_index != SPA_ID_INVALID)
|
||||
dev = find_device_by_index(impl, source_index);
|
||||
else if (source_name != NULL)
|
||||
dev = find_device_by_name(impl, source_name);
|
||||
if (dev == NULL) {
|
||||
res = -ENOENT;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
dev = &impl->default_source;
|
||||
}
|
||||
if (dev->direction == PW_DIRECTION_INPUT) {
|
||||
pw_properties_set(props, PW_KEY_STREAM_CAPTURE_SINK, "true");
|
||||
dev = dev->monitor;
|
||||
}
|
||||
|
||||
if (client->version >= 12) {
|
||||
if ((res = message_get(m,
|
||||
TAG_BOOLEAN, &no_remap,
|
||||
|
|
@ -1537,6 +1576,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
|
|||
stream->muted = muted;
|
||||
stream->muted_set = muted_set;
|
||||
stream->attr = attr;
|
||||
stream->dev = dev;
|
||||
|
||||
if (peak_detect)
|
||||
pw_properties_set(props, PW_KEY_STREAM_MONITOR, "true");
|
||||
|
|
|
|||
|
|
@ -228,6 +228,8 @@ extern "C" {
|
|||
* and might select a less accurate but faster
|
||||
* conversion algorithm. */
|
||||
#define PW_KEY_STREAM_DONT_REMIX "stream.dont-remix" /**< don't remix channels */
|
||||
#define PW_KEY_STREAM_CAPTURE_SINK "stream.capture.sink" /**< Try to capture the sink output instead of
|
||||
* source output */
|
||||
|
||||
/** object properties */
|
||||
#define PW_KEY_OBJECT_LINGER "object.linger" /**< the object lives on even after the client
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue