context: support foreign mainloop_api

Detect if the mainloop_api is one of ours and use the loop directly in
that case. Otherwise, make a new loop and add the fd to the foreign
mainloop_api. Make sure we clean up as well.

Fixes #345
This commit is contained in:
Wim Taymans 2020-10-22 12:24:49 +02:00
parent 7782352e8d
commit 55b4042512
3 changed files with 51 additions and 5 deletions

View file

@ -1664,12 +1664,24 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_c
return o; return o;
} }
static void io_event_cb(pa_mainloop_api*ea, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata)
{
pa_context *c = userdata;
if (events & PA_IO_EVENT_INPUT) {
pw_log_debug("%p: iterate loop %p", c, c->loop);
pw_loop_enter(c->loop);
pw_loop_iterate(c->loop, -1);
pw_loop_leave(c->loop);
}
}
SPA_EXPORT SPA_EXPORT
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, PA_CONST pa_proplist *p) pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, PA_CONST pa_proplist *p)
{ {
struct pw_context *context; struct pw_context *context;
struct pw_loop *loop; struct pw_loop *loop;
struct pw_properties *props; struct pw_properties *props;
bool fallback_loop = false;
pa_context *c; pa_context *c;
pa_assert(mainloop); pa_assert(mainloop);
@ -1681,7 +1693,15 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
if (p) if (p)
pw_properties_update_proplist(props, p); pw_properties_update_proplist(props, p);
loop = mainloop->userdata; if (pa_mainloop_api_is_pipewire(mainloop))
loop = mainloop->userdata;
else {
loop = pw_loop_new(NULL);
fallback_loop = true;
}
pw_log_debug("mainloop:%p loop:%p", mainloop, loop);
context = pw_context_new(loop, context = pw_context_new(loop,
pw_properties_new( pw_properties_new(
PW_KEY_CONTEXT_PROFILE_MODULES, "default", PW_KEY_CONTEXT_PROFILE_MODULES, "default",
@ -1692,6 +1712,7 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
c = pw_context_get_user_data(context); c = pw_context_get_user_data(context);
c->props = props; c->props = props;
c->fallback_loop = fallback_loop;
c->loop = loop; c->loop = loop;
c->context = context; c->context = context;
c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new(); c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
@ -1699,14 +1720,20 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
c->client_index = PA_INVALID_INDEX; c->client_index = PA_INVALID_INDEX;
c->default_sink = SPA_ID_INVALID; c->default_sink = SPA_ID_INVALID;
c->default_source = SPA_ID_INVALID; c->default_source = SPA_ID_INVALID;
if (name)
pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
c->mainloop = mainloop; c->mainloop = mainloop;
c->error = 0; c->error = 0;
c->state = PA_CONTEXT_UNCONNECTED; c->state = PA_CONTEXT_UNCONNECTED;
if (c->fallback_loop) {
c->io = c->mainloop->io_new(c->mainloop,
pw_loop_get_fd(c->loop),
PA_IO_EVENT_INPUT,
io_event_cb, c);
}
if (name)
pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
spa_list_init(&c->globals); spa_list_init(&c->globals);
spa_list_init(&c->streams); spa_list_init(&c->streams);
@ -1718,6 +1745,7 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
static void context_free(pa_context *c) static void context_free(pa_context *c)
{ {
struct pw_loop *loop;
pw_log_debug("context %p: free", c); pw_log_debug("context %p: free", c);
context_unlink(c); context_unlink(c);
@ -1728,7 +1756,14 @@ static void context_free(pa_context *c)
if (c->core_info) if (c->core_info)
pw_core_info_free(c->core_info); pw_core_info_free(c->core_info);
if (c->io)
c->mainloop->io_free(c->io);
loop = c->fallback_loop ? c->loop : NULL;
pw_context_destroy(c->context); pw_context_destroy(c->context);
if (loop)
pw_loop_destroy(loop);
} }
SPA_EXPORT SPA_EXPORT

View file

@ -346,6 +346,8 @@ struct pa_context {
int refcount; int refcount;
uint32_t client_index; uint32_t client_index;
pa_io_event *io;
bool fallback_loop;
struct pw_loop *loop; struct pw_loop *loop;
struct pw_context *context; struct pw_context *context;
@ -504,6 +506,7 @@ struct pa_operation
void *state_userdata; void *state_userdata;
}; };
bool pa_mainloop_api_is_pipewire(pa_mainloop_api *api);
pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, size_t userdata_size); pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, size_t userdata_size);
void pa_operation_done(pa_operation *o); void pa_operation_done(pa_operation *o);

View file

@ -272,6 +272,8 @@ pa_mainloop *pa_mainloop_new(void)
loop->api = api; loop->api = api;
loop->api.userdata = loop->loop; loop->api.userdata = loop->loop;
pw_log_debug("%p: %p fd:%d", loop, loop->loop, loop->fd);
return loop; return loop;
no_loop: no_loop:
@ -279,9 +281,15 @@ pa_mainloop *pa_mainloop_new(void)
return NULL; return NULL;
} }
bool pa_mainloop_api_is_pipewire(pa_mainloop_api *api)
{
return api && api->io_new == api_io_new;
}
SPA_EXPORT SPA_EXPORT
void pa_mainloop_free(pa_mainloop* m) void pa_mainloop_free(pa_mainloop* m)
{ {
pw_log_debug("%p", m);
pw_loop_destroy(m->loop); pw_loop_destroy(m->loop);
free(m); free(m);
} }