Pulse Hooks mechanism

PulseAudio is a huge project, and a lot of what it does is abstracted through the use of modules. To provide an interface for a wide array of modules, a dynamic hooks mechanism is inserted in differet areas of the code. You can get your modules code called in different situations like when a new sink is created or removed, when a new source is created or removed, when a client connects or disconnects to the server, etc.

All of these hooks are listed in the pa_core_hook enum at core.h:

typedef enum pa_core_hook {
    PA_CORE_HOOK_SINK_NEW,
    PA_CORE_HOOK_SINK_FIXATE,
    PA_CORE_HOOK_SINK_PUT,
    ...,
    PA_CORE_HOOK_SOURCE_NEW,
    PA_CORE_HOOK_SOURCE_FIXATE,
    PA_CORE_HOOK_SOURCE_PUT,
    ...
    PA_CORE_HOOK_SINK_INPUT_NEW,
    PA_CORE_HOOK_SINK_INPUT_FIXATE,
    PA_CORE_HOOK_SINK_INPUT_PUT,
    ...
    PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
    PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE,
    PA_CORE_HOOK_SOURCE_OUTPUT_PUT,
    ...
    PA_CORE_HOOK_CLIENT_NEW,
    PA_CORE_HOOK_CLIENT_PUT,
    PA_CORE_HOOK_CLIENT_UNLINK,
    ...
    PA_CORE_HOOK_CARD_NEW,
    PA_CORE_HOOK_CARD_PUT,
    PA_CORE_HOOK_CARD_UNLINK,
    ...
    PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
    PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED,
    PA_CORE_HOOK_DEFAULT_SINK_CHANGED,
    PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED,
    ...
    PA_CORE_HOOK_MODULE_NEW,
    PA_CORE_HOOK_MODULE_PROPLIST_CHANGED,
    PA_CORE_HOOK_MODULE_UNLINK,
    ...
    PA_CORE_HOOK_SAMPLE_CACHE_NEW,
    PA_CORE_HOOK_SAMPLE_CACHE_CHANGED,
    PA_CORE_HOOK_SAMPLE_CACHE_UNLINK,
} pa_core_hook_t;

In critical areas of the code, code registering with these hooks are then called. For example, when a new client is created, the respective hook is called as in the following manner, at client.c:

pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) {
    pa_client *c;

    pa_core_assert_ref(core);
    pa_assert(data);

    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0)
        return NULL;

    c = pa_xnew0(pa_client, 1);
    ...

    return c;
}

Registering your hook to be called in the appropriate time is also quite easy. To do it when a new client is created, you can simply do the following, as in module-augment-properties.c:


static pa_hook_result_t client_new_cb(pa_core *core, pa_client_new_data *data, struct userdata *u) {
    ...
    return process(u, data->proplist);
}

static pa_hook_result_t client_proplist_changed_cb(pa_core *core, pa_client *client, struct userdata *u) {
    ...
    return process(u, client->proplist);
}

int pa__init(pa_module *m) {
    struct userdata *u;
    ...
    u->client_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_CLIENT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) client_new_cb, u);
    u->client_proplist_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) client_proplist_changed_cb, u);
    ...
    return 0;
}

results matching ""

    No results matching ""