]> git.alsa-project.org Git - alsa-plugins.git/commitdiff
Alsa support for Maemo SDK (n770): External PCM IO plugin
authorEduardo Valentin <eduardo.valentin@indt.org.br>
Mon, 6 Nov 2006 13:31:31 +0000 (14:31 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 6 Nov 2006 13:31:31 +0000 (14:31 +0100)
This patch file adds an ALSA External PCM I/O plugin. This source uses
the dsp-protocol
implementation.

The plugin probes for a free communication channel at the start time.
It will probe only
for channels specified into the configuration file for the plugin. An
configuration example is:
# PCM
       pcm.!default {
               type alsa_dsp
               playback_device_file ["/dev/dsptask/pcm2"]
               recording_device_file ["/dev/dsptask/pcm_rec"]
       }

The plugin supports the following:

    *  Playback:
          o 16-bit PCM formats:
                + S16_LE
                + S16_BE
                + U16_LE
                + U16_BE
          o 8-bit PCM formats:
                + A_LAW
                + MU_LAW
                + U8
                + S8
          o Rates:
                + 8 KHz
                + 11.025 KHz
                + 12 KHz
                + 16 KHz
                + 22.050 KHz
                + 24 KHz
                + 32 KHz
                + 44.1 KHz
                + 48 KHz
          o Channels:
                + Mono
                + Stereo
    * Recording:
          o 16-bit PCM formats:
                + S16_LE
          o 8-bit PCM formats:
                + A_LAW
                + MU_LAW
          o Rates:
                + 8 KHz
          o Channels
                + Mono

Signed-off-by: Eduardo Valentin <eduardo.valentin@indt.org.br>
maemo/alsa-dsp.c [new file with mode: 0644]

diff --git a/maemo/alsa-dsp.c b/maemo/alsa-dsp.c
new file mode 100644 (file)
index 0000000..f23741c
--- /dev/null
@@ -0,0 +1,772 @@
+/**
+ * @file alsa-dsp.c
+ * @brief Alsa External plugin: I/O plugin
+ * <p>
+ * Copyright (C) 2006 Nokia Corporation
+ * <p>
+ * Contact: Eduardo Bezerra Valentin <eduardo.valentin@indt.org.br>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * */
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <alsa/asoundlib.h>
+#include <alsa/pcm_external.h>
+#include "list.h"
+#include "debug.h"
+#include "dsp-protocol.h"
+#include "constants.h"
+
+#define ARRAY_SIZE(ary)        (sizeof(ary)/sizeof(ary[0]))
+/** 
+ * Device node file name list.
+ */
+typedef struct {
+       char *device;
+       struct list_head list;
+} device_list_t;
+
+/** 
+ * Holds the need information: list of playback and recording devices,
+ * current format, sample_rate, bytes per frame and pointer to ring
+ * buffer.
+ */
+typedef struct snd_pcm_alsa_dsp {
+       snd_pcm_ioplug_t io;
+       dsp_protocol_t *dsp_protocol;
+       int format;
+       int sample_rate;
+       int bytes_per_frame;
+       snd_pcm_sframes_t hw_pointer;
+       device_list_t playback_devices;
+       device_list_t recording_devices;
+} snd_pcm_alsa_dsp_t;
+
+static snd_pcm_alsa_dsp_t *free_ref;
+/**
+ * @param io pcm io plugin configured to Alsa libs.
+ *
+ * It starts the playback sending a DSP_CMD_PLAY.
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_start(snd_pcm_ioplug_t * io)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       int ret;
+       DENTER();
+       DPRINT("IO_STREAM %d == SND_PCM_STREAM_PLAYBACK %d\n", io->stream,
+              io->stream == SND_PCM_STREAM_PLAYBACK);
+       if (io->stream != SND_PCM_STREAM_PLAYBACK)
+               dsp_protocol_set_mic_enabled(alsa_dsp->dsp_protocol, 1);
+       ret = dsp_protocol_send_play(alsa_dsp->dsp_protocol);
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ *
+ * It starts the playback sending a DSP_CMD_STOP.
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_stop(snd_pcm_ioplug_t * io)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       int ret;
+       DENTER();
+       ret = dsp_protocol_send_stop(alsa_dsp->dsp_protocol);
+       if (io->stream != SND_PCM_STREAM_PLAYBACK)
+               dsp_protocol_set_mic_enabled(alsa_dsp->dsp_protocol, 0);
+
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ *
+ * It returns the position of current period consuming.
+ *
+ * @return on success, returns current position, otherwise a negative
+ * error code.
+ */
+static snd_pcm_sframes_t alsa_dsp_pointer(snd_pcm_ioplug_t * io)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       snd_pcm_sframes_t ret;
+       DENTER();
+       ret = alsa_dsp->hw_pointer;
+       if (alsa_dsp->hw_pointer == 0)
+               alsa_dsp->hw_pointer =
+                   io->period_size * alsa_dsp->bytes_per_frame;
+       else
+               alsa_dsp->hw_pointer = 0;
+       DLEAVE((int)ret);
+       return ret;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ *
+ * It transfers the audio data to dsp side.
+ *
+ * @return on success, returns amount of data transfered,
+ * otherwise a negative error code.
+ */
+static snd_pcm_sframes_t alsa_dsp_transfer(snd_pcm_ioplug_t * io,
+                                          const snd_pcm_channel_area_t * areas,
+                                          snd_pcm_uframes_t offset,
+                                          snd_pcm_uframes_t size)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       DENTER();
+       char *buf;
+       int words;
+       ssize_t result;
+
+       words = size * alsa_dsp->bytes_per_frame;
+       words /= 2;
+       DPRINT("***** Info: words %d size %lu bpf: %d\n", words, size,
+              alsa_dsp->bytes_per_frame);
+       if (words > alsa_dsp->dsp_protocol->mmap_buffer_size) {
+               DERROR("Requested too much data transfer (playing only %d)\n",
+                      alsa_dsp->dsp_protocol->mmap_buffer_size);
+               words = alsa_dsp->dsp_protocol->mmap_buffer_size;
+       }
+       if (alsa_dsp->dsp_protocol->state != STATE_PLAYING) {
+               DPRINT("I did nothing - No start sent\n");
+               alsa_dsp_start(io);
+       }
+       /* we handle only an interleaved buffer */
+       buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8;
+       if (io->stream == SND_PCM_STREAM_PLAYBACK)
+               result =
+                   dsp_protocol_send_audio_data(alsa_dsp->dsp_protocol, buf,
+                                                words);
+       else
+               result =
+                   dsp_protocol_receive_audio_data(alsa_dsp->dsp_protocol, buf,
+                                                   words);
+       result *= 2;
+       result /= alsa_dsp->bytes_per_frame;
+      out:
+       alsa_dsp->hw_pointer += result;
+       DLEAVE(result);
+       return result;
+}
+
+/**
+ * @param device_list a list of device names to be freed.
+ *
+ * It passes a list of device names and frees each node.
+ *
+ * @return zero (success).
+ */
+static int free_device_list(device_list_t * device_list)
+{
+       struct list_head *pos, *q;
+       device_list_t *tmp;
+       list_for_each_safe(pos, q, &device_list->list) {
+               tmp = list_entry(pos, device_list_t, list);
+               list_del(pos);
+               free(tmp->device);
+               free(tmp);
+       }
+       return 0;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ *
+ * Closes the connection with the pcm dsp task. It
+ * destroies all allocated data. 
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_close(snd_pcm_ioplug_t * io)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       int ret = 0;
+       DENTER();
+       ret = dsp_protocol_close_node(alsa_dsp->dsp_protocol);
+       dsp_protocol_destroy(&(alsa_dsp->dsp_protocol));
+       free_device_list(&(alsa_dsp->playback_devices));
+       free_device_list(&(alsa_dsp->recording_devices));
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * @param map the values to be mapped
+ * @param value the search key
+ * @param steps how many keys should be checked 
+ *
+ * Maps a value to another. 
+ *
+ * @return on success, returns mapped value, otherwise a negative error code.
+ */
+static int map_value(int *map, int value, int steps)
+{
+       int i;
+       for (i = 0; i < steps; i++)
+               if (map[i * 2] == value)
+                       return map[i * 2 + 1];
+       return -1;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ * @param params 
+ *
+ * It checks if the pcm format and rate are supported. 
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_hw_params(snd_pcm_ioplug_t * io,
+                             snd_pcm_hw_params_t * params)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       int ret = 0;
+       int map_sample_rates[] = {
+               8000, SAMPLE_RATE_8KHZ,
+               11025, SAMPLE_RATE_11_025KHZ,
+               12000, SAMPLE_RATE_12KHZ,
+               16000, SAMPLE_RATE_16KHZ,
+               22050, SAMPLE_RATE_22_05KHZ,
+               24000, SAMPLE_RATE_24KHZ,
+               32000, SAMPLE_RATE_32KHZ,
+               44100, SAMPLE_RATE_44_1KHZ,
+               48000, SAMPLE_RATE_48KHZ
+       };
+       int map_formats[] = {
+               SND_PCM_FORMAT_A_LAW, DSP_AFMT_ALAW,
+               SND_PCM_FORMAT_MU_LAW, DSP_AFMT_ULAW,
+               SND_PCM_FORMAT_S16_LE, DSP_AFMT_S16_LE,
+               SND_PCM_FORMAT_U8, DSP_AFMT_U8,
+               SND_PCM_FORMAT_S8, DSP_AFMT_S8,
+               SND_PCM_FORMAT_S16_BE, DSP_AFMT_S16_BE,
+               SND_PCM_FORMAT_U16_LE, DSP_AFMT_U16_LE,
+               SND_PCM_FORMAT_U16_BE, DSP_AFMT_U16_BE
+       };
+       DENTER();
+       DPRINT("Checking Format- Ret %d\n", ret);
+       alsa_dsp->format = map_value(map_formats, io->format,
+                                    io->stream ==
+                                    SND_PCM_STREAM_PLAYBACK ?
+                                    ARRAY_SIZE(map_formats) : 3);
+       if (alsa_dsp->format < 0) {
+               DERROR("*** ALSA-DSP: unsupported format %s\n",
+                      snd_pcm_format_name(io->format));
+               ret = -EINVAL;
+       }
+       DPRINT("Format is Ok. Checking rate. Ret %d\n", ret);
+
+       alsa_dsp->sample_rate = map_value(map_sample_rates, io->rate,
+                                         io->stream ==
+                                         SND_PCM_STREAM_PLAYBACK ?
+                                         ARRAY_SIZE(map_sample_rates) : 1);
+       if (alsa_dsp->sample_rate < 0) {
+               ret = -EINVAL;
+               DERROR("** ALSA - DSP - Unsuported Sample Rate! **\n");
+       }
+       DPRINT("Rate is ok. Calculating WPF. Ret %d\n", ret);
+
+       alsa_dsp->bytes_per_frame =
+           ((snd_pcm_format_physical_width(io->format) * io->channels) / 8);
+       DPRINT("WPF: %d width %d channels %d\n", alsa_dsp->bytes_per_frame,
+              snd_pcm_format_physical_width(io->format), io->channels);
+
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ * 
+ * It sends the audio parameters to pcm task node (formats, channels, 
+ * access, rates). It is assumed that everything is proper set.
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_prepare(snd_pcm_ioplug_t * io)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       audio_params_data_t params;
+       speech_params_data_t sparams;
+       int ret = 0;
+       char *tmp;
+       DENTER();
+
+       alsa_dsp->hw_pointer = 0;
+       if (alsa_dsp->dsp_protocol->state != STATE_INITIALISED) {
+               tmp = strdup(alsa_dsp->dsp_protocol->device);
+               ret = dsp_protocol_close_node(alsa_dsp->dsp_protocol);
+               if (!ret)
+                       dsp_protocol_open_node(alsa_dsp->dsp_protocol, tmp);
+               free(tmp);
+       }
+       if (ret == 0) {
+               if (io->stream == SND_PCM_STREAM_PLAYBACK) {
+                       params.dsp_cmd = DSP_CMD_SET_PARAMS;
+                       params.dsp_audio_fmt = alsa_dsp->format;
+                       params.sample_rate = alsa_dsp->sample_rate;
+                       params.number_channels = io->channels;
+                       params.ds_stream_id = 0;
+                       params.stream_priority = 0;
+                       if (dsp_protocol_send_audio_params
+                           (alsa_dsp->dsp_protocol, &params) < 0) {
+                               ret = -EIO;
+                               DERROR("Error in send params data\n");
+                       } else
+                               DPRINT("Sending params data is ok\n");
+               } else {
+                       sparams.dsp_cmd = DSP_CMD_SET_SPEECH_PARAMS;
+                       sparams.audio_fmt = alsa_dsp->format;
+                       sparams.sample_rate = alsa_dsp->sample_rate;
+                       sparams.ds_stream_id = 0;
+                       sparams.stream_priority = 0;
+                       sparams.frame_size = io->period_size;
+                       DPRINT("frame size %u\n", sparams.frame_size);
+                       if (dsp_protocol_send_speech_params
+                           (alsa_dsp->dsp_protocol, &sparams) < 0) {
+                               ret = -EIO;
+                               DERROR("Error in send speech params data\n");
+                       } else
+                               DPRINT("Sending speech params data is ok\n");
+
+               }
+       }
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ *
+ * It pauses the playback sending a DSP_CMD_PAUSE.
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_pause(snd_pcm_ioplug_t * io, int enable)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       int ret;
+       DENTER();
+       ret = dsp_protocol_send_pause(alsa_dsp->dsp_protocol);
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * @param io the pcm io plugin we configured to Alsa libs.
+ *
+ * It starts the playback sending a DSP_CMD_PLAY.
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_resume(snd_pcm_ioplug_t * io)
+{
+       snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
+       int ret;
+       DENTER();
+       ret = dsp_protocol_send_play(alsa_dsp->dsp_protocol);
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * @param alsa_dsp the structure to be configured.
+ * 
+ * It configures constraints about formats, channels, access, rates, 
+ * periods and buffer size. It exports the supported constraints by the
+ * dsp task node to the alsa plugin library.
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_configure_constraints(snd_pcm_alsa_dsp_t * alsa_dsp)
+{
+       snd_pcm_ioplug_t *io = &alsa_dsp->io;
+       static snd_pcm_access_t access_list[] = {
+               SND_PCM_ACCESS_RW_INTERLEAVED
+       };
+       const unsigned int formats[] = {
+               SND_PCM_FORMAT_U8,      /* DSP_AFMT_U8 */
+               SND_PCM_FORMAT_S16_LE,  /* DSP_AFMT_S16_LE */
+               SND_PCM_FORMAT_S16_BE,  /* DSP_AFMT_S16_BE */
+               SND_PCM_FORMAT_S8,      /* DSP_AFMT_S8 */
+               SND_PCM_FORMAT_U16_LE,  /* DSP_AFMT_U16_LE */
+               SND_PCM_FORMAT_U16_BE,  /* DSP_AFMT_U16_BE */
+               SND_PCM_FORMAT_A_LAW,   /* DSP_AFMT_ALAW */
+               SND_PCM_FORMAT_MU_LAW   /* DSP_AFMT_ULAW */
+       };
+       const unsigned int formats_recor[] = {
+               SND_PCM_FORMAT_S16_LE,  /* DSP_AFMT_S16_LE */
+               SND_PCM_FORMAT_A_LAW,   /* DSP_AFMT_ALAW */
+               SND_PCM_FORMAT_MU_LAW   /* DSP_AFMT_ULAW */
+       };
+       static unsigned int bytes_list[] = {
+               1U << 11, 1U << 12
+       };
+       static unsigned int bytes_list_rec_8bit[] = {
+               /* It must be multiple of 80... less than or equal to 800 */
+               80, 160, 240, 320, 400, 480, 560, 640, 720, 800
+       };
+
+       int ret, err;
+       DENTER();
+       /* Configuring access */
+       if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
+                                                ARRAY_SIZE(access_list),
+                                                access_list)) < 0) {
+               ret = err;
+               goto out;
+       }
+       if (io->stream == SND_PCM_STREAM_PLAYBACK) {
+               /* Configuring formats */
+               if ((err =
+                    snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
+                                                  ARRAY_SIZE(formats),
+                                                  formats)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+               /* Configuring channels */
+               if ((err = 
+                    snd_pcm_ioplug_set_param_minmax(io,
+                                                    SND_PCM_IOPLUG_HW_CHANNELS,
+                                                    1, 2)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+
+               /* Configuring rates */
+               if ((err =
+                    snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
+                                                    8000, 48000)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+               /* Configuring periods */
+               if ((err = 
+                    snd_pcm_ioplug_set_param_list(io,
+                                                SND_PCM_IOPLUG_HW_PERIOD_BYTES,
+                                                ARRAY_SIZE(bytes_list),
+                                                bytes_list)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+               /* Configuring buffer size */
+               if ((err = 
+                    snd_pcm_ioplug_set_param_list(io,
+                                                SND_PCM_IOPLUG_HW_BUFFER_BYTES,
+                                                ARRAY_SIZE(bytes_list),
+                                                bytes_list)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+
+       } else {
+               /* Configuring formats */
+               if ((err =
+                    snd_pcm_ioplug_set_param_list(io, 
+                                                  SND_PCM_IOPLUG_HW_FORMAT,
+                                                  ARRAY_SIZE(formats_recor),
+                                                  formats_recor)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+               /* Configuring channels */
+               if ((err = snd_pcm_ioplug_set_param_minmax(io,
+                                                   SND_PCM_IOPLUG_HW_CHANNELS,
+                                                   1, 1)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+
+               /* Configuring rates */
+               if ((err =
+                    snd_pcm_ioplug_set_param_minmax(io, 
+                                                    SND_PCM_IOPLUG_HW_RATE,
+                                                    8000, 8000)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+               /* Configuring periods */
+               if ((err = 
+                    snd_pcm_ioplug_set_param_list(io, 
+                                               SND_PCM_IOPLUG_HW_PERIOD_BYTES,
+                                               ARRAY_SIZE
+                                               (bytes_list_rec_8bit),
+                                               bytes_list_rec_8bit)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+               /* Configuring buffer size */
+               if ((err =
+                    snd_pcm_ioplug_set_param_list(io, 
+                                               SND_PCM_IOPLUG_HW_BUFFER_BYTES,
+                                                  ARRAY_SIZE
+                                                  (bytes_list_rec_8bit),
+                                                  bytes_list_rec_8bit)) < 0) {
+                       ret = err;
+                       goto out;
+               }
+
+       }
+
+       if ((err = snd_pcm_ioplug_set_param_minmax(io,
+                                                  SND_PCM_IOPLUG_HW_PERIODS,
+                                                  2, 1024)) < 0) {
+               ret = err;
+               goto out;
+       }
+       ret = 0;
+      out:
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * Alsa-lib callback structure.
+ */
+static snd_pcm_ioplug_callback_t alsa_dsp_callback = {
+       .start = alsa_dsp_start,
+       .stop = alsa_dsp_stop,
+       .pointer = alsa_dsp_pointer,
+       .transfer = alsa_dsp_transfer,
+       .close = alsa_dsp_close,
+       .hw_params = alsa_dsp_hw_params,
+       .prepare = alsa_dsp_prepare,
+       .pause = alsa_dsp_pause,
+       .resume = alsa_dsp_resume,
+};
+
+/**
+ * @param alsa_dsp the structure to be configured.
+ * 
+ * It probes all configured dsp task devices to be available for 
+ * this plugin. It will use first dsp task device whose is in
+ * UNINITIALISED state. 
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int alsa_dsp_open_dsp_task(snd_pcm_alsa_dsp_t * alsa_dsp,
+                                 device_list_t * device_list)
+{
+       int err = -EINVAL;
+       device_list_t *tmp;
+       DENTER();
+       DPRINT("Looking for a dsp device node \n");
+       list_for_each_entry(tmp, &(device_list->list), list) {
+               DPRINT("Trying to use %s\n", tmp->device);
+               if ((err =
+                    dsp_protocol_open_node(alsa_dsp->dsp_protocol,
+                                           tmp->device)) < 0) {
+                       DPRINT("%s is not available now\n", tmp->device);
+                       dsp_protocol_close_node(alsa_dsp->dsp_protocol);
+               } else
+                       break;
+       }
+       if (err < 0) {
+               DPRINT("No valid dsp task nodes for now. Exiting.\n");
+       }
+       DLEAVE(err);
+       return err;
+}
+
+/**
+ * @param n configuration file parse tree. 
+ * @param device_list list of device files to be filled.
+ *
+ * It searches for device file names in given configuration parse
+ * tree. When one device file name is found, it is filled into device_list.
+ *
+ * @return zero if success, otherwise a negative error code.
+ */
+static int fill_string_list(snd_config_t * n, device_list_t * device_list)
+{
+       snd_config_iterator_t j, nextj;
+       device_list_t *tmp;
+       long idx = 0;
+       int ret;
+       DENTER();
+       INIT_LIST_HEAD(&device_list->list);
+       snd_config_for_each(j, nextj, n) {
+               snd_config_t *s = snd_config_iterator_entry(j);
+               const char *id_number;
+               long k;
+               if (snd_config_get_id(s, &id_number) < 0)
+                       continue;
+               if (safe_strtol(id_number, &k) < 0) {
+                       SNDERR("id of field %s is not an integer", id_number);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (k == idx) {
+                       idx++;
+                       /* add to available dsp task nodes */
+                       tmp = (device_list_t *) malloc(sizeof(device_list_t));
+                       if (snd_config_get_ascii(s, &(tmp->device)) < 0) {
+                               SNDERR("invalid ascii string for id %s\n",
+                                      id_number);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       list_add(&(tmp->list), &(device_list->list));
+               }
+
+       }
+       ret = 0;
+      out:
+       DLEAVE(ret);
+       return ret;
+}
+
+/**
+ * It initializes the alsa plugin. It reads the parameters and creates the 
+ * connection with the pcm device file.
+ *
+ * @return  zero if success, otherwise a negative error code.
+ */
+SND_PCM_PLUGIN_DEFINE_FUNC(alsa_dsp)
+{
+       snd_config_iterator_t i, next;
+       snd_pcm_alsa_dsp_t *alsa_dsp;
+       int err;
+       int ret;
+       DENTER();
+
+       /* Allocate the structure */
+       alsa_dsp = calloc(1, sizeof(snd_pcm_alsa_dsp_t));
+       if (alsa_dsp == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* Read the configuration searching for configurated devices */
+       snd_config_for_each(i, next, conf) {
+               snd_config_t *n = snd_config_iterator_entry(i);
+               const char *id;
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+               if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
+                       continue;
+               if (strcmp(id, "playback_device_file") == 0) {
+                       if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND){
+                               if ((err = 
+                                    fill_string_list(n,
+                                         &(alsa_dsp->playback_devices))) < 0) {
+                                       SNDERR("Could not fill string"
+                                               " list for playback devices\n");
+                                       goto error;
+                               }
+                       } else {
+                               SNDERR("Invalid type for %s", id);
+                               err = -EINVAL;
+                               goto error;
+                       }
+
+                       continue;
+               }
+               if (strcmp(id, "recording_device_file") == 0) {
+                       if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND){
+                               if ((err =
+                                    fill_string_list(n,
+                                         &(alsa_dsp->recording_devices))) < 0){
+                                       SNDERR("Could not fill string"
+                                              " list for recording devices\n");
+                                       goto error;
+                               }
+                       } else {
+                               SNDERR("Invalid type for %s", id);
+                               err = -EINVAL;
+                               goto error;
+                       }
+
+                       continue;
+               }
+               SNDERR("Unknown field %s", id);
+               err = -EINVAL;
+               goto error;
+       }
+       /* Initialise the dsp_protocol and create connection */
+       if ((err = dsp_protocol_create(&(alsa_dsp->dsp_protocol))) < 0)
+               goto error;
+       if ((err = alsa_dsp_open_dsp_task(alsa_dsp,
+                                         (stream == SND_PCM_STREAM_PLAYBACK) ?
+                                         &(alsa_dsp->playback_devices) : 
+                                         &(alsa_dsp->recording_devices))) < 0)
+               goto error;
+       /* Initialise the snd_pcm_ioplug_t */
+       alsa_dsp->io.version = SND_PCM_IOPLUG_VERSION;
+       alsa_dsp->io.name = "Alsa - DSP PCM Plugin";
+       alsa_dsp->io.mmap_rw = 0;
+       alsa_dsp->io.callback = &alsa_dsp_callback;
+       alsa_dsp->io.poll_fd = alsa_dsp->dsp_protocol->fd;
+       alsa_dsp->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
+           POLLOUT : POLLIN;
+
+       alsa_dsp->io.private_data = alsa_dsp;
+       free_ref = alsa_dsp;
+
+       if ((err = snd_pcm_ioplug_create(&alsa_dsp->io, name,
+                                        stream, mode)) < 0)
+               goto error;
+
+       /* Configure the plugin */
+       if ((err = alsa_dsp_configure_constraints(alsa_dsp)) < 0) {
+               snd_pcm_ioplug_delete(&alsa_dsp->io);
+               goto error;
+       }
+       *pcmp = alsa_dsp->io.pcm;
+       ret = 0;
+       goto out;
+      error:
+       ret = err;
+       free(alsa_dsp);
+      out:
+       DLEAVE(ret);
+       return ret;
+}
+
+
+void alsa_dsp_descructor(void) __attribute__ ((destructor));
+
+void alsa_dsp_descructor(void)
+{
+       DENTER();
+       DPRINT("alsa dsp destructor\n");
+       DPRINT("checking for memories leaks and releasing resources\n");
+       if (free_ref) {
+               if (free_ref->dsp_protocol) {
+                       dsp_protocol_close_node(free_ref->dsp_protocol);
+                       dsp_protocol_destroy(&(free_ref->dsp_protocol));        
+               }
+               free_device_list(&(free_ref->playback_devices));
+
+               free_device_list(&(free_ref->recording_devices));
+               
+               free(free_ref);
+               free_ref = NULL;
+       }
+       DLEAVE(0);
+
+}
+
+SND_PCM_PLUGIN_SYMBOL(alsa_dsp);