how pulse module are structured?

On my journey to a new module-tunnel I took a closer look into other modules. Pulseaudio got modules for event handling, got modules for os driver frameworks like alsa, oss, solaris. Also there a drivers to communicate over the local network. Starting with mod-native-protocol-tcp to allow remote pulseaudio connections, there is also support for esound, zeroconf, rtp or raop. Modify sound stream samples is also possible, take a look into the filters.

To write a hardware driver or network based driver I would recommend reading null-sink, raop-sink and esound-sink.

After looking around into several pulse modules. It is clear that most of the module which act as a sink have the following structure and nearby the same code beside from driver specific parts. :::c void thread_func() { / hard work / }

int pa__init(pa_module*m) {
    /* parse + validate + copy module arguments */
    pa_modargs_new(m->argument, valid_modargs)

    /* init driver specific */

    /* setup a real time poll */
    u->rtpoll = pa_rtpoll_new();

    /* setup a message queue */
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll
    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);

    /* create a thread */
    pa_thread_new("null-sink", thread_func, u)

    /* register sink */

int pa__done(pa_module*m) {
    /* deinit private structure + free everything */

All sink modules have a real time poll running in a seperated thread, often also caled I/O thread. This is because of [|the threading model]. In summary it says "don't block the mainloop and do the hard work within the I/O loop." Back to our thread, is has to do the real work of our module. It's dequeuing data from a sink buffer, mixing and adjusting volumes. This set of tasks is named rendering. It is done by pa_sink_render.

Syncronisation is done by message queues between mainloop and I/O loop named pa_thread_mq which has 2 pa_asyncmsgq one input queue for message to the thread and one output queue from thread to the mainloop. rtpoll is not as powerfull a mainloop is, but you can register at least a filehandler packed within rt_poll_item. When you write a network protocol this will be your socket.