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 */
pa_sink_put(u->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 [http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/Developer/Threading/|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.