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