mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
stream: fix introspection of linked device
This commit is contained in:
parent
3cfbdc750a
commit
71d87c589d
4 changed files with 165 additions and 35 deletions
|
|
@ -86,6 +86,16 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name)
|
|||
return pa_context_new_with_proplist(mainloop, name, NULL);
|
||||
}
|
||||
|
||||
struct global *pa_context_find_global(pa_context *c, uint32_t id)
|
||||
{
|
||||
struct global *g;
|
||||
spa_list_for_each(g, &c->globals, link) {
|
||||
if (g->id == id)
|
||||
return g;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int set_mask(pa_context *c, struct global *g)
|
||||
{
|
||||
const char *str;
|
||||
|
|
@ -100,10 +110,24 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
g->mask = PA_SUBSCRIPTION_MASK_SINK;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_SINK;
|
||||
}
|
||||
else if (strcmp(str, "Audio/DSP/Playback") == 0) {
|
||||
if ((str = pw_properties_get(g->props, "node.session")) == NULL)
|
||||
return 0;
|
||||
g->mask = PA_SUBSCRIPTION_MASK_DSP_SINK;
|
||||
g->dsp_info.session = pa_context_find_global(c,
|
||||
pw_properties_parse_int(str));
|
||||
}
|
||||
else if (strcmp(str, "Audio/Source") == 0) {
|
||||
g->mask = PA_SUBSCRIPTION_MASK_SOURCE;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_SOURCE;
|
||||
}
|
||||
else if (strcmp(str, "Audio/DSP/Capture") == 0) {
|
||||
if ((str = pw_properties_get(g->props, "node.session")) == NULL)
|
||||
return 0;
|
||||
g->mask = PA_SUBSCRIPTION_MASK_DSP_SOURCE;
|
||||
g->dsp_info.session = pa_context_find_global(c,
|
||||
pw_properties_parse_int(str));
|
||||
}
|
||||
else if (strcmp(str, "Stream/Output/Audio") == 0) {
|
||||
g->mask = PA_SUBSCRIPTION_MASK_SINK_INPUT;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_SINK_INPUT;
|
||||
|
|
@ -112,8 +136,6 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
g->mask = PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if (g->type == c->t->module) {
|
||||
g->mask = PA_SUBSCRIPTION_MASK_MODULE;
|
||||
|
|
@ -123,6 +145,23 @@ static int set_mask(pa_context *c, struct global *g)
|
|||
g->mask = PA_SUBSCRIPTION_MASK_CLIENT;
|
||||
g->event = PA_SUBSCRIPTION_EVENT_CLIENT;
|
||||
}
|
||||
else if (g->type == c->t->port) {
|
||||
pw_log_debug("found port %d", g->id);
|
||||
}
|
||||
else if (g->type == c->t->link) {
|
||||
if ((str = pw_properties_get(g->props, "link.output")) == NULL)
|
||||
return 0;
|
||||
g->link_info.src = pa_context_find_global(c, pw_properties_parse_int(str));
|
||||
if ((str = pw_properties_get(g->props, "link.input")) == NULL)
|
||||
return 0;
|
||||
g->link_info.dst = pa_context_find_global(c, pw_properties_parse_int(str));
|
||||
|
||||
if (g->link_info.src == NULL || g->link_info.dst == NULL)
|
||||
return 0;
|
||||
|
||||
pw_log_debug("link %d->%d", g->link_info.src->parent_id,
|
||||
g->link_info.dst->parent_id);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
|
|
@ -146,6 +185,7 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id,
|
|||
if (set_mask(c, g) == 0)
|
||||
return;
|
||||
|
||||
pw_log_debug("mask %d/%d", g->mask, g->event);
|
||||
spa_list_append(&c->globals, &g->link);
|
||||
|
||||
if (c->subscribe_mask & g->mask) {
|
||||
|
|
@ -157,16 +197,6 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id,
|
|||
}
|
||||
}
|
||||
|
||||
struct global *pa_context_find_global(pa_context *c, uint32_t id)
|
||||
{
|
||||
struct global *g;
|
||||
spa_list_for_each(g, &c->globals, link) {
|
||||
if (g->id == id)
|
||||
return g;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void registry_event_global_remove(void *object, uint32_t id)
|
||||
{
|
||||
pa_context *c = object;
|
||||
|
|
|
|||
|
|
@ -190,6 +190,10 @@ struct pa_mainloop {
|
|||
int n_events;
|
||||
};
|
||||
|
||||
#define PA_SUBSCRIPTION_MASK_DSP_SINK 0x1000U
|
||||
#define PA_SUBSCRIPTION_MASK_DSP_SOURCE 0x2000U
|
||||
#define PA_SUBSCRIPTION_MASK_DSP (PA_SUBSCRIPTION_MASK_DSP_SINK | PA_SUBSCRIPTION_MASK_DSP_SOURCE)
|
||||
|
||||
struct global {
|
||||
struct spa_list link;
|
||||
uint32_t id;
|
||||
|
|
@ -206,6 +210,17 @@ struct global {
|
|||
struct pw_proxy *proxy;
|
||||
struct spa_hook proxy_listener;
|
||||
struct spa_hook proxy_proxy_listener;
|
||||
|
||||
/* for links */
|
||||
union {
|
||||
struct {
|
||||
struct global *src;
|
||||
struct global *dst;
|
||||
} link_info;
|
||||
struct {
|
||||
struct global *session;
|
||||
} dsp_info;
|
||||
};
|
||||
};
|
||||
|
||||
struct pa_context {
|
||||
|
|
@ -333,6 +348,7 @@ struct pa_stream {
|
|||
struct pw_buffer *dequeued[MAX_BUFFERS];
|
||||
struct spa_ringbuffer dequeued_ring;
|
||||
size_t dequeued_size;
|
||||
size_t maxsize;
|
||||
struct spa_list pending;
|
||||
|
||||
struct pw_buffer *buffer;
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ static void sink_callback(struct sink_data *d)
|
|||
spa_zero(i);
|
||||
i.index = g->id;
|
||||
i.name = info->name;
|
||||
i.description = info->name;
|
||||
i.proplist = pa_proplist_new_dict(info->props);
|
||||
i.owner_module = g->parent_id;
|
||||
i.base_volume = PA_VOLUME_NORM;
|
||||
|
|
@ -339,6 +340,7 @@ static void source_info(pa_operation *o, void *userdata)
|
|||
struct source_data *d = userdata;
|
||||
source_callback(d);
|
||||
d->cb(d->context, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata)
|
||||
|
|
@ -388,6 +390,7 @@ static void source_info_list(pa_operation *o, void *userdata)
|
|||
source_callback(d);
|
||||
}
|
||||
d->cb(c, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata)
|
||||
|
|
@ -493,6 +496,7 @@ static void module_info(pa_operation *o, void *userdata)
|
|||
struct module_data *d = userdata;
|
||||
module_callback(d);
|
||||
d->cb(d->context, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata)
|
||||
|
|
@ -537,6 +541,7 @@ static void module_info_list(pa_operation *o, void *userdata)
|
|||
module_callback(d);
|
||||
}
|
||||
d->cb(c, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata)
|
||||
|
|
@ -601,6 +606,7 @@ static void client_info(pa_operation *o, void *userdata)
|
|||
struct client_data *d = userdata;
|
||||
client_callback(d);
|
||||
d->cb(d->context, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata)
|
||||
|
|
@ -645,6 +651,7 @@ static void client_info_list(pa_operation *o, void *userdata)
|
|||
client_callback(d);
|
||||
}
|
||||
d->cb(c, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata)
|
||||
|
|
@ -717,14 +724,27 @@ struct sink_input_data {
|
|||
struct global *global;
|
||||
};
|
||||
|
||||
static pa_stream *find_stream(pa_context *c, uint32_t idx)
|
||||
{
|
||||
pa_stream *s;
|
||||
spa_list_for_each(s, &c->streams, link) {
|
||||
if (pw_stream_get_node_id(s->stream) == idx)
|
||||
return s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sink_input_callback(struct sink_input_data *d)
|
||||
{
|
||||
struct global *g = d->global;
|
||||
struct pw_node_info *info = g->info;
|
||||
pa_sink_input_info i;
|
||||
pa_format_info ii[1];
|
||||
pa_stream *s;
|
||||
|
||||
pw_log_debug("index %d", g->id);
|
||||
s = find_stream(d->context, g->id);
|
||||
|
||||
spa_zero(i);
|
||||
i.index = g->id;
|
||||
i.name = info->name;
|
||||
|
|
@ -740,7 +760,11 @@ static void sink_input_callback(struct sink_input_data *d)
|
|||
i.has_volume = true;
|
||||
i.volume_writable = true;
|
||||
i.volume.channels = 1;
|
||||
i.volume.values[0] = PA_VOLUME_NORM;
|
||||
if (s)
|
||||
i.volume.values[0] = s->volume * PA_VOLUME_NORM;
|
||||
else
|
||||
i.volume.values[0] = PA_VOLUME_NORM;
|
||||
|
||||
d->cb(d->context, &i, 0, d->userdata);
|
||||
}
|
||||
|
||||
|
|
@ -749,6 +773,7 @@ static void sink_input_info(pa_operation *o, void *userdata)
|
|||
struct sink_input_data *d = userdata;
|
||||
sink_input_callback(d);
|
||||
d->cb(d->context, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata)
|
||||
|
|
@ -792,6 +817,7 @@ static void sink_input_info_list(pa_operation *o, void *userdata)
|
|||
sink_input_callback(d);
|
||||
}
|
||||
d->cb(c, NULL, 1, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata)
|
||||
|
|
@ -826,16 +852,6 @@ pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, u
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static pa_stream *find_stream(pa_context *c, uint32_t idx)
|
||||
{
|
||||
pa_stream *s;
|
||||
spa_list_for_each(s, &c->streams, link) {
|
||||
if (pw_stream_get_node_id(s->stream) == idx)
|
||||
return s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct success_ack {
|
||||
pa_context_success_cb_t cb;
|
||||
void *userdata;
|
||||
|
|
@ -845,9 +861,9 @@ static void on_success(pa_operation *o, void *userdata)
|
|||
{
|
||||
struct success_ack *d = userdata;
|
||||
pa_context *c = o->context;
|
||||
pa_operation_done(o);
|
||||
if (d->cb)
|
||||
d->cb(c, PA_OK, d->userdata);
|
||||
pa_operation_done(o);
|
||||
}
|
||||
|
||||
pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata)
|
||||
|
|
|
|||
90
src/stream.c
90
src/stream.c
|
|
@ -96,10 +96,70 @@ static int dequeue_buffer(pa_stream *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dump_buffer_attr(pa_stream *s, pa_buffer_attr *attr)
|
||||
{
|
||||
pw_log_info("stream %p: maxlength: %u", s, attr->maxlength);
|
||||
pw_log_info("stream %p: tlength: %u", s, attr->tlength);
|
||||
pw_log_info("stream %p: minreq: %u", s, attr->minreq);
|
||||
pw_log_info("stream %p: prebuf: %u", s, attr->prebuf);
|
||||
pw_log_info("stream %p: fragsize: %u", s, attr->fragsize);
|
||||
}
|
||||
|
||||
static void configure_buffers(pa_stream *s)
|
||||
{
|
||||
s->buffer_attr.maxlength = 65536;
|
||||
s->buffer_attr.maxlength = s->maxsize;
|
||||
s->buffer_attr.prebuf = s->buffer_attr.minreq;
|
||||
s->buffer_attr.fragsize = s->buffer_attr.minreq;
|
||||
dump_buffer_attr(s, &s->buffer_attr);
|
||||
}
|
||||
|
||||
static struct global *find_linked(pa_stream *s, uint32_t idx)
|
||||
{
|
||||
struct global *g, *f;
|
||||
pa_context *c = s->context;
|
||||
|
||||
spa_list_for_each(g, &c->globals, link) {
|
||||
if (g->type != c->t->link)
|
||||
continue;
|
||||
|
||||
pw_log_debug("%d %d %d", idx,
|
||||
g->link_info.src->parent_id,
|
||||
g->link_info.dst->parent_id);
|
||||
|
||||
if (g->link_info.src->parent_id == idx)
|
||||
f = pa_context_find_global(c, g->link_info.dst->parent_id);
|
||||
else if (g->link_info.dst->parent_id == idx)
|
||||
f = pa_context_find_global(c, g->link_info.src->parent_id);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (f == NULL)
|
||||
continue;
|
||||
if (f->mask & PA_SUBSCRIPTION_MASK_DSP) {
|
||||
f = f->dsp_info.session;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static void configure_device(pa_stream *s)
|
||||
{
|
||||
struct global *g;
|
||||
const char *str;
|
||||
|
||||
g = find_linked(s, pa_stream_get_index(s));
|
||||
if (g == NULL) {
|
||||
s->device_index = PA_INVALID_INDEX;
|
||||
s->device_name = NULL;
|
||||
}
|
||||
else {
|
||||
s->device_index = g->id;
|
||||
if ((str = pw_properties_get(g->props, "node.name")) == NULL)
|
||||
s->device_name = strdup("unknown");
|
||||
else
|
||||
s->device_name = strdup(str);
|
||||
}
|
||||
pw_log_debug("linked to %d '%s'", s->device_index, s->device_name);
|
||||
}
|
||||
|
||||
static void stream_state_changed(void *data, enum pw_stream_state old,
|
||||
|
|
@ -122,6 +182,7 @@ static void stream_state_changed(void *data, enum pw_stream_state old,
|
|||
case PW_STREAM_STATE_READY:
|
||||
break;
|
||||
case PW_STREAM_STATE_PAUSED:
|
||||
configure_device(s);
|
||||
configure_buffers(s);
|
||||
pa_stream_set_state(s, PA_STREAM_READY);
|
||||
break;
|
||||
|
|
@ -219,14 +280,9 @@ static void patch_buffer_attr(pa_stream *s, pa_buffer_attr *attr, pa_stream_flag
|
|||
if (attr->fragsize == (uint32_t) -1)
|
||||
attr->fragsize = attr->tlength; /* Pass data to the app only when the buffer is filled up once */
|
||||
|
||||
pw_log_info("stream %p: maxlength: %u", s, attr->maxlength);
|
||||
pw_log_info("stream %p: tlength: %u", s, attr->tlength);
|
||||
pw_log_info("stream %p: minreq: %u", s, attr->minreq);
|
||||
pw_log_info("stream %p: prebuf: %u", s, attr->prebuf);
|
||||
pw_log_info("stream %p: fragsize: %u", s, attr->fragsize);
|
||||
dump_buffer_attr(s, attr);
|
||||
}
|
||||
|
||||
|
||||
static void stream_format_changed(void *data, const struct spa_pod *format)
|
||||
{
|
||||
pa_stream *s = data;
|
||||
|
|
@ -271,6 +327,17 @@ static void stream_format_changed(void *data, const struct spa_pod *format)
|
|||
pw_stream_finish_format(s->stream, res, params, n_params);
|
||||
}
|
||||
|
||||
static void stream_add_buffer(void *data, struct pw_buffer *buffer)
|
||||
{
|
||||
pa_stream *s = data;
|
||||
s->maxsize += buffer->buffer->datas[0].maxsize;
|
||||
}
|
||||
static void stream_remove_buffer(void *data, struct pw_buffer *buffer)
|
||||
{
|
||||
pa_stream *s = data;
|
||||
s->maxsize -= buffer->buffer->datas[0].maxsize;
|
||||
}
|
||||
|
||||
static void stream_process(void *data)
|
||||
{
|
||||
pa_stream *s = data;
|
||||
|
|
@ -295,6 +362,8 @@ static const struct pw_stream_events stream_events =
|
|||
PW_VERSION_STREAM_EVENTS,
|
||||
.state_changed = stream_state_changed,
|
||||
.format_changed = stream_format_changed,
|
||||
.add_buffer = stream_add_buffer,
|
||||
.remove_buffer = stream_remove_buffer,
|
||||
.process = stream_process,
|
||||
};
|
||||
|
||||
|
|
@ -378,9 +447,7 @@ pa_stream* stream_new(pa_context *c, const char *name,
|
|||
s->buffer_attr.fragsize = (uint32_t) -1;
|
||||
|
||||
s->device_index = PA_INVALID_INDEX;
|
||||
|
||||
s->device_index = 0;
|
||||
s->device_name = strdup("unknown");
|
||||
s->device_name = NULL;
|
||||
|
||||
spa_ringbuffer_init(&s->dequeued_ring);
|
||||
|
||||
|
|
@ -479,6 +546,7 @@ void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) {
|
|||
|
||||
pa_stream_ref(s);
|
||||
|
||||
pw_log_debug("stream %p: state %d -> %d", s, s->state, st);
|
||||
s->state = st;
|
||||
|
||||
if (s->state_callback)
|
||||
|
|
@ -1279,7 +1347,7 @@ int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec)
|
|||
if (r_usec)
|
||||
*r_usec = res;
|
||||
|
||||
pw_log_debug("stream %p: %ld %ld %ld %ld %d/%d %ld", s, now, t.now, delay, t.ticks, t.rate.num, t.rate.denom, res);
|
||||
pw_log_trace("stream %p: %ld %ld %ld %ld %d/%d %ld", s, now, t.now, delay, t.ticks, t.rate.num, t.rate.denom, res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue