pactl should allow unloading modules by name. pactl and the native protocol were expanded to handle names while unloading modules. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=48289 --- src/map-file | 3 ++- src/pulse/introspect.c | 46 +++++++++++++++++++++++++++++++++++++-- src/pulse/introspect.h | 8 +++++-- src/pulsecore/protocol-native.c | 29 ++++++++++++++++++++---- src/utils/pactl.c | 13 ++++++++--- 5 files changed, 87 insertions(+), 12 deletions(-) diff --git a/src/map-file b/src/map-file index 69cf25b..82fdd06 100644 --- a/src/map-file +++ b/src/map-file @@ -113,7 +113,8 @@ pa_context_suspend_sink_by_index; pa_context_suspend_sink_by_name; pa_context_suspend_source_by_index; pa_context_suspend_source_by_name; -pa_context_unload_module; +pa_context_unload_module_by_index; +pa_context_unload_module_by_name; pa_context_unref; pa_cvolume_avg; pa_cvolume_avg_mask; diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c index 38a9d1c..332733b 100644 --- a/src/pulse/introspect.c +++ b/src/pulse/introspect.c @@ -1864,8 +1864,50 @@ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char return o; } -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); +pa_operation* pa_context_unload_module_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_UNLOAD_MODULE, &tag); + pa_tagstruct_putu32(t, idx); + pa_tagstruct_puts(t, NULL); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; +} + +pa_operation* pa_context_unload_module_by_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { + pa_operation *o; + pa_tagstruct *t; + uint32_t tag; + + pa_assert(c); + pa_assert(PA_REFCNT_VALUE(c) >= 1); + + PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); + PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); + PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); + + o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); + + t = pa_tagstruct_command(c, PA_COMMAND_UNLOAD_MODULE, &tag); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); + + return o; } /*** Autoload stuff ***/ diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h index 0072f5d..f80fb86 100644 --- a/src/pulse/introspect.h +++ b/src/pulse/introspect.h @@ -409,8 +409,12 @@ typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdat /** Load a module. */ pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); -/** Unload a module. */ -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); +/** Unload a module by its index. */ +pa_operation* pa_context_unload_module_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); + + +/** Unload a module by its name. */ +pa_operation* pa_context_unload_module_by_name(pa_context *c, const char*name, pa_context_success_cb_t cb, void *userdata); /** @} */ diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 396e143..56722e4 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -4434,23 +4434,44 @@ static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; + const char *name; pa_module *m; pa_native_connection_assert_ref(c); pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - m = pa_idxset_get_by_index(c->protocol->core->modules, idx); - CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); - pa_module_unload_request(m, FALSE); - pa_pstream_send_simple_ack(c->pstream, tag); + if (idx != PA_INVALID_INDEX) { + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); + + m = pa_idxset_get_by_index(c->protocol->core->modules, idx); + + CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); + + pa_module_unload_request(m, FALSE); + pa_pstream_send_simple_ack(c->pstream, tag); + } + else { + CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID); + + /* Traverse the module list and unload all modules with the matching name */ + for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx)) { + if (strcmp(name, m->name) == 0) { + CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); + + pa_module_unload_request(m, FALSE); + pa_pstream_send_simple_ack(c->pstream, tag); + } + } + } } static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 05a1519..b1f72f8 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -32,6 +32,7 @@ #include <stdlib.h> #include <getopt.h> #include <locale.h> +#include <ctype.h> #include <sndfile.h> @@ -1152,7 +1153,10 @@ static void context_state_callback(pa_context *c, void *userdata) { break; case UNLOAD_MODULE: - pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL)); + if (module_name) + pa_operation_unref(pa_context_unload_module_by_name(c, module_name, simple_callback, NULL)); + else + pa_operation_unref(pa_context_unload_module_by_index(c, module_index, simple_callback, NULL)); break; case SUSPEND_SINK: @@ -1345,7 +1349,7 @@ static void help(const char *argv0) { printf("%s %s %s %s\n", argv0, _("[options]"), "play-sample ", _("NAME [SINK]")); printf("%s %s %s %s\n", argv0, _("[options]"), "remove-sample ", _("NAME")); printf("%s %s %s %s\n", argv0, _("[options]"), "load-module ", _("NAME [ARGS ...]")); - printf("%s %s %s %s\n", argv0, _("[options]"), "unload-module ", _("#N")); + printf("%s %s %s %s\n", argv0, _("[options]"), "unload-module ", _("NAME|#N")); printf("%s %s %s %s\n", argv0, _("[options]"), "move-(sink-input|source-output)", _("#N SINK|SOURCE")); printf("%s %s %s %s\n", argv0, _("[options]"), "suspend-(sink|source)", _("NAME|#N 1|0")); printf("%s %s %s %s\n", argv0, _("[options]"), "set-card-profile ", _("CARD PROFILE")); @@ -1572,7 +1576,10 @@ int main(int argc, char *argv[]) { goto quit; } - module_index = (uint32_t) atoi(argv[optind+1]); + if (isdigit(argv[optind+1][0])) + module_index = (uint32_t) atoi(argv[optind+1]); + else + module_name = argv[optind+1]; } else if (pa_streq(argv[optind], "suspend-sink")) { action = SUSPEND_SINK; -- 1.7.10.2