This makes the tunnel manager load tunnel sinks and sources for all devices in the remote servers, except for monitor sources. --- src/modules/tunnel-manager/tunnel-manager.c | 81 +++++++++++++++++++++++++++++ src/modules/tunnel-manager/tunnel-manager.h | 4 ++ 2 files changed, 85 insertions(+) diff --git a/src/modules/tunnel-manager/tunnel-manager.c b/src/modules/tunnel-manager/tunnel-manager.c index cb8b3a6..0735c66 100644 --- a/src/modules/tunnel-manager/tunnel-manager.c +++ b/src/modules/tunnel-manager/tunnel-manager.c @@ -46,6 +46,7 @@ static void remote_server_set_failed(pa_tunnel_manager_remote_server *server, bo static void remote_device_new(pa_tunnel_manager_remote_server *server, pa_device_type_t type, const void *info); static void remote_device_free(pa_tunnel_manager_remote_device *device); static void remote_device_update(pa_tunnel_manager_remote_device *device); +static void remote_device_apply_tunnel_enabled_policy(pa_tunnel_manager_remote_device *device); struct device_stub { pa_tunnel_manager_remote_server *server; @@ -67,6 +68,21 @@ static void device_stub_new(pa_tunnel_manager_remote_server *server, pa_device_t static void device_stub_unlink(struct device_stub *stub); static void device_stub_free(struct device_stub *stub); +static pa_hook_result_t module_unload_cb(void *hook_data, void *call_data, void *userdata) { + pa_module *module = call_data; + pa_tunnel_manager *manager = userdata; + pa_tunnel_manager_remote_device *device; + + pa_assert(module); + pa_assert(manager); + + device = pa_hashmap_remove(manager->remote_devices_by_module, module); + if (device) + device->tunnel_module = NULL; + + return PA_HOOK_OK; +} + static pa_tunnel_manager *tunnel_manager_new(pa_core *core) { pa_tunnel_manager *manager; pa_tunnel_manager_config *manager_config; @@ -77,9 +93,13 @@ static pa_tunnel_manager *tunnel_manager_new(pa_core *core) { manager = pa_xnew0(pa_tunnel_manager, 1); manager->core = core; + manager->remote_devices_by_module = pa_hashmap_new(NULL, NULL); manager->remote_servers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); manager->refcnt = 1; + manager->module_unload_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_MODULE_UNLOAD], PA_HOOK_NORMAL, module_unload_cb, + manager); + manager_config = pa_tunnel_manager_config_new(); PA_HASHMAP_FOREACH(server_config, manager_config->remote_servers, state) @@ -98,6 +118,9 @@ static void tunnel_manager_free(pa_tunnel_manager *manager) { pa_shared_remove(manager->core, "tunnel_manager"); + if (manager->module_unload_slot) + pa_hook_slot_free(manager->module_unload_slot); + if (manager->remote_servers) { pa_tunnel_manager_remote_server *server; @@ -107,6 +130,11 @@ static void tunnel_manager_free(pa_tunnel_manager *manager) { pa_hashmap_free(manager->remote_servers); } + if (manager->remote_devices_by_module) { + pa_assert(pa_hashmap_isempty(manager->remote_devices_by_module)); + pa_hashmap_free(manager->remote_devices_by_module); + } + pa_xfree(manager); } @@ -561,6 +589,36 @@ static void remote_device_new(pa_tunnel_manager_remote_server *server, pa_device pa_log_debug(" Sample spec: %s", pa_sample_spec_snprint(sample_spec_str, sizeof(sample_spec_str), sample_spec)); pa_log_debug(" Channel map: %s", pa_channel_map_snprint(channel_map_str, sizeof(channel_map_str), channel_map)); pa_log_debug(" Is monitor: %s", pa_boolean_to_string(device->is_monitor)); + pa_log_debug(" Tunnel enabled: %s", pa_boolean_to_string(device->tunnel_enabled)); + + remote_device_apply_tunnel_enabled_policy(device); + + if (device->tunnel_enabled) { + const char *module_name; + char *args; + + switch (device->type) { + case PA_DEVICE_TYPE_SINK: + module_name = "module-tunnel-sink-new"; + break; + + case PA_DEVICE_TYPE_SOURCE: + module_name = "module-tunnel-source-new"; + break; + } + + args = pa_sprintf_malloc("server=%s " + "%s=%s " + "%s_name=tunnel_manager.%s.%s", + device->server->address, + device_type_to_string(device->type), device->name, + device_type_to_string(device->type), device->server->name, device->name); + device->tunnel_module = pa_module_load(device->server->manager->core, module_name, args); + pa_xfree(args); + + if (device->tunnel_module) + pa_hashmap_put(device->server->manager->remote_devices_by_module, device->tunnel_module, device); + } } static void remote_device_free(pa_tunnel_manager_remote_device *device) { @@ -570,6 +628,11 @@ static void remote_device_free(pa_tunnel_manager_remote_device *device) { pa_log_debug("[%s] Freeing remote device %s.", device->server->name, device->name); + if (device->tunnel_module) { + pa_hashmap_remove(device->server->manager->remote_devices_by_module, device->tunnel_module); + pa_module_unload(device->server->manager->core, device->tunnel_module, true); + } + pa_hashmap_remove(device->server->devices, device->name); pa_hook_fire(&device->hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_UNLINKED], NULL); @@ -602,6 +665,18 @@ static void remote_device_set_proplist(pa_tunnel_manager_remote_device *device, pa_hook_fire(&device->hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_PROPLIST_CHANGED], NULL); } +static void remote_device_set_tunnel_enabled(pa_tunnel_manager_remote_device *device, bool enabled) { + pa_assert(device); + + if (enabled == device->tunnel_enabled) + return; + + device->tunnel_enabled = enabled; + + pa_log_debug("[%s %s] Tunnel enabled changed from %s to %s.", device->server->name, device->name, + pa_boolean_to_string(!enabled), pa_boolean_to_string(enabled)); +} + static void remote_device_get_info_cb(pa_context *context, const void *info, int is_last, void *userdata) { pa_tunnel_manager_remote_device *device = userdata; pa_proplist *proplist = NULL; @@ -674,6 +749,12 @@ static void remote_device_update(pa_tunnel_manager_remote_device *device) { } } +static void remote_device_apply_tunnel_enabled_policy(pa_tunnel_manager_remote_device *device) { + pa_assert(device); + + remote_device_set_tunnel_enabled(device, !device->is_monitor); +} + static void device_stub_get_info_cb(pa_context *context, const void *info, int is_last, void *userdata) { struct device_stub *stub = userdata; uint32_t idx = PA_INVALID_INDEX; diff --git a/src/modules/tunnel-manager/tunnel-manager.h b/src/modules/tunnel-manager/tunnel-manager.h index 9775fd1..cd790b5 100644 --- a/src/modules/tunnel-manager/tunnel-manager.h +++ b/src/modules/tunnel-manager/tunnel-manager.h @@ -32,9 +32,11 @@ typedef struct pa_tunnel_manager_remote_device pa_tunnel_manager_remote_device; struct pa_tunnel_manager { pa_core *core; + pa_hashmap *remote_devices_by_module; /* pa_module -> pa_tunnel_manager_remote_device */ pa_hashmap *remote_servers; /* name -> pa_tunnel_manager_remote_server */ unsigned refcnt; + pa_hook_slot *module_unload_slot; }; /* If ref is true, the reference count of the manager is incremented, and also @@ -73,9 +75,11 @@ struct pa_tunnel_manager_remote_device { pa_sample_spec sample_spec; pa_channel_map channel_map; bool is_monitor; + bool tunnel_enabled; pa_hook hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_MAX]; pa_operation *get_info_operation; + pa_module *tunnel_module; /* These are a workaround for the problem that the introspection API's info * callbacks are called multiple times, which means that if the userdata -- 1.9.3