alsa-lib/src/pcm/pcm_file.c

537 lines
14 KiB
C
Raw Normal View History

2000-09-24 09:57:26 +00:00
/*
* PCM - File plugin
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
* 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 program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <byteswap.h>
#include "pcm_local.h"
#include "pcm_plugin.h"
2001-01-25 14:27:33 +00:00
typedef enum _snd_pcm_file_format {
2000-11-20 20:10:46 +00:00
SND_PCM_FILE_FORMAT_RAW
2001-01-25 14:27:33 +00:00
} snd_pcm_file_format_t;
2000-11-20 20:10:46 +00:00
2000-09-24 09:57:26 +00:00
typedef struct {
snd_pcm_t *slave;
int close_slave;
const char *fname;
2000-09-24 09:57:26 +00:00
int fd;
2000-11-20 20:10:46 +00:00
int format;
snd_pcm_uframes_t appl_ptr;
snd_pcm_uframes_t file_ptr_bytes;
snd_pcm_uframes_t wbuf_size;
2001-01-01 15:16:10 +00:00
size_t wbuf_size_bytes;
size_t wbuf_used_bytes;
char *wbuf;
snd_pcm_channel_area_t *wbuf_areas;
size_t buffer_bytes;
2000-09-24 09:57:26 +00:00
} snd_pcm_file_t;
2001-01-01 15:16:10 +00:00
static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
{
snd_pcm_file_t *file = pcm->private;
assert(bytes <= file->wbuf_used_bytes);
while (bytes > 0) {
snd_pcm_sframes_t err;
2001-01-01 15:16:10 +00:00
size_t n = bytes;
size_t cont = file->wbuf_size_bytes - file->file_ptr_bytes;
if (n > cont)
n = cont;
err = write(file->fd, file->wbuf + file->file_ptr_bytes, n);
if (err < 0) {
SYSERR("write failed");
break;
}
bytes -= err;
file->wbuf_used_bytes -= err;
file->file_ptr_bytes += err;
if (file->file_ptr_bytes == file->wbuf_size_bytes)
file->file_ptr_bytes = 0;
if ((snd_pcm_uframes_t)err != n)
2001-01-01 15:16:10 +00:00
break;
}
}
static void snd_pcm_file_add_frames(snd_pcm_t *pcm,
const snd_pcm_channel_area_t *areas,
snd_pcm_uframes_t offset, snd_pcm_uframes_t frames)
2001-01-01 15:16:10 +00:00
{
snd_pcm_file_t *file = pcm->private;
while (frames > 0) {
snd_pcm_uframes_t n = frames;
snd_pcm_uframes_t cont = file->wbuf_size - file->appl_ptr;
snd_pcm_uframes_t avail = file->wbuf_size - snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
2001-01-01 15:16:10 +00:00
if (n > cont)
n = cont;
if (n > avail)
n = avail;
snd_pcm_areas_copy(file->wbuf_areas, file->appl_ptr,
areas, offset,
2001-01-01 15:16:10 +00:00
pcm->channels, n, pcm->format);
frames -= n;
file->appl_ptr += n;
if (file->appl_ptr == file->wbuf_size)
file->appl_ptr = 0;
file->wbuf_used_bytes += snd_pcm_frames_to_bytes(pcm, n);
if (file->wbuf_used_bytes > file->buffer_bytes)
snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes - file->buffer_bytes);
assert(file->wbuf_used_bytes < file->wbuf_size_bytes);
}
}
2000-09-24 09:57:26 +00:00
static int snd_pcm_file_close(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
int err = 0;
if (file->close_slave)
err = snd_pcm_close(file->slave);
if (file->fname) {
free((void *)file->fname);
2000-09-24 09:57:26 +00:00
close(file->fd);
}
free(file);
return 0;
}
static int snd_pcm_file_nonblock(snd_pcm_t *pcm, int nonblock)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_nonblock(file->slave, nonblock);
}
static int snd_pcm_file_async(snd_pcm_t *pcm, int sig, pid_t pid)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_async(file->slave, sig, pid);
}
2000-09-24 09:57:26 +00:00
static int snd_pcm_file_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_info(file->slave, info);
}
static int snd_pcm_file_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_channel_info(file->slave, info);
}
static int snd_pcm_file_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_status(file->slave, status);
}
static snd_pcm_state_t snd_pcm_file_state(snd_pcm_t *pcm)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_state(file->slave);
}
static int snd_pcm_file_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_delay(file->slave, delayp);
}
static int snd_pcm_file_prepare(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_prepare(file->slave);
}
2000-11-24 17:08:03 +00:00
static int snd_pcm_file_reset(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
2001-01-01 15:16:10 +00:00
int err = snd_pcm_reset(file->slave);
if (err >= 0) {
/* FIXME: Questionable here */
snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
assert(file->wbuf_used_bytes == 0);
}
return err;
2000-11-24 17:08:03 +00:00
}
2000-09-24 09:57:26 +00:00
static int snd_pcm_file_start(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_start(file->slave);
}
2000-10-02 06:59:59 +00:00
static int snd_pcm_file_drop(snd_pcm_t *pcm)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2001-01-01 15:16:10 +00:00
int err = snd_pcm_drop(file->slave);
if (err >= 0) {
/* FIXME: Questionable here */
snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
assert(file->wbuf_used_bytes == 0);
}
return err;
2000-09-24 09:57:26 +00:00
}
static int snd_pcm_file_drain(snd_pcm_t *pcm)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2001-01-01 15:16:10 +00:00
int err = snd_pcm_drain(file->slave);
if (err >= 0) {
snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
assert(file->wbuf_used_bytes == 0);
}
return err;
2000-09-24 09:57:26 +00:00
}
static int snd_pcm_file_pause(snd_pcm_t *pcm, int enable)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_pause(file->slave, enable);
}
static snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
snd_pcm_sframes_t err = snd_pcm_rewind(file->slave, frames);
2001-01-01 15:16:10 +00:00
if (err > 0) {
snd_pcm_uframes_t n = snd_pcm_frames_to_bytes(pcm, frames);
snd_pcm_sframes_t ptr;
2001-01-01 15:16:10 +00:00
assert(n >= file->wbuf_used_bytes);
ptr = file->appl_ptr - err;
if (ptr < 0)
ptr += file->wbuf_size;
file->wbuf_used_bytes -= n;
}
2001-01-01 15:16:10 +00:00
return err;
2000-09-24 09:57:26 +00:00
}
static snd_pcm_sframes_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2001-01-01 15:16:10 +00:00
snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_sframes_t n = snd_pcm_writei(file->slave, buffer, size);
2000-09-24 09:57:26 +00:00
if (n > 0) {
2001-01-01 15:16:10 +00:00
snd_pcm_areas_from_buf(pcm, areas, (void*) buffer);
snd_pcm_file_add_frames(pcm, areas, 0, n);
2000-09-24 09:57:26 +00:00
}
return n;
}
static snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2000-11-20 20:10:46 +00:00
snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_sframes_t n = snd_pcm_writen(file->slave, bufs, size);
2000-09-24 09:57:26 +00:00
if (n > 0) {
snd_pcm_areas_from_bufs(pcm, areas, bufs);
2001-01-01 15:16:10 +00:00
snd_pcm_file_add_frames(pcm, areas, 0, n);
2000-09-24 09:57:26 +00:00
}
return n;
}
static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2001-01-01 15:16:10 +00:00
snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_sframes_t n = snd_pcm_readi(file->slave, buffer, size);
2000-09-24 09:57:26 +00:00
if (n > 0) {
2001-01-01 15:16:10 +00:00
snd_pcm_areas_from_buf(pcm, areas, buffer);
snd_pcm_file_add_frames(pcm, areas, 0, n);
2000-09-24 09:57:26 +00:00
}
return n;
}
static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2000-11-20 20:10:46 +00:00
snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_sframes_t n = snd_pcm_writen(file->slave, bufs, size);
2000-09-24 09:57:26 +00:00
if (n > 0) {
snd_pcm_areas_from_bufs(pcm, areas, bufs);
2001-01-01 15:16:10 +00:00
snd_pcm_file_add_frames(pcm, areas, 0, n);
2000-09-24 09:57:26 +00:00
}
return n;
}
static snd_pcm_sframes_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
snd_pcm_uframes_t ofs = snd_pcm_mmap_offset(pcm);
snd_pcm_sframes_t n = snd_pcm_mmap_forward(file->slave, size);
snd_pcm_uframes_t xfer = 0;
2000-09-24 09:57:26 +00:00
if (n <= 0)
return n;
while (xfer < (snd_pcm_uframes_t)n) {
2001-01-25 14:27:33 +00:00
snd_pcm_uframes_t frames = n - xfer;
snd_pcm_uframes_t cont = pcm->buffer_size - ofs;
2001-01-01 15:16:10 +00:00
if (frames > cont)
2000-09-24 09:57:26 +00:00
frames = cont;
2001-01-01 15:16:10 +00:00
snd_pcm_file_add_frames(pcm, snd_pcm_mmap_areas(file->slave), ofs, frames);
2000-09-24 09:57:26 +00:00
ofs += frames;
2000-11-20 20:10:46 +00:00
if (ofs == pcm->buffer_size)
2000-09-24 09:57:26 +00:00
ofs = 0;
xfer += frames;
}
return n;
}
static snd_pcm_sframes_t snd_pcm_file_avail_update(snd_pcm_t *pcm)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_avail_update(file->slave);
}
2000-12-21 20:44:10 +00:00
static int snd_pcm_file_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2000-12-21 20:44:10 +00:00
return snd_pcm_hw_refine(file->slave, params);
2000-09-24 09:57:26 +00:00
}
2000-11-20 20:10:46 +00:00
static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
2001-01-01 15:16:10 +00:00
unsigned int channel;
snd_pcm_t *slave = file->slave;
2001-02-05 09:35:17 +00:00
int err = _snd_pcm_hw_params(slave, params);
2001-01-01 15:16:10 +00:00
if (err < 0)
return err;
file->buffer_bytes = snd_pcm_frames_to_bytes(slave, slave->buffer_size);
file->wbuf_size = slave->buffer_size * 2;
file->wbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->wbuf_size);
2001-01-19 13:10:50 +00:00
assert(!file->wbuf);
2001-01-01 15:16:10 +00:00
file->wbuf = malloc(file->wbuf_size_bytes);
file->wbuf_areas = malloc(sizeof(*file->wbuf_areas) * slave->channels);
file->appl_ptr = file->file_ptr_bytes = 0;
for (channel = 0; channel < slave->channels; ++channel) {
snd_pcm_channel_area_t *a = &file->wbuf_areas[channel];
a->addr = file->wbuf;
a->first = slave->sample_bits * channel;
a->step = slave->frame_bits;
2001-01-01 15:16:10 +00:00
}
return 0;
2000-11-20 20:10:46 +00:00
}
2001-01-19 13:10:50 +00:00
static int snd_pcm_file_hw_free(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private;
if (file->wbuf) {
free(file->wbuf);
free(file->wbuf_areas);
file->wbuf = 0;
file->wbuf_areas = 0;
}
return snd_pcm_hw_free(file->slave);
}
2000-11-20 20:10:46 +00:00
static int snd_pcm_file_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_sw_params(file->slave, params);
}
static int snd_pcm_file_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
2000-09-24 09:57:26 +00:00
{
2001-01-01 15:16:10 +00:00
return 0;
2000-09-24 09:57:26 +00:00
}
2000-11-20 20:10:46 +00:00
static int snd_pcm_file_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
2000-09-24 09:57:26 +00:00
{
2001-01-01 15:16:10 +00:00
return 0;
2000-09-24 09:57:26 +00:00
}
2001-01-17 11:00:32 +00:00
static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private;
if (file->fname)
2001-01-17 11:00:32 +00:00
snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
2000-09-24 09:57:26 +00:00
else
2001-01-17 11:00:32 +00:00
snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
2000-11-20 20:10:46 +00:00
if (pcm->setup) {
2001-01-17 11:00:32 +00:00
snd_output_printf(out, "Its setup is:\n");
snd_pcm_dump_setup(pcm, out);
2000-09-24 09:57:26 +00:00
}
2001-01-17 11:00:32 +00:00
snd_output_printf(out, "Slave: ");
snd_pcm_dump(file->slave, out);
2000-09-24 09:57:26 +00:00
}
snd_pcm_ops_t snd_pcm_file_ops = {
2000-09-24 09:57:26 +00:00
close: snd_pcm_file_close,
info: snd_pcm_file_info,
2000-12-21 20:44:10 +00:00
hw_refine: snd_pcm_file_hw_refine,
2000-11-20 20:10:46 +00:00
hw_params: snd_pcm_file_hw_params,
2001-01-19 13:10:50 +00:00
hw_free: snd_pcm_file_hw_free,
2000-11-20 20:10:46 +00:00
sw_params: snd_pcm_file_sw_params,
2000-09-24 09:57:26 +00:00
channel_info: snd_pcm_file_channel_info,
dump: snd_pcm_file_dump,
nonblock: snd_pcm_file_nonblock,
async: snd_pcm_file_async,
mmap: snd_pcm_file_mmap,
munmap: snd_pcm_file_munmap,
2000-09-24 09:57:26 +00:00
};
snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
2000-09-24 09:57:26 +00:00
status: snd_pcm_file_status,
state: snd_pcm_file_state,
delay: snd_pcm_file_delay,
prepare: snd_pcm_file_prepare,
2000-11-24 17:08:03 +00:00
reset: snd_pcm_file_reset,
2000-09-24 09:57:26 +00:00
start: snd_pcm_file_start,
2000-10-02 06:59:59 +00:00
drop: snd_pcm_file_drop,
drain: snd_pcm_file_drain,
2000-09-24 09:57:26 +00:00
pause: snd_pcm_file_pause,
rewind: snd_pcm_file_rewind,
2000-09-24 09:57:26 +00:00
writei: snd_pcm_file_writei,
writen: snd_pcm_file_writen,
readi: snd_pcm_file_readi,
readn: snd_pcm_file_readn,
avail_update: snd_pcm_file_avail_update,
mmap_forward: snd_pcm_file_mmap_forward,
};
int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, const char *fname, int fd, const char *fmt, snd_pcm_t *slave, int close_slave)
2000-09-24 09:57:26 +00:00
{
snd_pcm_t *pcm;
2000-09-24 09:57:26 +00:00
snd_pcm_file_t *file;
2001-01-25 14:27:33 +00:00
snd_pcm_file_format_t format;
2000-11-20 20:10:46 +00:00
assert(pcmp);
2001-01-25 14:27:33 +00:00
if (fmt == NULL ||
strcmp(fmt, "raw") == 0)
format = SND_PCM_FILE_FORMAT_RAW;
else {
ERR("file format %s is unknown", fmt);
return -EINVAL;
}
2000-09-24 09:57:26 +00:00
if (fname) {
fd = open(fname, O_WRONLY|O_CREAT, 0666);
2000-10-14 19:43:14 +00:00
if (fd < 0) {
SYSERR("open %s failed", fname);
2000-09-24 09:57:26 +00:00
return -errno;
2000-10-14 19:43:14 +00:00
}
2000-09-24 09:57:26 +00:00
}
file = calloc(1, sizeof(snd_pcm_file_t));
if (!file) {
2000-11-20 20:10:46 +00:00
if (fname)
close(fd);
2000-09-24 09:57:26 +00:00
return -ENOMEM;
}
2000-11-20 20:10:46 +00:00
2000-09-24 09:57:26 +00:00
file->fname = fname;
file->fd = fd;
2001-01-25 14:27:33 +00:00
file->format = format;
2000-09-24 09:57:26 +00:00
file->slave = slave;
file->close_slave = close_slave;
pcm = calloc(1, sizeof(snd_pcm_t));
if (!pcm) {
2000-09-24 09:57:26 +00:00
free(file);
return -ENOMEM;
}
2000-10-10 09:11:07 +00:00
if (name)
pcm->name = strdup(name);
pcm->type = SND_PCM_TYPE_FILE;
pcm->stream = slave->stream;
pcm->mode = slave->mode;
pcm->ops = &snd_pcm_file_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_file_fast_ops;
pcm->fast_op_arg = pcm;
pcm->private = file;
pcm->poll_fd = slave->poll_fd;
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
*pcmp = pcm;
2000-09-24 09:57:26 +00:00
return 0;
}
int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
snd_config_t *conf,
snd_pcm_stream_t stream, int mode)
2000-09-24 09:57:26 +00:00
{
snd_config_iterator_t i;
const char *sname = NULL;
2000-09-24 09:57:26 +00:00
int err;
snd_pcm_t *spcm;
const char *fname = NULL;
const char *format = NULL;
2000-09-24 09:57:26 +00:00
long fd = -1;
snd_config_foreach(i, conf) {
snd_config_t *n = snd_config_entry(i);
if (strcmp(n->id, "comment") == 0)
continue;
if (strcmp(n->id, "type") == 0)
continue;
if (strcmp(n->id, "stream") == 0)
continue;
if (strcmp(n->id, "sname") == 0) {
err = snd_config_string_get(n, &sname);
2000-11-30 09:40:50 +00:00
if (err < 0) {
ERR("Invalid type for %s", n->id);
2000-09-24 09:57:26 +00:00
return -EINVAL;
2000-11-30 09:40:50 +00:00
}
2000-09-24 09:57:26 +00:00
continue;
}
2000-11-20 20:10:46 +00:00
if (strcmp(n->id, "format") == 0) {
err = snd_config_string_get(n, &format);
2000-11-30 09:40:50 +00:00
if (err < 0) {
ERR("Invalid type for %s", n->id);
2000-11-20 20:10:46 +00:00
return -EINVAL;
2000-11-30 09:40:50 +00:00
}
2000-11-20 20:10:46 +00:00
continue;
}
2000-09-24 09:57:26 +00:00
if (strcmp(n->id, "file") == 0) {
err = snd_config_string_get(n, &fname);
if (err < 0) {
err = snd_config_integer_get(n, &fd);
2000-11-30 09:40:50 +00:00
if (err < 0) {
ERR("Invalid type for %s", n->id);
2000-09-24 09:57:26 +00:00
return -EINVAL;
2000-11-30 09:40:50 +00:00
}
2000-09-24 09:57:26 +00:00
}
continue;
}
2000-11-30 09:40:50 +00:00
ERR("Unknown field %s", n->id);
2000-09-24 09:57:26 +00:00
return -EINVAL;
}
2000-11-30 09:40:50 +00:00
if (!sname) {
ERR("sname is not defined");
2000-09-24 09:57:26 +00:00
return -EINVAL;
2000-11-30 09:40:50 +00:00
}
if (!fname && fd < 0) {
ERR("file is not defined");
return -EINVAL;
}
2000-09-24 09:57:26 +00:00
if (fname) {
fname = strdup(fname);
if (!fname)
return -ENOMEM;
}
/* This is needed cause snd_config_update may destroy config */
sname = strdup(sname);
if (!sname)
return -ENOMEM;
err = snd_pcm_open(&spcm, sname, stream, mode);
free((void *) sname);
2000-09-24 09:57:26 +00:00
if (err < 0)
return err;
2000-11-20 20:10:46 +00:00
err = snd_pcm_file_open(pcmp, name, fname, fd, format, spcm, 1);
2000-09-24 09:57:26 +00:00
if (err < 0)
snd_pcm_close(spcm);
return err;
}