mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
modules: improve loopback module
Handle error when loading and fix leaks. Mark streams as virtual if nothing else is specified. Try to reuse an existing core connection if possible. unload the module when the core is in error or when it is destroyed.
This commit is contained in:
parent
3b021cc4ed
commit
93d1c8f31d
1 changed files with 70 additions and 15 deletions
|
|
@ -74,6 +74,9 @@ static const struct spa_dict_item module_props[] = {
|
|||
struct impl {
|
||||
struct pw_context *context;
|
||||
|
||||
struct pw_impl_module *module;
|
||||
struct pw_work_queue *work;
|
||||
|
||||
struct spa_hook module_listener;
|
||||
|
||||
struct pw_core *core;
|
||||
|
|
@ -89,8 +92,24 @@ struct impl {
|
|||
struct pw_properties *playback_props;
|
||||
struct pw_stream *playback;
|
||||
struct spa_hook playback_listener;
|
||||
|
||||
unsigned int do_disconnect:1;
|
||||
unsigned int unloading:1;
|
||||
};
|
||||
|
||||
static void do_unload_module(void *obj, void *data, int res, uint32_t id)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
pw_impl_module_destroy(impl->module);
|
||||
}
|
||||
static void unload_module(struct impl *impl)
|
||||
{
|
||||
if (!impl->unloading) {
|
||||
impl->unloading = true;
|
||||
pw_work_queue_add(impl->work, impl, 0, do_unload_module, impl);
|
||||
}
|
||||
}
|
||||
|
||||
static void capture_destroy(void *d)
|
||||
{
|
||||
struct impl *impl = d;
|
||||
|
|
@ -206,8 +225,13 @@ static int setup_streams(struct impl *impl)
|
|||
|
||||
static void core_error(void *data, uint32_t id, int seq, int res, const char *message)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
|
||||
pw_log_error("error id:%u seq:%d res:%d (%s): %s",
|
||||
id, seq, res, spa_strerror(res), message);
|
||||
|
||||
if (id == PW_ID_CORE && res == -EPIPE)
|
||||
unload_module(impl);
|
||||
}
|
||||
|
||||
static const struct pw_core_events core_events = {
|
||||
|
|
@ -220,23 +244,20 @@ static void core_destroy(void *d)
|
|||
struct impl *impl = d;
|
||||
spa_hook_remove(&impl->core_listener);
|
||||
impl->core = NULL;
|
||||
unload_module(impl);
|
||||
}
|
||||
|
||||
static const struct pw_proxy_events core_proxy_events = {
|
||||
.destroy = core_destroy,
|
||||
};
|
||||
|
||||
static void module_destroy(void *data)
|
||||
static void impl_destroy(struct impl *impl)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
|
||||
spa_hook_remove(&impl->module_listener);
|
||||
|
||||
if (impl->capture)
|
||||
pw_stream_destroy(impl->capture);
|
||||
if (impl->playback)
|
||||
pw_stream_destroy(impl->playback);
|
||||
if (impl->core)
|
||||
if (impl->core && impl->do_disconnect)
|
||||
pw_core_disconnect(impl->core);
|
||||
if (impl->capture_props)
|
||||
pw_properties_free(impl->capture_props);
|
||||
|
|
@ -245,6 +266,13 @@ static void module_destroy(void *data)
|
|||
free(impl);
|
||||
}
|
||||
|
||||
static void module_destroy(void *data)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
spa_hook_remove(&impl->module_listener);
|
||||
impl_destroy(impl);
|
||||
}
|
||||
|
||||
static const struct pw_impl_module_events module_events = {
|
||||
PW_VERSION_IMPL_MODULE_EVENTS,
|
||||
.destroy = module_destroy,
|
||||
|
|
@ -284,6 +312,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
struct impl *impl;
|
||||
uint32_t id = pw_global_get_id(pw_impl_module_get_global(module));
|
||||
const char *str;
|
||||
int res;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
if (impl == NULL)
|
||||
|
|
@ -297,15 +326,23 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
props = pw_properties_new_string(args);
|
||||
else
|
||||
props = pw_properties_new(NULL, NULL);
|
||||
if (props == NULL) {
|
||||
res = -errno;
|
||||
pw_log_error( "can't create properties: %m");
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->capture_props = pw_properties_new(NULL, NULL);
|
||||
impl->playback_props = pw_properties_new(NULL, NULL);
|
||||
if (impl->capture_props == NULL || impl->playback_props == NULL) {
|
||||
res = -errno;
|
||||
pw_log_error( "can't create properties: %m");
|
||||
return -errno;
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->module = module;
|
||||
impl->context = context;
|
||||
impl->work = pw_context_get_work_queue(context);
|
||||
|
||||
if ((str = pw_properties_get(props, PW_KEY_AUDIO_RATE)) != NULL)
|
||||
impl->info.rate = atoi(str);
|
||||
|
|
@ -324,16 +361,28 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
if (pw_properties_get(impl->playback_props, PW_KEY_NODE_GROUP) == NULL)
|
||||
pw_properties_setf(impl->playback_props, PW_KEY_NODE_GROUP, "loopback-%u", id);
|
||||
|
||||
str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
|
||||
impl->core = pw_context_connect(impl->context,
|
||||
pw_properties_new(
|
||||
PW_KEY_REMOTE_NAME, str,
|
||||
NULL),
|
||||
0);
|
||||
if (pw_properties_get(impl->capture_props, PW_KEY_NODE_VIRTUAL) == NULL)
|
||||
pw_properties_set(impl->capture_props, PW_KEY_NODE_VIRTUAL, "true");
|
||||
if (pw_properties_get(impl->playback_props, PW_KEY_NODE_VIRTUAL) == NULL)
|
||||
pw_properties_set(impl->playback_props, PW_KEY_NODE_VIRTUAL, "true");
|
||||
|
||||
impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
|
||||
if (impl->core == NULL) {
|
||||
pw_log_error("can't connect: %m");
|
||||
return -errno;
|
||||
str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
|
||||
impl->core = pw_context_connect(impl->context,
|
||||
pw_properties_new(
|
||||
PW_KEY_REMOTE_NAME, str,
|
||||
NULL),
|
||||
0);
|
||||
impl->do_disconnect = true;
|
||||
}
|
||||
if (impl->core == NULL) {
|
||||
res = -errno;
|
||||
pw_log_error("can't connect: %m");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pw_properties_free(props);
|
||||
|
||||
pw_proxy_add_listener((struct pw_proxy*)impl->core,
|
||||
&impl->core_proxy_listener,
|
||||
|
|
@ -349,4 +398,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (props)
|
||||
pw_properties_free(props);
|
||||
impl_destroy(impl);
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue