[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH 4/6] CDI/audio



From: Max Reitz <max@xxxxxxxxxx>

+ Header für CDI.audio hinzugefügt und Interface für die grundlegendsten
  Funktionen implementiert.

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 src/modules/cdi/include/cdi/audio.h |  419 +++++++++++++++++++++++++++++++++++
 src/modules/cdi/lib/audio.c         |  342 ++++++++++++++++++++++++++++
 src/modules/cdi/lib/cdi.c           |    7 +
 3 files changed, 768 insertions(+), 0 deletions(-)
 create mode 100644 src/modules/cdi/include/cdi/audio.h
 create mode 100644 src/modules/cdi/lib/audio.c

diff --git a/src/modules/cdi/include/cdi/audio.h b/src/modules/cdi/include/cdi/audio.h
new file mode 100644
index 0000000..c12d5d0
--- /dev/null
+++ b/src/modules/cdi/include/cdi/audio.h
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2010 Max Reitz
+ *
+ * This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
+ */
+
+/**
+ * \german
+ * Treiber für Soundkarten
+ * \endgerman
+ * \english
+ * Sound card drivers
+ * \endenglish
+ * \defgroup audio
+ */
+/*\@{*/
+
+#ifndef _CDI_AUDIO_H_
+#define _CDI_AUDIO_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "cdi.h"
+#include "cdi/lists.h"
+#include "cdi/mem.h"
+
+/**
+ * \german
+ * Mögliche Sampleformate (also Integer vorzeichenbehaftet/vorzeichenlos,
+ * Gleitkommazahlen, Größe eines Samples, ...).
+ * Wenn nicht anders gekennzeichnet, wird Little Endian verwendet.
+ * \endgerman
+ * \english
+ * Possible sample formats (i.e., signed/unsigned integer, floating point
+ * numbers, one sample's size, ...).
+ * Little endian is used, unless marked otherwise.
+ * \endenglish
+ */
+typedef enum {
+    // 16 bit signed integer
+    CDI_AUDIO_16SI = 0,
+    // 8 bit signed integer
+    CDI_AUDIO_8SI,
+    // 32 bit signed integer
+    CDI_AUDIO_32SI
+} cdi_audio_sample_format_t;
+
+/**
+ * \german
+ * Abspielposition eines Kanals. Enthält den Index des aktuellen Puffers und
+ * des aktuell abgespielten Frames.
+ * \endgerman
+ * \english
+ * A stream's playback position. Contains the index of both the current buffer
+ * and the frame being played.
+ * \endenglish
+ */
+typedef struct cdi_audio_position {
+    size_t buffer;
+    size_t frame;
+} cdi_audio_position_t;
+
+/**
+ * \german
+ * Status eines Kanals.
+ * \endgerman
+ * \english
+ * A stream's status.
+ * \endenglish
+ */
+typedef enum {
+    /**
+     * \german
+     * Angehalten
+     * \endgerman
+     * \english
+     * Stopped
+     * \endenglish
+     */
+    CDI_AUDIO_STOP = 0,
+    /**
+     * \german
+     * Entweder abspielen oder aufnehmen, je nach Typ.
+     * \endgerman
+     * \english
+     * According to the device type either playing or recording.
+     * \endenglish
+     */
+    CDI_AUDIO_PLAY = 1
+} cdi_audio_status_t;
+
+/**
+ * \german
+ * Beschreibt ein CDI.audio-Gerät, also Tonabspiel- oder Aufnahmehardware.
+ * Bietet eine Soundkarte beide Funktionen an, so muss sie in zwei CDI.audio-
+ * Geräte aufgeteilt werden.
+ * \endgerman
+ * \english
+ * Describes a CDI.audio device, i.e. a playback or recording device. If a
+ * sound card provides both functions, the driver must register one CDI.audio
+ * device per function.
+ * \endenglish
+ */
+struct cdi_audio_device {
+    struct cdi_device dev;
+
+    /**
+     * \german
+     * Ist dieser Wert ungleich 0, so handelt es sich um ein Aufnahmegerät,
+     * es kann nur gelesen werden. Ist er 0, dann können nur Töne abgespielt
+     * werden.
+     * \endgerman
+     * \english
+     * If this value is not 0, this device is a recording device, thus one can
+     * only read data. Otherwise, only play back is possible.
+     * \endenglish
+     */
+    int record;
+
+    /**
+     * \german
+     * Abspielgeräte können mehrere logische Kanäle anbieten, die vom Gerät
+     * zusammengemixt werden. Ist dem nicht der Fall oder handelt es sich um
+     * ein Aufnahmegerät, dann ist die Größe dieser Liste genau 1. Sie enthält
+     * Elemente des Typs struct cdi_audio_stream.
+     * \endgerman
+     * \english
+     * Play back devices may provide several logical streams which are mixed by
+     * the device. If this is either not true or it is a recording device, the
+     * list's size is exactly 1. It contains elements of type
+     * struct cdi_audio_stream.
+     * \endenglish
+     */
+    cdi_list_t streams;
+};
+
+/**
+ * \german
+ * Beschreibt einen Kanal eines CDI.audio-Geräts.
+ * Jeder Kanal besteht aus einer Reihe von Puffern mit abzuspielenden Samples,
+ * die hintereinander und in einer Schleife abgespielt werden.
+ * \endgerman
+ * \english
+ * Describes a CDI.audio device's stream.
+ * Each stream consists of a set of buffers containing samples being played
+ * consecutively and as a loop.
+ * \endenglish
+ */
+struct cdi_audio_stream {
+    /**
+     * \german
+     * Gerät, zu dem dieser Kanal gehört.
+     * \endgerman
+     * \english
+     * Device to which this stream belongs.
+     * \endenglish
+     */
+    struct cdi_audio_device* device;
+
+    /**
+     * \german
+     * Gibt die Anzahl der verfügbaren Datenpuffer an.
+     * \endgerman
+     * \english
+     * Contains the number of available data buffers.
+     * \endenglish
+     */
+    size_t num_buffers;
+
+    /**
+     * \german
+     * Gibt die Anzahl von Samples pro Datenpuffer an.
+     * \endgerman
+     * \english
+     * Contains the number of samples per buffer.
+     * \endenglish
+     */
+    size_t buffer_size;
+
+    /**
+     * \german
+     * Bei 0 kann die Samplerate eingestellt werden. Ansonsten kann sie nicht
+     * verändert werden und hat einen festen (hier angegebenen) Wert (in Hz).
+     * \endgerman
+     * \english
+     * If 0, the sample rate is adjustable. Otherwise, it isn't and is set to
+     * a fixed value in Hz (which is given here).
+     * \endenglish
+     */
+    int fixed_sample_rate;
+
+    /**
+     * \german
+     * Format der Samples in den Puffern.
+     * \endgerman
+     * \english
+     * Format of the samples contained in the buffers.
+     * \endenglish
+     */
+    cdi_audio_sample_format_t sample_format;
+};
+
+struct cdi_audio_driver {
+    struct cdi_driver drv;
+
+    /**
+     * \german
+     *
+     * Überträgt Daten von oder zu einem Puffer eines Geräts (bei
+     * Aufnahmegeräten wird empfangen, sonst gesendet). Es werden so viele
+     * Bytes übertragen, wie in den Puffer passen (abhängig von Sampleformat und
+     * Anzahl der Samples pro Puffer).
+     *
+     * @param stream Kanal, der angesprochen werden soll.
+     * @param buffer Der dort zu verwendende Puffer.
+     * @param memory Speicher, mit dem die Daten ausgetauscht werden sollen.
+     * @param offset Offset im Puffer (in Samples), an den die Daten kopiert
+     *               werden (es wird nur so viel kopiert, bis das Ende des
+     *               Puffers erreicht wird), wird bei Aufnahmegeräten ignoriert.
+     *
+     * @return 0 bei Erfolg, -1 im Fehlerfall.
+     *
+     * \endgerman
+     * \english
+     *
+     * Sends or receives data to/from a device's buffer (receives from recording
+     * devices, sends otherwise). The amount of data transmitted equals the
+     * buffer's size (depends on the sample format and the number of samples per
+     * buffer) reduced by the offset.
+     *
+     * @param stream Stream to be used.
+     * @param buffer Buffer to be used.
+     * @param memory Memory buffer being either source or destination.
+     * @param offset The content from memory is copied to the buffer respecting
+     *               this offset (in samples) in the buffer. Thus, the data is
+     *               copied to this offset until the end of the buffer has been
+     *               reached (recording devices ignore this).
+     *
+     * @return 0 on success, -1 on error.
+     *
+     * \endenglish
+     */
+    int (*transfer_data)(struct cdi_audio_stream* stream, size_t buffer,
+        struct cdi_mem_area* memory, size_t offset);
+
+    /**
+     * \german
+     *
+     * Hält ein CDI.audio-Gerät an oder lässt es aufnehmen bzw. abspielen. Wird
+     * es angehalten, so wird die Position automatisch auf den Anfang des ersten
+     * Puffers gesetzt.
+     *
+     * @param device Das Gerät
+     * @param status Zu setzender Status.
+     *
+     * @return Tatsächlicher neuer Status.
+     *
+     * \endgerman
+     * \english
+     *
+     * Stops a CDI.audio device or makes it record or play, respectively. If it
+     * is stopped, its position is automatically set to the beginning of the
+     * first buffer.
+     *
+     * @param device The device
+     * @param status Status to be set.
+     *
+     * @return Actual new status.
+     *
+     * \endenglish
+     */
+    cdi_audio_status_t (*change_device_status)(struct cdi_audio_device* device,
+        cdi_audio_status_t status);
+
+    /**
+     * \german
+     *
+     * Setzt die Lautstärke eines Kanals.
+     *
+     * @param volume 0x00 ist stumm, 0xFF ist volle Lautstärke.
+     *
+     * \endgerman
+     * \english
+     *
+     * Sets a stream's volume.
+     *
+     * @param volume 0x00 is mute, 0xFF is full volume.
+     *
+     * \endenglish
+     */
+    void (*set_volume)(struct cdi_audio_stream* stream, uint8_t volume);
+
+    /**
+     * \german
+     *
+     * Verändert die Samplerate eines Kanals.
+     *
+     * @param stream Anzupassender Kanal.
+     * @param sample_rate Neue Samplerate, ist der Wert nichtpositiv, dann wird
+     *                    die aktuelle Samplerate nicht verändert.
+     *
+     * @return Gibt die tatsächliche neue Samplerate zurück (kann vom Parameter
+     *         abweichen und wird es bei nichtpositivem auch).
+     *
+     * \endgerman
+     * \english
+     *
+     * Changes a stream's sample rate.
+     *
+     * @param stream Stream to be adjusted.
+     * @param sample_rate New sample rate, if nonpositive, the current sample
+     *                    rate won't be changed.
+     *
+     * @return Returns the actual new sample rate (may differ from the parameter
+     *         and will, if the latter was nonpositive).
+     *
+     * \endenglish
+     */
+    int (*set_sample_rate)(struct cdi_audio_stream* stream, int sample_rate);
+
+    /**
+     * \german
+     *
+     * Gibt die aktuelle Abspiel-/Aufnahmeposition des Kanals zurück.
+     *
+     * @param stream Abzufragender Kanal.
+     * @param position Zeiger zu einer Struktur, die den Index des aktuellen
+     *                 Puffers und des derzeit abgespielten Frames empfängt.
+     *
+     * \endgerman
+     * \english
+     *
+     * Returns the stream's current playback/recording position.
+     *
+     * @param stream Stream to be queried.
+     * @param position Pointer to a structure receiving the index of both the
+     *                 current buffer and the frame played right now.
+     *
+     * \endenglish
+     */
+    void (*get_position)(struct cdi_audio_stream* stream,
+        cdi_audio_position_t* position);
+
+    /**
+     * \german
+     *
+     * Verändert die Anzahl der von einem CDI.audio-Gerät verwendeten Channel
+     * (da dies die Größe der Frames verändert, kann auch die Anzahl der
+     * tatsächlich verwendeten Samples in einem Puffer verändert werden:
+     * Beträgt diese Maximalzahl z. B. 0xFFFF, dann können bei zwei Channeln
+     * nur 0xFFFE Samples verwendet werden (da es keine halben Frames gibt)).
+     *
+     * @param dev CDI.audio-Gerät
+     * @param channels Anzahl der zu verwendenden Channels (bei ungültigem Wert
+     *                 wird am Gerät nichts verändert).
+     *
+     * @return Jetzt tatsächlich benutzte Channelanzahl.
+     *
+     * \endgerman
+     * \english
+     *
+     * Changes the number of channels used by a CDI.audio device (this changes
+     * the frames' size, hence the number of actually used samples per buffer
+     * may be changed, too: If this size equals e.g. 0xFFFF, only 0xFFFE samples
+     * are used when working with two channels (because there is no half of a
+     * frame)).
+     *
+     * @param dev CDI.audio device
+     * @param channels Number of channels to be used (if invalid, nothing will
+     *                 be changed).
+     *
+     * @return Actually used number of channels now.
+     *
+     * \endenglish
+     */
+    int (*set_number_of_channels)(struct cdi_audio_device* dev, int channels);
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \german
+ *
+ * Wird vom Treiber aufgerufen, wenn die Bearbeitung eines Puffers abgeschlossen
+ * wurde (komplett abgespielt oder aufgenommen). Darf auch aus einer ISR heraus
+ * aufgerufen werden.
+ *
+ * @param stream Kanal, den es betrifft.
+ * @param buffer Pufferindex, der bearbeitet wurde.
+ *
+ * \endgerman
+ * \english
+ *
+ * Is called by a driver when having completed a buffer (i.e., completely played
+ * or recorded). May be called by an ISR.
+ *
+ * @param stream Stream being concerned.
+ * @param buffer Index of the completed buffer.
+ *
+ * \endenglish
+ */
+void cdi_audio_buffer_completed(struct cdi_audio_stream* stream, size_t buffer);
+
+#ifdef __cplusplus
+}; // extern "C"
+#endif
+
+#endif
+
+/*\@}*/
+
diff --git a/src/modules/cdi/lib/audio.c b/src/modules/cdi/lib/audio.c
new file mode 100644
index 0000000..7618c42
--- /dev/null
+++ b/src/modules/cdi/lib/audio.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2010 Max Reitz
+ *
+ * This program is free software. It comes without any warranty, to
+ * the extent permitted by applicable law. You can redistribute it
+ * and/or modify it under the terms of the Do What The Fuck You Want
+ * To Public License, Version 2, as published by Sam Hocevar. See
+ * http://sam.zoy.org/projects/COPYING.WTFPL for more details.
+ */
+
+#include <init.h>
+#include <rpc.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <sys/types.h>
+
+#include "cdi.h"
+#include "cdi/audio.h"
+#include "cdi/lists.h"
+#include "cdi/mem.h"
+
+static pid_t current_mixer = 0;
+static struct cdi_audio_driver* adriver = NULL;
+
+#define RPC(name) \
+    static void name(pid_t src, uint32_t corr_id, size_t length, void* data)
+
+#define rpc_int_resp(val) rpc_send_int_response(src, corr_id, val)
+
+static size_t sample_size[] = {
+    2, // CDI_AUDIO_16SI
+    1, // CDI_AUDIO_8SI
+    4  // CDI_AUDIO_32SI
+};
+
+RPC(register_mixer);
+RPC(number_of_devices);
+RPC(is_playback_device);
+RPC(change_device_status);
+RPC(transfer_data);
+RPC(stream_info);
+RPC(set_sample_rate);
+RPC(set_number_of_channels);
+RPC(get_current_frame);
+
+void cdi_audio_driver_register(struct cdi_audio_driver* driver)
+{
+    if (adriver != NULL) {
+        return;
+    }
+
+    adriver = driver;
+
+    // Die Registrierung bei init machen schon andere Teile der CDI-Lib
+
+    register_message_handler("REG", &register_mixer);
+    register_message_handler("NUMODEV", &number_of_devices);
+    register_message_handler("ISPLYBK", &is_playback_device);
+    register_message_handler("CHGSTAT", &change_device_status);
+    register_message_handler("TFRDATA", &transfer_data);
+    register_message_handler("STRINFO", &stream_info);
+    register_message_handler("SSPRATE", &set_sample_rate);
+    register_message_handler("SETCHAN", &set_number_of_channels);
+    register_message_handler("GTFRAME", &get_current_frame);
+}
+
+/**
+ * Ein Mixer registriert sich bei diesem Treiber oder meldet sich ab.
+ */
+RPC(register_mixer)
+{
+    // Es kann immer nur ein Mixer einen Treiber ansteuern
+    if ((length != sizeof(int)) || (current_mixer && (current_mixer != src))) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    if (current_mixer) {
+        if (!*(int*) data) {
+            // Mixer abmelden
+            current_mixer = 0;
+            rpc_int_resp(1);
+        } else {
+            // Anmeldung bereits erfolgt, noch mal geht nicht
+            rpc_int_resp(0);
+        }
+        return;
+    } else if (*(int*) data != 1) {
+        // Anmeldung noch nicht erfolgt, Abmeldung geht daher nicht
+        rpc_int_resp(0);
+        return;
+    }
+
+    // Mixer anmelden
+    current_mixer = src;
+    rpc_int_resp(1);
+}
+
+/**
+ * Gibt die Anzahl der verfügbaren Soundkarten zurück
+ */
+RPC(number_of_devices)
+{
+    if (src != current_mixer) {
+        rpc_int_resp(0);
+    } else {
+        rpc_int_resp(cdi_list_size(adriver->drv.devices));
+    }
+}
+
+/**
+ * Gibt 1 zurück, wenn der angegebene Index für ein Abspielgerät steht, bei
+ * einem Aufnahmegerät wird 0 und im Fehlerfall -1 zurückgegeben.
+ */
+RPC(is_playback_device)
+{
+    if ((src != current_mixer) || (length < sizeof(int))) {
+        rpc_int_resp(-1);
+        return;
+    }
+
+    struct cdi_audio_device* dev =
+        cdi_list_get(adriver->drv.devices, ((int*) data)[0]);
+
+    rpc_int_resp(!dev->record);
+}
+
+/**
+ * Verändert den Zustand des Geräts.
+ */
+RPC(change_device_status)
+{
+    if ((src != current_mixer) || (length < 2 * sizeof(int))) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_device* dev =
+        cdi_list_get(adriver->drv.devices, ((int*) data)[0]);
+
+    if (dev == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    rpc_int_resp(adriver->change_device_status(dev, ((int*) data)[1]));
+}
+
+/**
+ * Überträgt Daten von oder zu einem Stream (per SHM).
+ */
+RPC(transfer_data)
+{
+    struct {
+        int card, stream, buffer;
+        size_t offset, shm_size;
+        uint32_t shm;
+    } __attribute__((packed))* tfrd = data;
+
+    if ((src != current_mixer) || (length < sizeof(*tfrd))) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_device* dev =
+        cdi_list_get(adriver->drv.devices, tfrd->card);
+
+    if (dev == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_stream* str =
+        cdi_list_get(dev->streams, tfrd->stream);
+
+    if (str == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    size_t ssize;
+
+    switch (str->sample_format) {
+        case CDI_AUDIO_8SI:
+        case CDI_AUDIO_16SI:
+        case CDI_AUDIO_32SI:
+            ssize = sample_size[str->sample_format];
+            break;
+        default:
+            rpc_int_resp(0);
+            return;
+    }
+
+    size_t size =
+        (str->buffer_size - (dev->record ? 0 : tfrd->offset)) * ssize;
+
+    // Größe des SHM ist nicht ausreichend
+    if (tfrd->shm_size < size) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    void* shm = open_shared_memory(tfrd->shm);
+
+    // CDI-mem-area-Struktur erstellen, mit der der Treiber dann arbeitet
+    struct cdi_mem_area* buffer = calloc(1, sizeof(*buffer));
+    buffer->vaddr = shm;
+    buffer->size  = size;
+
+    int ret = adriver->transfer_data(str, tfrd->buffer, buffer, tfrd->offset);
+
+    free(buffer);
+
+    close_shared_memory(tfrd->shm);
+
+    rpc_int_resp(!ret);
+}
+
+/**
+ * Gibt Informationen über einen Stream zurück (also die cdi_audio_stream-
+ * Struktur).
+ */
+RPC(stream_info)
+{
+    char dummy = 0;
+
+    if ((src != current_mixer) || (length < 2 * sizeof(int))) {
+        rpc_send_response(src, corr_id, 1, &dummy);
+        return;
+    }
+
+    struct cdi_audio_device* dev =
+        cdi_list_get(adriver->drv.devices, ((int*) data)[0]);
+
+    if (dev == NULL) {
+        rpc_send_response(src, corr_id, 1, &dummy);
+        return;
+    }
+
+    struct cdi_audio_stream* str = cdi_list_get(dev->streams, ((int*) data)[1]);
+
+    if (str == NULL) {
+        rpc_send_response(src, corr_id, 1, &dummy);
+        return;
+    }
+
+    rpc_send_response(src, corr_id, sizeof(*str), (char*) str);
+}
+
+/**
+ * Setzt die Samplerate eines Streams.
+ */
+RPC(set_sample_rate)
+{
+    if ((src != current_mixer) || (length < 3 * sizeof(int))) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_device* dev =
+        cdi_list_get(adriver->drv.devices, ((int*) data)[0]);
+
+    if (dev == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_stream* str = cdi_list_get(dev->streams, ((int*) data)[1]);
+
+    if (str == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    rpc_int_resp(adriver->set_sample_rate(str, ((int*) data)[2]));
+}
+
+/**
+ * Legt die Anzahl der Channels einer Soundkarte fest.
+ */
+RPC(set_number_of_channels)
+{
+    if ((src != current_mixer) || (length < 2 * sizeof(int))) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_device* dev =
+        cdi_list_get(adriver->drv.devices, ((int*) data)[0]);
+
+    if (dev == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    rpc_int_resp(adriver->set_number_of_channels(dev, ((int*) data)[1]));
+}
+
+/**
+ * Gibt den Index des aktuell abgespielten Frames im aktuellen Puffer zurück.
+ */
+RPC(get_current_frame)
+{
+    if ((src != current_mixer) || (length < 2 * sizeof(int))) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_device* dev =
+        cdi_list_get(adriver->drv.devices, ((int*) data)[0]);
+
+    if (dev == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    struct cdi_audio_stream* str = cdi_list_get(dev->streams, ((int*) data)[1]);
+
+    if (str == NULL) {
+        rpc_int_resp(0);
+        return;
+    }
+
+    cdi_audio_position_t pos;
+    adriver->get_position(str, &pos);
+
+    rpc_int_resp(pos.frame);
+}
+
+/**
+ * Wird vom Soundkartentreiber aufgerufen, wenn die Bearbeitung eines Puffers
+ * abgeschlossen wurde.
+ */
+void cdi_audio_buffer_completed(struct cdi_audio_stream* stream, size_t buffer)
+{
+    if (current_mixer) {
+        rpc_get_int(current_mixer, "BUFCOM", sizeof(buffer), (char*) &buffer);
+    }
+}
+
diff --git a/src/modules/cdi/lib/cdi.c b/src/modules/cdi/lib/cdi.c
index 0d634d7..3502c2b 100644
--- a/src/modules/cdi/lib/cdi.c
+++ b/src/modules/cdi/lib/cdi.c
@@ -17,10 +17,13 @@
 #include <rpc.h>
 
 #include "cdi.h"
+#include "cdi/audio.h"
 #include "cdi/fs.h"
 #include "cdi/pci.h"
 #include "cdi/storage.h"
 
+extern void cdi_audio_driver_register(struct cdi_audio_driver* driver);
+
 static list_t* drivers = NULL;
 
 static void cdi_tyndur_run_drivers(void);
@@ -210,6 +213,10 @@ void cdi_driver_register(struct cdi_driver* driver)
             cdi_fs_driver_register((struct cdi_fs_driver*) driver);
             break;
 
+        case CDI_AUDIO:
+            cdi_audio_driver_register((struct cdi_audio_driver*) driver);
+            break;
+
         default:
             break;
     }
-- 
1.7.1