alsa-lib/src/pcm/pcm_file.c

620 lines
17 KiB
C
Raw Normal View History

2002-01-16 16:42:40 +00:00
/**
* \file pcm/pcm_file.c
* \ingroup PCM_Plugins
* \brief PCM File Plugin Interface
* \author Abramo Bagnara <abramo@alsa-project.org>
* \date 2000-2001
*/
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 Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
2000-09-24 09:57:26 +00:00
* 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 Lesser General Public License for more details.
2000-09-24 09:57:26 +00:00
*
* You should have received a copy of the GNU Lesser General Public
2000-09-24 09:57:26 +00:00
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2000-09-24 09:57:26 +00:00
*
*/
#include <byteswap.h>
#include <ctype.h>
2000-09-24 09:57:26 +00:00
#include "pcm_local.h"
#include "pcm_plugin.h"
2001-10-24 14:14:11 +00:00
#ifndef PIC
/* entry for static linking */
const char *_snd_module_pcm_file = "";
#endif
2002-01-16 16:42:40 +00:00
#ifndef DOC_HIDDEN
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_generic_t gen;
2001-03-29 17:50:28 +00:00
char *fname;
2000-09-24 09:57:26 +00:00
int fd;
char *ifname;
int ifd;
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;
size_t rbuf_size_bytes;
size_t rbuf_used_bytes;
char *rbuf;
2001-01-01 15:16:10 +00:00
snd_pcm_channel_area_t *wbuf_areas;
size_t buffer_bytes;
2000-09-24 09:57:26 +00:00
} snd_pcm_file_t;
2002-01-16 16:42:40 +00:00
#endif /* DOC_HIDDEN */
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_data;
2001-01-01 15:16:10 +00:00
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_data;
2001-01-01 15:16:10 +00:00
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;
offset += n;
2001-01-01 15:16:10 +00:00
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_data;
2000-09-24 09:57:26 +00:00
if (file->fname) {
free((void *)file->fname);
2000-09-24 09:57:26 +00:00
close(file->fd);
}
if (file->ifname) {
free((void *)file->ifname);
close(file->ifd);
}
return snd_pcm_generic_close(pcm);
2000-09-24 09:57:26 +00:00
}
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_data;
int err = snd_pcm_reset(file->gen.slave);
2001-01-01 15:16:10 +00:00
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-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_data;
int err = snd_pcm_drop(file->gen.slave);
2001-01-01 15:16:10 +00:00
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_data;
int err = snd_pcm_drain(file->gen.slave);
2001-01-01 15:16:10 +00:00
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 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_data;
snd_pcm_sframes_t err;
snd_pcm_uframes_t n;
n = snd_pcm_frames_to_bytes(pcm, frames);
if (n > file->wbuf_used_bytes)
frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
err = snd_pcm_rewind(file->gen.slave, frames);
2001-01-01 15:16:10 +00:00
if (err > 0) {
file->appl_ptr = (file->appl_ptr - err + file->wbuf_size) % file->wbuf_size;
n = snd_pcm_frames_to_bytes(pcm, err);
2001-01-01 15:16:10 +00:00
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_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
snd_pcm_file_t *file = pcm->private_data;
snd_pcm_sframes_t err;
snd_pcm_uframes_t n;
n = snd_pcm_frames_to_bytes(pcm, frames);
if (file->wbuf_used_bytes + n > file->wbuf_size_bytes)
frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes);
err = INTERNAL(snd_pcm_forward)(file->gen.slave, frames);
if (err > 0) {
file->appl_ptr = (file->appl_ptr + err) % file->wbuf_size;
n = snd_pcm_frames_to_bytes(pcm, err);
file->wbuf_used_bytes += n;
}
return err;
}
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_data;
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->gen.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_data;
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->gen.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_data;
2001-01-01 15:16:10 +00:00
snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_sframes_t n /* , bytesn */;
if (file->ifd >= 0) {
n = /* bytesn = */ read(file->ifd, buffer, size * pcm->frame_bits / 8);
if (n > 0)
n = n * 8 / pcm->frame_bits;
/* SNDERR("DEBUG: channels = %d, sample_bits = %d, frame_bits = %d, bytes = %d, frames = %d",
pcm->channels, pcm->sample_bits, pcm->frame_bits, bytesn, n); */
} else {
n = snd_pcm_readi(file->gen.slave, buffer, size);
if (n > 0) {
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_data;
2000-11-20 20:10:46 +00:00
snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_sframes_t n;
if (file->ifd >= 0) {
SNDERR("DEBUG: Noninterleaved read not yet implemented.\n");
return 0; /* TODO: Noninterleaved read */
}
n = snd_pcm_readn(file->gen.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_commit(snd_pcm_t *pcm,
snd_pcm_uframes_t offset,
snd_pcm_uframes_t size)
2000-09-24 09:57:26 +00:00
{
snd_pcm_file_t *file = pcm->private_data;
2001-04-13 15:40:53 +00:00
snd_pcm_uframes_t ofs;
snd_pcm_uframes_t siz = size;
const snd_pcm_channel_area_t *areas;
snd_pcm_sframes_t result;
snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz);
2001-04-13 15:40:53 +00:00
assert(ofs == offset && siz == size);
result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz);
if (result > 0)
snd_pcm_file_add_frames(pcm, areas, ofs, result);
return result;
2000-09-24 09:57:26 +00:00
}
static int snd_pcm_file_hw_free(snd_pcm_t *pcm)
{
snd_pcm_file_t *file = pcm->private_data;
free(file->wbuf);
free(file->wbuf_areas);
file->wbuf = NULL;
file->wbuf_areas = NULL;
return snd_pcm_hw_free(file->gen.slave);
}
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_data;
2001-01-01 15:16:10 +00:00
unsigned int channel;
snd_pcm_t *slave = file->gen.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);
file->wbuf_used_bytes = 0;
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);
if (file->wbuf == NULL) {
snd_pcm_file_hw_free(pcm);
return -ENOMEM;
}
2001-01-01 15:16:10 +00:00
file->wbuf_areas = malloc(sizeof(*file->wbuf_areas) * slave->channels);
if (file->wbuf_areas == NULL) {
snd_pcm_file_hw_free(pcm);
return -ENOMEM;
}
2001-01-01 15:16:10 +00:00
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-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_data;
2000-09-24 09:57:26 +00:00
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->gen.slave, out);
2000-09-24 09:57:26 +00:00
}
2002-01-16 16:42:40 +00:00
static snd_pcm_ops_t snd_pcm_file_ops = {
.close = snd_pcm_file_close,
.info = snd_pcm_generic_info,
.hw_refine = snd_pcm_generic_hw_refine,
.hw_params = snd_pcm_file_hw_params,
.hw_free = snd_pcm_file_hw_free,
.sw_params = snd_pcm_generic_sw_params,
.channel_info = snd_pcm_generic_channel_info,
.dump = snd_pcm_file_dump,
.nonblock = snd_pcm_generic_nonblock,
.async = snd_pcm_generic_async,
.mmap = snd_pcm_generic_mmap,
.munmap = snd_pcm_generic_munmap,
2000-09-24 09:57:26 +00:00
};
2002-01-16 16:42:40 +00:00
static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
.status = snd_pcm_generic_status,
.state = snd_pcm_generic_state,
.hwsync = snd_pcm_generic_hwsync,
.delay = snd_pcm_generic_delay,
.prepare = snd_pcm_generic_prepare,
.reset = snd_pcm_file_reset,
.start = snd_pcm_generic_start,
.drop = snd_pcm_file_drop,
.drain = snd_pcm_file_drain,
.pause = snd_pcm_generic_pause,
.rewind = snd_pcm_file_rewind,
.forward = snd_pcm_file_forward,
.resume = snd_pcm_generic_resume,
.link = snd_pcm_generic_link,
.link_slaves = snd_pcm_generic_link_slaves,
.unlink = snd_pcm_generic_unlink,
.writei = snd_pcm_file_writei,
.writen = snd_pcm_file_writen,
.readi = snd_pcm_file_readi,
.readn = snd_pcm_file_readn,
.avail_update = snd_pcm_generic_avail_update,
.mmap_commit = snd_pcm_file_mmap_commit,
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
.poll_descriptors = snd_pcm_generic_poll_descriptors,
.poll_revents = snd_pcm_generic_poll_revents,
2000-09-24 09:57:26 +00:00
};
2002-01-16 16:42:40 +00:00
/**
* \brief Creates a new File PCM
* \param pcmp Returns created PCM handle
* \param name Name of PCM
* \param fname Output filename (or NULL if file descriptor fd is available)
* \param fd Output file descriptor
* \param ifname Input filename (or NULL if file descriptor ifd is available)
* \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input
* redirection will be performed)
2002-01-16 16:42:40 +00:00
* \param fmt File format ("raw" is supported only)
* \param perm File permission
2002-01-16 16:42:40 +00:00
* \param slave Slave PCM handle
* \param close_slave When set, the slave PCM handle is closed with copy PCM
* \retval zero on success otherwise a negative error code
* \warning Using of this function might be dangerous in the sense
* of compatibility reasons. The prototype might be freely
* changed in future.
*/
int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
const char *fname, int fd, const char *ifname, int ifd,
const char *fmt, int perm, 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;
int err;
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 {
SNDERR("file format %s is unknown", fmt);
2001-01-25 14:27:33 +00:00
return -EINVAL;
}
2000-09-24 09:57:26 +00:00
if (fname) {
fd = open(fname, O_WRONLY|O_CREAT, perm);
2000-10-14 19:43:14 +00:00
if (fd < 0) {
SYSERR("open %s for writing 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;
}
if (ifname) {
ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */
if (ifd < 0) {
SYSERR("open %s for reading failed", ifname);
if (fname)
close(fd);
return -errno;
}
}
2001-06-06 14:19:40 +00:00
if (fname)
file->fname = strdup(fname);
if (ifname)
file->ifname = strdup(ifname);
2000-09-24 09:57:26 +00:00
file->fd = fd;
file->ifd = ifd;
2001-01-25 14:27:33 +00:00
file->format = format;
file->gen.slave = slave;
file->gen.close_slave = close_slave;
2000-09-24 09:57:26 +00:00
err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode);
if (err < 0) {
free(file->fname);
2000-09-24 09:57:26 +00:00
free(file);
return err;
2000-09-24 09:57:26 +00:00
}
pcm->ops = &snd_pcm_file_ops;
pcm->fast_ops = &snd_pcm_file_fast_ops;
pcm->private_data = file;
pcm->poll_fd = slave->poll_fd;
pcm->poll_events = slave->poll_events;
pcm->mmap_shadow = 1;
2008-01-09 11:13:34 +01:00
pcm->monotonic = 1;
snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
2000-09-24 09:57:26 +00:00
return 0;
}
2002-01-16 16:42:40 +00:00
/*! \page pcm_plugins
\section pcm_plugins_file Plugin: File
This plugin stores contents of a PCM stream to file, and optionally
uses an existing file as an input data source (i.e., "virtual mic")
2002-01-16 16:42:40 +00:00
\code
pcm.name {
type file # File PCM
slave STR # Slave name
# or
slave { # Slave definition
pcm STR # Slave PCM name
# or
pcm { } # Slave PCM definition
}
file STR # Output filename
or
file INT # Output file descriptor number
infile STR # Input filename
2002-01-16 16:42:40 +00:00
or
infile INT # Input file descriptor number
2002-01-16 16:42:40 +00:00
[format STR] # File format (only "raw" at the moment)
[perm INT] # Output file permission (octal, def. 0600)
2002-01-16 16:42:40 +00:00
}
\endcode
\subsection pcm_plugins_file_funcref Function reference
<UL>
<LI>snd_pcm_file_open()
<LI>_snd_pcm_file_open()
</UL>
*/
/**
* \brief Creates a new File PCM
* \param pcmp Returns created PCM handle
* \param name Name of PCM
* \param root Root configuration node
* \param conf Configuration node with File PCM description
* \param stream Stream type
* \param mode Stream mode
* \retval zero on success otherwise a negative error code
* \warning Using of this function might be dangerous in the sense
* of compatibility reasons. The prototype might be freely
* changed in future.
*/
int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
snd_config_t *root, snd_config_t *conf,
snd_pcm_stream_t stream, int mode)
2000-09-24 09:57:26 +00:00
{
snd_config_iterator_t i, next;
2000-09-24 09:57:26 +00:00
int err;
snd_pcm_t *spcm;
snd_config_t *slave = NULL, *sconf;
const char *fname = NULL, *ifname = NULL;
const char *format = NULL;
long fd = -1, ifd = -1;
long perm = 0600;
snd_config_for_each(i, next, conf) {
2001-02-07 11:34:33 +00:00
snd_config_t *n = snd_config_iterator_entry(i);
const char *id;
if (snd_config_get_id(n, &id) < 0)
continue;
if (snd_pcm_conf_generic_id(id))
2000-09-24 09:57:26 +00:00
continue;
2001-03-17 16:34:43 +00:00
if (strcmp(id, "slave") == 0) {
slave = n;
2000-09-24 09:57:26 +00:00
continue;
}
2001-02-07 11:34:33 +00:00
if (strcmp(id, "format") == 0) {
err = snd_config_get_string(n, &format);
2000-11-30 09:40:50 +00:00
if (err < 0) {
SNDERR("Invalid type for %s", 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;
}
2001-02-07 11:34:33 +00:00
if (strcmp(id, "file") == 0) {
err = snd_config_get_string(n, &fname);
2000-09-24 09:57:26 +00:00
if (err < 0) {
2001-02-07 11:34:33 +00:00
err = snd_config_get_integer(n, &fd);
2000-11-30 09:40:50 +00:00
if (err < 0) {
SNDERR("Invalid type for %s", 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;
}
if (strcmp(id, "infile") == 0) {
err = snd_config_get_string(n, &ifname);
if (err < 0) {
err = snd_config_get_integer(n, &ifd);
if (err < 0) {
SNDERR("Invalid type for %s", id);
return -EINVAL;
}
}
continue;
}
if (strcmp(id, "perm") == 0) {
err = snd_config_get_integer(n, &perm);
if (err < 0) {
SNDERR("Invalid type for %s", id);
return err;
}
if ((perm & ~0777) != 0) {
SNDERR("The field perm must be a valid file permission");
return -EINVAL;
}
continue;
}
SNDERR("Unknown field %s", id);
2000-09-24 09:57:26 +00:00
return -EINVAL;
}
2001-03-17 16:34:43 +00:00
if (!slave) {
SNDERR("slave is not defined");
2000-09-24 09:57:26 +00:00
return -EINVAL;
2000-11-30 09:40:50 +00:00
}
err = snd_pcm_slave_conf(root, slave, &sconf, 0);
2001-03-17 16:34:43 +00:00
if (err < 0)
return err;
2000-11-30 09:40:50 +00:00
if (!fname && fd < 0) {
snd_config_delete(sconf);
SNDERR("file is not defined");
2000-11-30 09:40:50 +00:00
return -EINVAL;
}
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
snd_config_delete(sconf);
2000-09-24 09:57:26 +00:00
if (err < 0)
return err;
err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd, format, perm, spcm, 1);
2000-09-24 09:57:26 +00:00
if (err < 0)
snd_pcm_close(spcm);
return err;
}
2002-01-16 16:42:40 +00:00
#ifndef DOC_HIDDEN
2001-10-24 14:14:11 +00:00
SND_DLSYM_BUILD_VERSION(_snd_pcm_file_open, SND_PCM_DLSYM_VERSION);
2002-01-16 16:42:40 +00:00
#endif