Client to server communication

Basic application code:

#include <stdio.h>
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/def.h>

/* Raw audio in PCM format */
static unsigned char raw_audio[] = {
    0x38, 0x08, 0x30, 0xf0, 0xfa, 0x08, 0xf6, 0xf1, 0x23, 0x0c, 0xe5, 0xf2,
};

static const pa_sample_spec ss = {
    .format = PA_SAMPLE_S16LE,
    .rate = 44100,
    .channels = 2
};

static char *application_name = "Name: Test application";
static char *stream_name = "Stream Name: Test application [test song name]";

int main(int argc, char **argv)
{
    static pa_simple *pa_dev = NULL;
    int pa_error, ret;

    pa_dev = pa_simple_new(
                   NULL,        /* server */
                   application_name,
                   PA_STREAM_PLAYBACK,
                   NULL,        /* sink name, NULL for default*/
                   stream_name,
                   &ss,         /* sample type to use */
                   NULL,        /* channel map to use */
                   NULL,        /* buffering attributes */
                   &pa_error    /* where error codes are stored */);
    if (!pa_dev) {
        fprintf(stderr, "Could not connect to PA server: %s\n",
            pa_strerror(pa_error));
        return -1;
    }

    while (1) {
        ret = pa_simple_write(pa_dev, raw_audio,
                      sizeof(raw_audio), &pa_error);
        if (ret < 0) {
            fprintf(stderr, "pa_simple_write() failed: %s\n",
                pa_strerror(pa_error));
            return -1;
        }
    }

    return 0;
}

This is possibly the simplest application that can be written. When run, a light hissing sound will be produced from the speakers.

Client libraries - under the hood

To see what is happening under the hood, we will first enable PulseAudio client libraries while running the application:

$ PULSE_LOG=99 PULSE_LOG_COLORS= PULSE_LOG_FILE=  ./a.out 
[a.out] conf-parser.c: Parsing configuration file '/home/darwish/.pulse/client.conf'
[a.out] memblock.c: Using shared memory pool with 1024 slots of size 64.0 KiB each, total size is 64.0 MiB, maximum usable slot size is 65472
[a.out] context.c: Trying to connect to /run/user/1000/pulse/native...
[threaded-ml] context.c: SHM possible: yes
[threaded-ml] context.c: Protocol version: remote 30, local 30
[threaded-ml] context.c: Negotiated SHM: yes

And we can see that even though our application calls a very small number of PA client libraries APIs, these APIs does a lot of thing under the hood. First, the PA clients configuration file is read and parsed for configuration. The syntax of this file is documented in the pulse-client.conf(5) manpage.

Afterwards, the client library communicates with the server using a classical Unix domain socket (This is where systemd socket activation could come in). This socket usually exists at /run/user/$UID/pulse/native.

Then the client checks if enabling data transfer between the application and the PulseAudio daemon is doable using POSIX Shared Memory mechanisms. This is mostly how applications send audio data to the pulseAudio daemon.

If no PulseAudio daemon is running, the following output is shown instead:

$ PULSE_LOG=99 PULSE_LOG_COLORS= PULSE_LOG_FILE=  ./a.out 
[a.out] conf-parser.c: Parsing configuration file '/home/darwish/.pulse/client.conf'
[a.out] memblock.c: Using shared memory pool with 1024 slots of size 64.0 KiB each, total size is 64.0 MiB, maximum usable slot size is 65472
[a.out] context.c: Trying to connect to /run/user/1000/pulse/native...
[a.out] socket-client.c: connect(): No such file or directory (2)
[a.out] context.c: Trying to connect to /var/run/pulse/native...
[a.out] socket-client.c: connect(): No such file or directory (2)
Could not connect to PA server: Connection refused

Note that what happens is that the client library first tries to connect to the PulseAudio user instance. If no user instance exist (by virtue of having no user-unique PA socket), connecting to the system instance is tried. A system instance PA socket usually exists at $INSTALL_DIR/var/run/pulse/native. If even no PA system instance exist, the client library just gives up and return failure.

results matching ""

    No results matching ""