~ubuntu-branches/ubuntu/hardy/alsa-plugins/hardy-proposed

« back to all changes in this revision

Viewing changes to maemo/alsa-dsp.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel T Chen
  • Date: 2007-06-12 19:03:08 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070612190308-yhyjw8t4wk7zhte0
Tags: 1.0.14-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - debian/control:
    + Don't build-depend on JACK, as it's in universe.  Clarify and
      update the Description to note the above restriction and
      {in,ex}clusion of newer plugins (LP: #57089),
    + Adhere to DebianMaintainerField.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @file alsa-dsp.c
 
3
 * @brief Alsa External plugin: I/O plugin
 
4
 * <p>
 
5
 * Copyright (C) 2006 Nokia Corporation
 
6
 * <p>
 
7
 * Contact: Eduardo Bezerra Valentin <eduardo.valentin@indt.org.br>
 
8
 * 
 
9
 * This library is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU Library General Public
 
11
 * License as published by the Free Software Foundation; either
 
12
 * version 2 of the License, or (at your option) any later version.
 
13
 *
 
14
 * This library is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 * Library General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Library General Public
 
20
 * License along with this library; if not, write to the
 
21
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
22
 * Boston, MA 02111-1307, USA.
 
23
 * */
 
24
#include <stdio.h>
 
25
#include <sys/ioctl.h>
 
26
#include <alsa/asoundlib.h>
 
27
#include <alsa/pcm_external.h>
 
28
#include "list.h"
 
29
#include "debug.h"
 
30
#include "dsp-protocol.h"
 
31
#include "constants.h"
 
32
 
 
33
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
 
34
/** 
 
35
 * Device node file name list.
 
36
 */
 
37
typedef struct {
 
38
        char *device;
 
39
        struct list_head list;
 
40
} device_list_t;
 
41
 
 
42
/** 
 
43
 * Holds the need information: list of playback and recording devices,
 
44
 * current format, sample_rate, bytes per frame and pointer to ring
 
45
 * buffer.
 
46
 */
 
47
typedef struct snd_pcm_alsa_dsp {
 
48
        snd_pcm_ioplug_t io;
 
49
        dsp_protocol_t *dsp_protocol;
 
50
        int format;
 
51
        int sample_rate;
 
52
        int bytes_per_frame;
 
53
        snd_pcm_sframes_t hw_pointer;
 
54
        device_list_t playback_devices;
 
55
        device_list_t recording_devices;
 
56
} snd_pcm_alsa_dsp_t;
 
57
 
 
58
static snd_pcm_alsa_dsp_t *free_ref;
 
59
/**
 
60
 * @param io pcm io plugin configured to Alsa libs.
 
61
 *
 
62
 * It starts the playback sending a DSP_CMD_PLAY.
 
63
 *
 
64
 * @return zero if success, otherwise a negative error code.
 
65
 */
 
66
static int alsa_dsp_start(snd_pcm_ioplug_t * io)
 
67
{
 
68
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
69
        int ret;
 
70
        DENTER();
 
71
        DPRINT("IO_STREAM %d == SND_PCM_STREAM_PLAYBACK %d\n", io->stream,
 
72
               io->stream == SND_PCM_STREAM_PLAYBACK);
 
73
        if (io->stream != SND_PCM_STREAM_PLAYBACK)
 
74
                dsp_protocol_set_mic_enabled(alsa_dsp->dsp_protocol, 1);
 
75
        ret = dsp_protocol_send_play(alsa_dsp->dsp_protocol);
 
76
        DLEAVE(ret);
 
77
        return ret;
 
78
}
 
79
 
 
80
/**
 
81
 * @param io the pcm io plugin we configured to Alsa libs.
 
82
 *
 
83
 * It starts the playback sending a DSP_CMD_STOP.
 
84
 *
 
85
 * @return zero if success, otherwise a negative error code.
 
86
 */
 
87
static int alsa_dsp_stop(snd_pcm_ioplug_t * io)
 
88
{
 
89
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
90
        int ret;
 
91
        DENTER();
 
92
        ret = dsp_protocol_send_stop(alsa_dsp->dsp_protocol);
 
93
        if (io->stream != SND_PCM_STREAM_PLAYBACK)
 
94
                dsp_protocol_set_mic_enabled(alsa_dsp->dsp_protocol, 0);
 
95
 
 
96
        DLEAVE(ret);
 
97
        return ret;
 
98
}
 
99
 
 
100
/**
 
101
 * @param io the pcm io plugin we configured to Alsa libs.
 
102
 *
 
103
 * It returns the position of current period consuming.
 
104
 *
 
105
 * @return on success, returns current position, otherwise a negative
 
106
 * error code.
 
107
 */
 
108
static snd_pcm_sframes_t alsa_dsp_pointer(snd_pcm_ioplug_t * io)
 
109
{
 
110
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
111
        snd_pcm_sframes_t ret;
 
112
        DENTER();
 
113
        ret = alsa_dsp->hw_pointer;
 
114
        if (alsa_dsp->hw_pointer == 0)
 
115
                alsa_dsp->hw_pointer =
 
116
                    io->period_size * alsa_dsp->bytes_per_frame;
 
117
        else
 
118
                alsa_dsp->hw_pointer = 0;
 
119
        DLEAVE((int)ret);
 
120
        return ret;
 
121
}
 
122
 
 
123
/**
 
124
 * @param io the pcm io plugin we configured to Alsa libs.
 
125
 *
 
126
 * It transfers the audio data to dsp side.
 
127
 *
 
128
 * @return on success, returns amount of data transfered,
 
129
 * otherwise a negative error code.
 
130
 */
 
131
static snd_pcm_sframes_t alsa_dsp_transfer(snd_pcm_ioplug_t * io,
 
132
                                           const snd_pcm_channel_area_t * areas,
 
133
                                           snd_pcm_uframes_t offset,
 
134
                                           snd_pcm_uframes_t size)
 
135
{
 
136
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
137
        DENTER();
 
138
        char *buf;
 
139
        int words;
 
140
        ssize_t result;
 
141
 
 
142
        words = size * alsa_dsp->bytes_per_frame;
 
143
        words /= 2;
 
144
        DPRINT("***** Info: words %d size %lu bpf: %d\n", words, size,
 
145
               alsa_dsp->bytes_per_frame);
 
146
        if (words > alsa_dsp->dsp_protocol->mmap_buffer_size) {
 
147
                DERROR("Requested too much data transfer (playing only %d)\n",
 
148
                       alsa_dsp->dsp_protocol->mmap_buffer_size);
 
149
                words = alsa_dsp->dsp_protocol->mmap_buffer_size;
 
150
        }
 
151
        if (alsa_dsp->dsp_protocol->state != STATE_PLAYING) {
 
152
                DPRINT("I did nothing - No start sent\n");
 
153
                alsa_dsp_start(io);
 
154
        }
 
155
        /* we handle only an interleaved buffer */
 
156
        buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8;
 
157
        if (io->stream == SND_PCM_STREAM_PLAYBACK)
 
158
                result =
 
159
                    dsp_protocol_send_audio_data(alsa_dsp->dsp_protocol, buf,
 
160
                                                 words);
 
161
        else
 
162
                result =
 
163
                    dsp_protocol_receive_audio_data(alsa_dsp->dsp_protocol, buf,
 
164
                                                    words);
 
165
        result *= 2;
 
166
        result /= alsa_dsp->bytes_per_frame;
 
167
        alsa_dsp->hw_pointer += result;
 
168
        DLEAVE(result);
 
169
        return result;
 
170
}
 
171
 
 
172
/**
 
173
 * @param device_list a list of device names to be freed.
 
174
 *
 
175
 * It passes a list of device names and frees each node.
 
176
 *
 
177
 * @return zero (success).
 
178
 */
 
179
static int free_device_list(device_list_t * device_list)
 
180
{
 
181
        struct list_head *pos, *q;
 
182
        device_list_t *tmp;
 
183
        list_for_each_safe(pos, q, &device_list->list) {
 
184
                tmp = list_entry(pos, device_list_t, list);
 
185
                list_del(pos);
 
186
                free(tmp->device);
 
187
                free(tmp);
 
188
        }
 
189
        return 0;
 
190
}
 
191
 
 
192
/**
 
193
 * @param io the pcm io plugin we configured to Alsa libs.
 
194
 *
 
195
 * Closes the connection with the pcm dsp task. It
 
196
 * destroies all allocated data. 
 
197
 *
 
198
 * @return zero if success, otherwise a negative error code.
 
199
 */
 
200
static int alsa_dsp_close(snd_pcm_ioplug_t * io)
 
201
{
 
202
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
203
        int ret = 0;
 
204
        DENTER();
 
205
        ret = dsp_protocol_close_node(alsa_dsp->dsp_protocol);
 
206
        dsp_protocol_destroy(&(alsa_dsp->dsp_protocol));
 
207
        free_device_list(&(alsa_dsp->playback_devices));
 
208
        free_device_list(&(alsa_dsp->recording_devices));
 
209
        DLEAVE(ret);
 
210
        return ret;
 
211
}
 
212
 
 
213
/**
 
214
 * @param map the values to be mapped
 
215
 * @param value the search key
 
216
 * @param steps how many keys should be checked 
 
217
 *
 
218
 * Maps a value to another. 
 
219
 *
 
220
 * @return on success, returns mapped value, otherwise a negative error code.
 
221
 */
 
222
static int map_value(int *map, int value, int steps)
 
223
{
 
224
        int i;
 
225
        for (i = 0; i < steps; i++)
 
226
                if (map[i * 2] == value)
 
227
                        return map[i * 2 + 1];
 
228
        return -1;
 
229
}
 
230
 
 
231
/**
 
232
 * @param io the pcm io plugin we configured to Alsa libs.
 
233
 * @param params 
 
234
 *
 
235
 * It checks if the pcm format and rate are supported. 
 
236
 *
 
237
 * @return zero if success, otherwise a negative error code.
 
238
 */
 
239
static int alsa_dsp_hw_params(snd_pcm_ioplug_t * io,
 
240
                              snd_pcm_hw_params_t * params)
 
241
{
 
242
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
243
        int ret = 0;
 
244
        int map_sample_rates[] = {
 
245
                8000, SAMPLE_RATE_8KHZ,
 
246
                11025, SAMPLE_RATE_11_025KHZ,
 
247
                12000, SAMPLE_RATE_12KHZ,
 
248
                16000, SAMPLE_RATE_16KHZ,
 
249
                22050, SAMPLE_RATE_22_05KHZ,
 
250
                24000, SAMPLE_RATE_24KHZ,
 
251
                32000, SAMPLE_RATE_32KHZ,
 
252
                44100, SAMPLE_RATE_44_1KHZ,
 
253
                48000, SAMPLE_RATE_48KHZ
 
254
        };
 
255
        int map_formats[] = {
 
256
                SND_PCM_FORMAT_A_LAW, DSP_AFMT_ALAW,
 
257
                SND_PCM_FORMAT_MU_LAW, DSP_AFMT_ULAW,
 
258
                SND_PCM_FORMAT_S16_LE, DSP_AFMT_S16_LE,
 
259
                SND_PCM_FORMAT_U8, DSP_AFMT_U8,
 
260
                SND_PCM_FORMAT_S8, DSP_AFMT_S8,
 
261
                SND_PCM_FORMAT_S16_BE, DSP_AFMT_S16_BE,
 
262
                SND_PCM_FORMAT_U16_LE, DSP_AFMT_U16_LE,
 
263
                SND_PCM_FORMAT_U16_BE, DSP_AFMT_U16_BE
 
264
        };
 
265
        DENTER();
 
266
        DPRINT("Checking Format- Ret %d\n", ret);
 
267
        alsa_dsp->format = map_value(map_formats, io->format,
 
268
                                     io->stream ==
 
269
                                     SND_PCM_STREAM_PLAYBACK ?
 
270
                                     ARRAY_SIZE(map_formats) : 3);
 
271
        if (alsa_dsp->format < 0) {
 
272
                DERROR("*** ALSA-DSP: unsupported format %s\n",
 
273
                       snd_pcm_format_name(io->format));
 
274
                ret = -EINVAL;
 
275
        }
 
276
        DPRINT("Format is Ok. Checking rate. Ret %d\n", ret);
 
277
 
 
278
        alsa_dsp->sample_rate = map_value(map_sample_rates, io->rate,
 
279
                                          io->stream ==
 
280
                                          SND_PCM_STREAM_PLAYBACK ?
 
281
                                          ARRAY_SIZE(map_sample_rates) : 1);
 
282
        if (alsa_dsp->sample_rate < 0) {
 
283
                ret = -EINVAL;
 
284
                DERROR("** ALSA - DSP - Unsuported Sample Rate! **\n");
 
285
        }
 
286
        DPRINT("Rate is ok. Calculating WPF. Ret %d\n", ret);
 
287
 
 
288
        alsa_dsp->bytes_per_frame =
 
289
            ((snd_pcm_format_physical_width(io->format) * io->channels) / 8);
 
290
        DPRINT("WPF: %d width %d channels %d\n", alsa_dsp->bytes_per_frame,
 
291
               snd_pcm_format_physical_width(io->format), io->channels);
 
292
 
 
293
        DLEAVE(ret);
 
294
        return ret;
 
295
}
 
296
 
 
297
/**
 
298
 * @param io the pcm io plugin we configured to Alsa libs.
 
299
 * 
 
300
 * It sends the audio parameters to pcm task node (formats, channels, 
 
301
 * access, rates). It is assumed that everything is proper set.
 
302
 *
 
303
 * @return zero if success, otherwise a negative error code.
 
304
 */
 
305
static int alsa_dsp_prepare(snd_pcm_ioplug_t * io)
 
306
{
 
307
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
308
        audio_params_data_t params;
 
309
        speech_params_data_t sparams;
 
310
        int ret = 0;
 
311
        char *tmp;
 
312
        DENTER();
 
313
 
 
314
        alsa_dsp->hw_pointer = 0;
 
315
        if (alsa_dsp->dsp_protocol->state != STATE_INITIALISED) {
 
316
                tmp = strdup(alsa_dsp->dsp_protocol->device);
 
317
                ret = dsp_protocol_close_node(alsa_dsp->dsp_protocol);
 
318
                if (!ret)
 
319
                        dsp_protocol_open_node(alsa_dsp->dsp_protocol, tmp);
 
320
                free(tmp);
 
321
        }
 
322
        if (ret == 0) {
 
323
                if (io->stream == SND_PCM_STREAM_PLAYBACK) {
 
324
                        params.dsp_cmd = DSP_CMD_SET_PARAMS;
 
325
                        params.dsp_audio_fmt = alsa_dsp->format;
 
326
                        params.sample_rate = alsa_dsp->sample_rate;
 
327
                        params.number_channels = io->channels;
 
328
                        params.ds_stream_id = 0;
 
329
                        params.stream_priority = 0;
 
330
                        if (dsp_protocol_send_audio_params
 
331
                            (alsa_dsp->dsp_protocol, &params) < 0) {
 
332
                                ret = -EIO;
 
333
                                DERROR("Error in send params data\n");
 
334
                        } else
 
335
                                DPRINT("Sending params data is ok\n");
 
336
                } else {
 
337
                        sparams.dsp_cmd = DSP_CMD_SET_SPEECH_PARAMS;
 
338
                        sparams.audio_fmt = alsa_dsp->format;
 
339
                        sparams.sample_rate = alsa_dsp->sample_rate;
 
340
                        sparams.ds_stream_id = 0;
 
341
                        sparams.stream_priority = 0;
 
342
                        sparams.frame_size = io->period_size;
 
343
                        DPRINT("frame size %u\n", sparams.frame_size);
 
344
                        if (dsp_protocol_send_speech_params
 
345
                            (alsa_dsp->dsp_protocol, &sparams) < 0) {
 
346
                                ret = -EIO;
 
347
                                DERROR("Error in send speech params data\n");
 
348
                        } else
 
349
                                DPRINT("Sending speech params data is ok\n");
 
350
 
 
351
                }
 
352
        }
 
353
        DLEAVE(ret);
 
354
        return ret;
 
355
}
 
356
 
 
357
/**
 
358
 * @param io the pcm io plugin we configured to Alsa libs.
 
359
 *
 
360
 * It pauses the playback sending a DSP_CMD_PAUSE.
 
361
 *
 
362
 * @return zero if success, otherwise a negative error code.
 
363
 */
 
364
static int alsa_dsp_pause(snd_pcm_ioplug_t * io, int enable)
 
365
{
 
366
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
367
        int ret;
 
368
        DENTER();
 
369
        ret = dsp_protocol_send_pause(alsa_dsp->dsp_protocol);
 
370
        DLEAVE(ret);
 
371
        return ret;
 
372
}
 
373
 
 
374
/**
 
375
 * @param io the pcm io plugin we configured to Alsa libs.
 
376
 *
 
377
 * It starts the playback sending a DSP_CMD_PLAY.
 
378
 *
 
379
 * @return zero if success, otherwise a negative error code.
 
380
 */
 
381
static int alsa_dsp_resume(snd_pcm_ioplug_t * io)
 
382
{
 
383
        snd_pcm_alsa_dsp_t *alsa_dsp = io->private_data;
 
384
        int ret;
 
385
        DENTER();
 
386
        ret = dsp_protocol_send_play(alsa_dsp->dsp_protocol);
 
387
        DLEAVE(ret);
 
388
        return ret;
 
389
}
 
390
 
 
391
/**
 
392
 * @param alsa_dsp the structure to be configured.
 
393
 * 
 
394
 * It configures constraints about formats, channels, access, rates, 
 
395
 * periods and buffer size. It exports the supported constraints by the
 
396
 * dsp task node to the alsa plugin library.
 
397
 *
 
398
 * @return zero if success, otherwise a negative error code.
 
399
 */
 
400
static int alsa_dsp_configure_constraints(snd_pcm_alsa_dsp_t * alsa_dsp)
 
401
{
 
402
        snd_pcm_ioplug_t *io = &alsa_dsp->io;
 
403
        static snd_pcm_access_t access_list[] = {
 
404
                SND_PCM_ACCESS_RW_INTERLEAVED
 
405
        };
 
406
        const unsigned int formats[] = {
 
407
                SND_PCM_FORMAT_U8,      /* DSP_AFMT_U8 */
 
408
                SND_PCM_FORMAT_S16_LE,  /* DSP_AFMT_S16_LE */
 
409
                SND_PCM_FORMAT_S16_BE,  /* DSP_AFMT_S16_BE */
 
410
                SND_PCM_FORMAT_S8,      /* DSP_AFMT_S8 */
 
411
                SND_PCM_FORMAT_U16_LE,  /* DSP_AFMT_U16_LE */
 
412
                SND_PCM_FORMAT_U16_BE,  /* DSP_AFMT_U16_BE */
 
413
                SND_PCM_FORMAT_A_LAW,   /* DSP_AFMT_ALAW */
 
414
                SND_PCM_FORMAT_MU_LAW   /* DSP_AFMT_ULAW */
 
415
        };
 
416
        const unsigned int formats_recor[] = {
 
417
                SND_PCM_FORMAT_S16_LE,  /* DSP_AFMT_S16_LE */
 
418
                SND_PCM_FORMAT_A_LAW,   /* DSP_AFMT_ALAW */
 
419
                SND_PCM_FORMAT_MU_LAW   /* DSP_AFMT_ULAW */
 
420
        };
 
421
        static unsigned int bytes_list[] = {
 
422
                1U << 11, 1U << 12
 
423
        };
 
424
        static unsigned int bytes_list_rec_8bit[] = {
 
425
                /* It must be multiple of 80... less than or equal to 800 */
 
426
                80, 160, 240, 320, 400, 480, 560, 640, 720, 800
 
427
        };
 
428
 
 
429
        int ret, err;
 
430
        DENTER();
 
431
        /* Configuring access */
 
432
        if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
 
433
                                                 ARRAY_SIZE(access_list),
 
434
                                                 access_list)) < 0) {
 
435
                ret = err;
 
436
                goto out;
 
437
        }
 
438
        if (io->stream == SND_PCM_STREAM_PLAYBACK) {
 
439
                /* Configuring formats */
 
440
                if ((err =
 
441
                     snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
 
442
                                                   ARRAY_SIZE(formats),
 
443
                                                   formats)) < 0) {
 
444
                        ret = err;
 
445
                        goto out;
 
446
                }
 
447
                /* Configuring channels */
 
448
                if ((err = 
 
449
                     snd_pcm_ioplug_set_param_minmax(io,
 
450
                                                     SND_PCM_IOPLUG_HW_CHANNELS,
 
451
                                                     1, 2)) < 0) {
 
452
                        ret = err;
 
453
                        goto out;
 
454
                }
 
455
 
 
456
                /* Configuring rates */
 
457
                if ((err =
 
458
                     snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
 
459
                                                     8000, 48000)) < 0) {
 
460
                        ret = err;
 
461
                        goto out;
 
462
                }
 
463
                /* Configuring periods */
 
464
                if ((err = 
 
465
                     snd_pcm_ioplug_set_param_list(io,
 
466
                                                 SND_PCM_IOPLUG_HW_PERIOD_BYTES,
 
467
                                                 ARRAY_SIZE(bytes_list),
 
468
                                                 bytes_list)) < 0) {
 
469
                        ret = err;
 
470
                        goto out;
 
471
                }
 
472
                /* Configuring buffer size */
 
473
                if ((err = 
 
474
                     snd_pcm_ioplug_set_param_list(io,
 
475
                                                 SND_PCM_IOPLUG_HW_BUFFER_BYTES,
 
476
                                                 ARRAY_SIZE(bytes_list),
 
477
                                                 bytes_list)) < 0) {
 
478
                        ret = err;
 
479
                        goto out;
 
480
                }
 
481
 
 
482
        } else {
 
483
                /* Configuring formats */
 
484
                if ((err =
 
485
                     snd_pcm_ioplug_set_param_list(io, 
 
486
                                                   SND_PCM_IOPLUG_HW_FORMAT,
 
487
                                                   ARRAY_SIZE(formats_recor),
 
488
                                                   formats_recor)) < 0) {
 
489
                        ret = err;
 
490
                        goto out;
 
491
                }
 
492
                /* Configuring channels */
 
493
                if ((err = snd_pcm_ioplug_set_param_minmax(io,
 
494
                                                    SND_PCM_IOPLUG_HW_CHANNELS,
 
495
                                                    1, 1)) < 0) {
 
496
                        ret = err;
 
497
                        goto out;
 
498
                }
 
499
 
 
500
                /* Configuring rates */
 
501
                if ((err =
 
502
                     snd_pcm_ioplug_set_param_minmax(io, 
 
503
                                                     SND_PCM_IOPLUG_HW_RATE,
 
504
                                                     8000, 8000)) < 0) {
 
505
                        ret = err;
 
506
                        goto out;
 
507
                }
 
508
                /* Configuring periods */
 
509
                if ((err = 
 
510
                     snd_pcm_ioplug_set_param_list(io, 
 
511
                                                SND_PCM_IOPLUG_HW_PERIOD_BYTES,
 
512
                                                ARRAY_SIZE
 
513
                                                (bytes_list_rec_8bit),
 
514
                                                bytes_list_rec_8bit)) < 0) {
 
515
                        ret = err;
 
516
                        goto out;
 
517
                }
 
518
                /* Configuring buffer size */
 
519
                if ((err =
 
520
                     snd_pcm_ioplug_set_param_list(io, 
 
521
                                                SND_PCM_IOPLUG_HW_BUFFER_BYTES,
 
522
                                                   ARRAY_SIZE
 
523
                                                   (bytes_list_rec_8bit),
 
524
                                                   bytes_list_rec_8bit)) < 0) {
 
525
                        ret = err;
 
526
                        goto out;
 
527
                }
 
528
 
 
529
        }
 
530
 
 
531
        if ((err = snd_pcm_ioplug_set_param_minmax(io,
 
532
                                                   SND_PCM_IOPLUG_HW_PERIODS,
 
533
                                                   2, 1024)) < 0) {
 
534
                ret = err;
 
535
                goto out;
 
536
        }
 
537
        ret = 0;
 
538
      out:
 
539
        DLEAVE(ret);
 
540
        return ret;
 
541
}
 
542
 
 
543
/**
 
544
 * Alsa-lib callback structure.
 
545
 */
 
546
static snd_pcm_ioplug_callback_t alsa_dsp_callback = {
 
547
        .start = alsa_dsp_start,
 
548
        .stop = alsa_dsp_stop,
 
549
        .pointer = alsa_dsp_pointer,
 
550
        .transfer = alsa_dsp_transfer,
 
551
        .close = alsa_dsp_close,
 
552
        .hw_params = alsa_dsp_hw_params,
 
553
        .prepare = alsa_dsp_prepare,
 
554
        .pause = alsa_dsp_pause,
 
555
        .resume = alsa_dsp_resume,
 
556
};
 
557
 
 
558
/**
 
559
 * @param alsa_dsp the structure to be configured.
 
560
 * 
 
561
 * It probes all configured dsp task devices to be available for 
 
562
 * this plugin. It will use first dsp task device whose is in
 
563
 * UNINITIALISED state. 
 
564
 *
 
565
 * @return zero if success, otherwise a negative error code.
 
566
 */
 
567
static int alsa_dsp_open_dsp_task(snd_pcm_alsa_dsp_t * alsa_dsp,
 
568
                                  device_list_t * device_list)
 
569
{
 
570
        int err = -EINVAL;
 
571
        device_list_t *tmp;
 
572
        DENTER();
 
573
        DPRINT("Looking for a dsp device node \n");
 
574
        list_for_each_entry(tmp, &(device_list->list), list) {
 
575
                DPRINT("Trying to use %s\n", tmp->device);
 
576
                if ((err =
 
577
                     dsp_protocol_open_node(alsa_dsp->dsp_protocol,
 
578
                                            tmp->device)) < 0) {
 
579
                        DPRINT("%s is not available now\n", tmp->device);
 
580
                        dsp_protocol_close_node(alsa_dsp->dsp_protocol);
 
581
                } else
 
582
                        break;
 
583
        }
 
584
        if (err < 0) {
 
585
                DPRINT("No valid dsp task nodes for now. Exiting.\n");
 
586
        }
 
587
        DLEAVE(err);
 
588
        return err;
 
589
}
 
590
 
 
591
/**
 
592
 * @param n configuration file parse tree. 
 
593
 * @param device_list list of device files to be filled.
 
594
 *
 
595
 * It searches for device file names in given configuration parse
 
596
 * tree. When one device file name is found, it is filled into device_list.
 
597
 *
 
598
 * @return zero if success, otherwise a negative error code.
 
599
 */
 
600
static int fill_string_list(snd_config_t * n, device_list_t * device_list)
 
601
{
 
602
        snd_config_iterator_t j, nextj;
 
603
        device_list_t *tmp;
 
604
        long idx = 0;
 
605
        int ret;
 
606
        DENTER();
 
607
        INIT_LIST_HEAD(&device_list->list);
 
608
        snd_config_for_each(j, nextj, n) {
 
609
                snd_config_t *s = snd_config_iterator_entry(j);
 
610
                const char *id_number;
 
611
                long k;
 
612
                if (snd_config_get_id(s, &id_number) < 0)
 
613
                        continue;
 
614
                if (safe_strtol(id_number, &k) < 0) {
 
615
                        SNDERR("id of field %s is not an integer", id_number);
 
616
                        ret = -EINVAL;
 
617
                        goto out;
 
618
                }
 
619
                if (k == idx) {
 
620
                        idx++;
 
621
                        /* add to available dsp task nodes */
 
622
                        tmp = (device_list_t *) malloc(sizeof(device_list_t));
 
623
                        if (snd_config_get_ascii(s, &(tmp->device)) < 0) {
 
624
                                SNDERR("invalid ascii string for id %s\n",
 
625
                                       id_number);
 
626
                                ret = -EINVAL;
 
627
                                goto out;
 
628
                        }
 
629
 
 
630
                        list_add(&(tmp->list), &(device_list->list));
 
631
                }
 
632
 
 
633
        }
 
634
        ret = 0;
 
635
      out:
 
636
        DLEAVE(ret);
 
637
        return ret;
 
638
}
 
639
 
 
640
/**
 
641
 * It initializes the alsa plugin. It reads the parameters and creates the 
 
642
 * connection with the pcm device file.
 
643
 *
 
644
 * @return  zero if success, otherwise a negative error code.
 
645
 */
 
646
SND_PCM_PLUGIN_DEFINE_FUNC(alsa_dsp)
 
647
{
 
648
        snd_config_iterator_t i, next;
 
649
        snd_pcm_alsa_dsp_t *alsa_dsp;
 
650
        int err;
 
651
        int ret;
 
652
        DENTER();
 
653
 
 
654
        /* Allocate the structure */
 
655
        alsa_dsp = calloc(1, sizeof(snd_pcm_alsa_dsp_t));
 
656
        if (alsa_dsp == NULL) {
 
657
                ret = -ENOMEM;
 
658
                goto out;
 
659
        }
 
660
 
 
661
        /* Read the configuration searching for configurated devices */
 
662
        snd_config_for_each(i, next, conf) {
 
663
                snd_config_t *n = snd_config_iterator_entry(i);
 
664
                const char *id;
 
665
                if (snd_config_get_id(n, &id) < 0)
 
666
                        continue;
 
667
                if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
 
668
                        continue;
 
669
                if (strcmp(id, "playback_device_file") == 0) {
 
670
                        if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND){
 
671
                                if ((err = 
 
672
                                     fill_string_list(n,
 
673
                                          &(alsa_dsp->playback_devices))) < 0) {
 
674
                                        SNDERR("Could not fill string"
 
675
                                                " list for playback devices\n");
 
676
                                        goto error;
 
677
                                }
 
678
                        } else {
 
679
                                SNDERR("Invalid type for %s", id);
 
680
                                err = -EINVAL;
 
681
                                goto error;
 
682
                        }
 
683
 
 
684
                        continue;
 
685
                }
 
686
                if (strcmp(id, "recording_device_file") == 0) {
 
687
                        if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND){
 
688
                                if ((err =
 
689
                                     fill_string_list(n,
 
690
                                          &(alsa_dsp->recording_devices))) < 0){
 
691
                                        SNDERR("Could not fill string"
 
692
                                               " list for recording devices\n");
 
693
                                        goto error;
 
694
                                }
 
695
                        } else {
 
696
                                SNDERR("Invalid type for %s", id);
 
697
                                err = -EINVAL;
 
698
                                goto error;
 
699
                        }
 
700
 
 
701
                        continue;
 
702
                }
 
703
                SNDERR("Unknown field %s", id);
 
704
                err = -EINVAL;
 
705
                goto error;
 
706
        }
 
707
        /* Initialise the dsp_protocol and create connection */
 
708
        if ((err = dsp_protocol_create(&(alsa_dsp->dsp_protocol))) < 0)
 
709
                goto error;
 
710
        if ((err = alsa_dsp_open_dsp_task(alsa_dsp,
 
711
                                          (stream == SND_PCM_STREAM_PLAYBACK) ?
 
712
                                          &(alsa_dsp->playback_devices) : 
 
713
                                          &(alsa_dsp->recording_devices))) < 0)
 
714
                goto error;
 
715
        /* Initialise the snd_pcm_ioplug_t */
 
716
        alsa_dsp->io.version = SND_PCM_IOPLUG_VERSION;
 
717
        alsa_dsp->io.name = "Alsa - DSP PCM Plugin";
 
718
        alsa_dsp->io.mmap_rw = 0;
 
719
        alsa_dsp->io.callback = &alsa_dsp_callback;
 
720
        alsa_dsp->io.poll_fd = alsa_dsp->dsp_protocol->fd;
 
721
        alsa_dsp->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
 
722
            POLLOUT : POLLIN;
 
723
 
 
724
        alsa_dsp->io.private_data = alsa_dsp;
 
725
        free_ref = alsa_dsp;
 
726
 
 
727
        if ((err = snd_pcm_ioplug_create(&alsa_dsp->io, name,
 
728
                                         stream, mode)) < 0)
 
729
                goto error;
 
730
 
 
731
        /* Configure the plugin */
 
732
        if ((err = alsa_dsp_configure_constraints(alsa_dsp)) < 0) {
 
733
                snd_pcm_ioplug_delete(&alsa_dsp->io);
 
734
                goto error;
 
735
        }
 
736
        *pcmp = alsa_dsp->io.pcm;
 
737
        ret = 0;
 
738
        goto out;
 
739
      error:
 
740
        ret = err;
 
741
        free(alsa_dsp);
 
742
      out:
 
743
        DLEAVE(ret);
 
744
        return ret;
 
745
}
 
746
 
 
747
 
 
748
void alsa_dsp_descructor(void) __attribute__ ((destructor));
 
749
 
 
750
void alsa_dsp_descructor(void)
 
751
{
 
752
        DENTER();
 
753
        DPRINT("alsa dsp destructor\n");
 
754
        DPRINT("checking for memories leaks and releasing resources\n");
 
755
        if (free_ref) {
 
756
                if (free_ref->dsp_protocol) {
 
757
                        dsp_protocol_close_node(free_ref->dsp_protocol);
 
758
                        dsp_protocol_destroy(&(free_ref->dsp_protocol));        
 
759
                }
 
760
                free_device_list(&(free_ref->playback_devices));
 
761
 
 
762
                free_device_list(&(free_ref->recording_devices));
 
763
                
 
764
                free(free_ref);
 
765
                free_ref = NULL;
 
766
        }
 
767
        DLEAVE(0);
 
768
 
 
769
}
 
770
 
 
771
SND_PCM_PLUGIN_SYMBOL(alsa_dsp);