4 * \brief PCM File Plugin Interface
5 * \author Abramo Bagnara <abramo@alsa-project.org>
10 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "pcm_local.h"
34 #include "pcm_plugin.h"
37 /* entry for static linking */
38 const char *_snd_module_pcm_file = "";
43 /* keys to be replaced by real values in the filename */
44 #define LEADING_KEY '%' /* i.e. %r, %c, %b ... */
46 #define CHANNELS_KEY 'c'
47 #define BWIDTH_KEY 'b'
48 #define FORMAT_KEY 'f'
50 /* maximum length of a value */
51 #define VALUE_MAXLEN 64
53 typedef enum _snd_pcm_file_format {
54 SND_PCM_FILE_FORMAT_RAW,
55 SND_PCM_FILE_FORMAT_WAV
56 } snd_pcm_file_format_t;
58 /* WAV format chunk */
69 snd_pcm_generic_t gen;
78 snd_pcm_uframes_t appl_ptr;
79 snd_pcm_uframes_t file_ptr_bytes;
80 snd_pcm_uframes_t wbuf_size;
81 size_t wbuf_size_bytes;
82 size_t wbuf_used_bytes;
84 size_t rbuf_size_bytes;
85 size_t rbuf_used_bytes;
87 snd_pcm_channel_area_t *wbuf_areas;
89 struct wav_fmt wav_header;
93 #if __BYTE_ORDER == __LITTLE_ENDIAN
94 #define TO_LE32(x) (x)
95 #define TO_LE16(x) (x)
97 #define TO_LE32(x) bswap_32(x)
98 #define TO_LE16(x) bswap_16(x)
101 static int snd_pcm_file_append_value(char **string_p, char **index_ch_p,
102 int *len_p, const char *value)
104 char *string, *index_ch;
105 int index, len, value_len;
106 /* input pointer values */
108 string = *(string_p);
109 index_ch = *(index_ch_p);
111 value_len = strlen(value);
112 /* reallocation to accommodate the value */
113 index = index_ch - string;
115 string = realloc(string, len + 1);
118 index_ch = string + index;
119 /* concatenating the new value */
120 strcpy(index_ch, value);
121 index_ch += value_len;
124 *(string_p) = string;
125 *(index_ch_p) = index_ch;
129 static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
131 char value[VALUE_MAXLEN];
132 char *fname = file->fname;
133 char *new_fname = NULL;
134 char *old_last_ch, *old_index_ch, *new_index_ch;
135 int old_len, new_len, err;
137 snd_pcm_t *pcm = file->gen.slave;
139 /* we want to keep fname, const */
140 old_len = new_len = strlen(fname);
141 old_last_ch = fname + old_len - 1;
142 new_fname = malloc(new_len + 1);
146 old_index_ch = fname; /* first character of the old name */
147 new_index_ch = new_fname; /* first char of the new name */
149 while (old_index_ch <= old_last_ch) {
150 if (*(old_index_ch) == LEADING_KEY &&
151 old_index_ch != old_last_ch) {
152 /* is %, not last char, skipping and checking
154 switch (*(++old_index_ch)) {
156 snprintf(value, sizeof(value), "%d",
158 err = snd_pcm_file_append_value(&new_fname,
159 &new_index_ch, &new_len, value);
165 snprintf(value, sizeof(value), "%d",
167 err = snd_pcm_file_append_value(&new_fname,
168 &new_index_ch, &new_len, value);
174 snprintf(value, sizeof(value), "%d",
175 pcm->frame_bits/pcm->channels);
176 err = snd_pcm_file_append_value(&new_fname,
177 &new_index_ch, &new_len, value);
183 err = snd_pcm_file_append_value(&new_fname,
184 &new_index_ch, &new_len,
185 snd_pcm_format_name(pcm->format));
191 /* non-key char, just copying */
192 *(new_index_ch++) = *(old_index_ch);
197 /* plain copying, shifting both strings to next chars */
198 *(new_index_ch++) = *(old_index_ch++);
201 /* closing the new string */
202 *(new_index_ch) = '\0';
203 *(new_fname_p) = new_fname;
208 static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
212 /* fname can contain keys, generating final_fname */
213 err = snd_pcm_file_replace_fname(file, &(file->final_fname));
216 /*printf("DEBUG - original fname: %s, final fname: %s\n",
217 file->fname, file->final_fname);*/
219 if (file->final_fname[0] == '|') {
223 pipe = popen(file->final_fname + 1, "w");
225 SYSERR("running %s for writing failed",
232 fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC,
235 fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL,
238 char *tmpfname = NULL;
240 len = strlen(file->final_fname) + 6;
241 tmpfname = malloc(len);
244 for (idx = 1; idx < 10000; idx++) {
245 snprintf(tmpfname, len,
246 "%s.%04d", file->final_fname,
249 O_WRONLY|O_CREAT|O_EXCL,
252 free(file->final_fname);
253 file->final_fname = tmpfname;
258 SYSERR("open %s for writing failed",
270 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
272 fmt->fmt = TO_LE16(0x01);
273 fmt->chan = TO_LE16(pcm->channels);
274 fmt->rate = TO_LE32(pcm->rate);
275 fmt->bwidth = pcm->frame_bits / 8;
276 fmt->bps = fmt->bwidth * pcm->rate;
277 fmt->bits = snd_pcm_format_width(pcm->format);
278 fmt->bps = TO_LE32(fmt->bps);
279 fmt->bwidth = TO_LE16(fmt->bwidth);
280 fmt->bits = TO_LE16(fmt->bits);
283 static int write_wav_header(snd_pcm_t *pcm)
285 snd_pcm_file_t *file = pcm->private_data;
286 static const char header[] = {
293 static const char header2[] = {
298 setup_wav_header(pcm, &file->wav_header);
300 if (write(file->fd, header, sizeof(header)) != sizeof(header) ||
301 write(file->fd, &file->wav_header, sizeof(file->wav_header)) !=
302 sizeof(file->wav_header) ||
303 write(file->fd, header2, sizeof(header2)) != sizeof(header2)) {
305 SYSERR("Write error.\n");
311 /* fix up the length fields in WAV header */
312 static void fixup_wav_header(snd_pcm_t *pcm)
314 snd_pcm_file_t *file = pcm->private_data;
318 if (lseek(file->fd, 4, SEEK_SET) == 4) {
319 len = (file->filelen + 0x24) > 0x7fffffff ?
320 0x7fffffff : (int)(file->filelen + 0x24);
322 ret = write(file->fd, &len, 4);
327 if (lseek(file->fd, 0x28, SEEK_SET) == 0x28) {
328 len = file->filelen > 0x7fffffff ?
329 0x7fffffff : (int)file->filelen;
331 ret = write(file->fd, &len, 4);
336 #endif /* DOC_HIDDEN */
340 static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
342 snd_pcm_file_t *file = pcm->private_data;
343 assert(bytes <= file->wbuf_used_bytes);
345 if (file->format == SND_PCM_FILE_FORMAT_WAV &&
346 !file->wav_header.fmt) {
347 if (write_wav_header(pcm) < 0)
352 snd_pcm_sframes_t err;
354 size_t cont = file->wbuf_size_bytes - file->file_ptr_bytes;
357 err = write(file->fd, file->wbuf + file->file_ptr_bytes, n);
359 SYSERR("write failed");
363 file->wbuf_used_bytes -= err;
364 file->file_ptr_bytes += err;
365 if (file->file_ptr_bytes == file->wbuf_size_bytes)
366 file->file_ptr_bytes = 0;
367 file->filelen += err;
368 if ((snd_pcm_uframes_t)err != n)
373 static void snd_pcm_file_add_frames(snd_pcm_t *pcm,
374 const snd_pcm_channel_area_t *areas,
375 snd_pcm_uframes_t offset,
376 snd_pcm_uframes_t frames)
378 snd_pcm_file_t *file = pcm->private_data;
380 snd_pcm_uframes_t n = frames;
381 snd_pcm_uframes_t cont = file->wbuf_size - file->appl_ptr;
382 snd_pcm_uframes_t avail = file->wbuf_size - snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
387 snd_pcm_areas_copy(file->wbuf_areas, file->appl_ptr,
389 pcm->channels, n, pcm->format);
393 if (file->appl_ptr == file->wbuf_size)
395 file->wbuf_used_bytes += snd_pcm_frames_to_bytes(pcm, n);
396 if (file->wbuf_used_bytes > file->buffer_bytes)
397 snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes - file->buffer_bytes);
398 assert(file->wbuf_used_bytes < file->wbuf_size_bytes);
402 static int snd_pcm_file_close(snd_pcm_t *pcm)
404 snd_pcm_file_t *file = pcm->private_data;
406 if (file->wav_header.fmt)
407 fixup_wav_header(pcm);
408 free((void *)file->fname);
412 free((void *)file->ifname);
415 return snd_pcm_generic_close(pcm);
418 static int snd_pcm_file_reset(snd_pcm_t *pcm)
420 snd_pcm_file_t *file = pcm->private_data;
421 int err = snd_pcm_reset(file->gen.slave);
423 /* FIXME: Questionable here */
424 snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
425 assert(file->wbuf_used_bytes == 0);
430 static int snd_pcm_file_drop(snd_pcm_t *pcm)
432 snd_pcm_file_t *file = pcm->private_data;
433 int err = snd_pcm_drop(file->gen.slave);
435 /* FIXME: Questionable here */
436 snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
437 assert(file->wbuf_used_bytes == 0);
442 static int snd_pcm_file_drain(snd_pcm_t *pcm)
444 snd_pcm_file_t *file = pcm->private_data;
445 int err = snd_pcm_drain(file->gen.slave);
447 snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
448 assert(file->wbuf_used_bytes == 0);
453 static snd_pcm_sframes_t snd_pcm_file_rewindable(snd_pcm_t *pcm)
455 snd_pcm_file_t *file = pcm->private_data;
456 snd_pcm_sframes_t res = snd_pcm_rewindable(pcm);
457 snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
463 static snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
465 snd_pcm_file_t *file = pcm->private_data;
466 snd_pcm_sframes_t err;
469 n = snd_pcm_frames_to_bytes(pcm, frames);
470 if (n > file->wbuf_used_bytes)
471 frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
472 err = snd_pcm_rewind(file->gen.slave, frames);
474 file->appl_ptr = (file->appl_ptr - err + file->wbuf_size) % file->wbuf_size;
475 n = snd_pcm_frames_to_bytes(pcm, err);
476 file->wbuf_used_bytes -= n;
481 static snd_pcm_sframes_t snd_pcm_file_forwardable(snd_pcm_t *pcm)
483 snd_pcm_file_t *file = pcm->private_data;
484 snd_pcm_sframes_t res = snd_pcm_forwardable(pcm);
485 snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes);
491 static snd_pcm_sframes_t snd_pcm_file_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
493 snd_pcm_file_t *file = pcm->private_data;
494 snd_pcm_sframes_t err;
497 n = snd_pcm_frames_to_bytes(pcm, frames);
498 if (file->wbuf_used_bytes + n > file->wbuf_size_bytes)
499 frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes);
500 err = INTERNAL(snd_pcm_forward)(file->gen.slave, frames);
502 file->appl_ptr = (file->appl_ptr + err) % file->wbuf_size;
503 n = snd_pcm_frames_to_bytes(pcm, err);
504 file->wbuf_used_bytes += n;
509 static snd_pcm_sframes_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
511 snd_pcm_file_t *file = pcm->private_data;
512 snd_pcm_channel_area_t areas[pcm->channels];
513 snd_pcm_sframes_t n = snd_pcm_writei(file->gen.slave, buffer, size);
515 snd_pcm_areas_from_buf(pcm, areas, (void*) buffer);
516 snd_pcm_file_add_frames(pcm, areas, 0, n);
521 static snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
523 snd_pcm_file_t *file = pcm->private_data;
524 snd_pcm_channel_area_t areas[pcm->channels];
525 snd_pcm_sframes_t n = snd_pcm_writen(file->gen.slave, bufs, size);
527 snd_pcm_areas_from_bufs(pcm, areas, bufs);
528 snd_pcm_file_add_frames(pcm, areas, 0, n);
533 static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
535 snd_pcm_file_t *file = pcm->private_data;
536 snd_pcm_channel_area_t areas[pcm->channels];
539 n = snd_pcm_readi(file->gen.slave, buffer, size);
542 if (file->ifd >= 0) {
543 n = read(file->ifd, buffer, n * pcm->frame_bits / 8);
546 return n * 8 / pcm->frame_bits;
548 snd_pcm_areas_from_buf(pcm, areas, buffer);
549 snd_pcm_file_add_frames(pcm, areas, 0, n);
553 static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
555 snd_pcm_file_t *file = pcm->private_data;
556 snd_pcm_channel_area_t areas[pcm->channels];
559 if (file->ifd >= 0) {
560 SNDERR("DEBUG: Noninterleaved read not yet implemented.\n");
561 return 0; /* TODO: Noninterleaved read */
564 n = snd_pcm_readn(file->gen.slave, bufs, size);
566 snd_pcm_areas_from_bufs(pcm, areas, bufs);
567 snd_pcm_file_add_frames(pcm, areas, 0, n);
572 static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
573 snd_pcm_uframes_t offset,
574 snd_pcm_uframes_t size)
576 snd_pcm_file_t *file = pcm->private_data;
577 snd_pcm_uframes_t ofs;
578 snd_pcm_uframes_t siz = size;
579 const snd_pcm_channel_area_t *areas;
580 snd_pcm_sframes_t result;
582 snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz);
583 assert(ofs == offset && siz == size);
584 result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz);
586 snd_pcm_file_add_frames(pcm, areas, ofs, result);
590 static int snd_pcm_file_hw_free(snd_pcm_t *pcm)
592 snd_pcm_file_t *file = pcm->private_data;
594 free(file->wbuf_areas);
596 file->wbuf_areas = NULL;
597 return snd_pcm_hw_free(file->gen.slave);
600 static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
602 snd_pcm_file_t *file = pcm->private_data;
603 unsigned int channel;
604 snd_pcm_t *slave = file->gen.slave;
605 int err = _snd_pcm_hw_params(slave, params);
608 file->buffer_bytes = snd_pcm_frames_to_bytes(slave, slave->buffer_size);
609 file->wbuf_size = slave->buffer_size * 2;
610 file->wbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->wbuf_size);
611 file->wbuf_used_bytes = 0;
613 file->wbuf = malloc(file->wbuf_size_bytes);
614 if (file->wbuf == NULL) {
615 snd_pcm_file_hw_free(pcm);
618 file->wbuf_areas = malloc(sizeof(*file->wbuf_areas) * slave->channels);
619 if (file->wbuf_areas == NULL) {
620 snd_pcm_file_hw_free(pcm);
623 file->appl_ptr = file->file_ptr_bytes = 0;
624 for (channel = 0; channel < slave->channels; ++channel) {
625 snd_pcm_channel_area_t *a = &file->wbuf_areas[channel];
626 a->addr = file->wbuf;
627 a->first = slave->sample_bits * channel;
628 a->step = slave->frame_bits;
631 err = snd_pcm_file_open_output_file(file);
633 SYSERR("failed opening output file %s", file->fname);
640 static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
642 snd_pcm_file_t *file = pcm->private_data;
644 snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
646 snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
647 if (file->final_fname)
648 snd_output_printf(out, "Final file PCM (file=%s)\n",
652 snd_output_printf(out, "Its setup is:\n");
653 snd_pcm_dump_setup(pcm, out);
655 snd_output_printf(out, "Slave: ");
656 snd_pcm_dump(file->gen.slave, out);
659 static const snd_pcm_ops_t snd_pcm_file_ops = {
660 .close = snd_pcm_file_close,
661 .info = snd_pcm_generic_info,
662 .hw_refine = snd_pcm_generic_hw_refine,
663 .hw_params = snd_pcm_file_hw_params,
664 .hw_free = snd_pcm_file_hw_free,
665 .sw_params = snd_pcm_generic_sw_params,
666 .channel_info = snd_pcm_generic_channel_info,
667 .dump = snd_pcm_file_dump,
668 .nonblock = snd_pcm_generic_nonblock,
669 .async = snd_pcm_generic_async,
670 .mmap = snd_pcm_generic_mmap,
671 .munmap = snd_pcm_generic_munmap,
674 static const snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
675 .status = snd_pcm_generic_status,
676 .state = snd_pcm_generic_state,
677 .hwsync = snd_pcm_generic_hwsync,
678 .delay = snd_pcm_generic_delay,
679 .prepare = snd_pcm_generic_prepare,
680 .reset = snd_pcm_file_reset,
681 .start = snd_pcm_generic_start,
682 .drop = snd_pcm_file_drop,
683 .drain = snd_pcm_file_drain,
684 .pause = snd_pcm_generic_pause,
685 .rewindable = snd_pcm_file_rewindable,
686 .rewind = snd_pcm_file_rewind,
687 .forwardable = snd_pcm_file_forwardable,
688 .forward = snd_pcm_file_forward,
689 .resume = snd_pcm_generic_resume,
690 .link = snd_pcm_generic_link,
691 .link_slaves = snd_pcm_generic_link_slaves,
692 .unlink = snd_pcm_generic_unlink,
693 .writei = snd_pcm_file_writei,
694 .writen = snd_pcm_file_writen,
695 .readi = snd_pcm_file_readi,
696 .readn = snd_pcm_file_readn,
697 .avail_update = snd_pcm_generic_avail_update,
698 .mmap_commit = snd_pcm_file_mmap_commit,
699 .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
700 .poll_descriptors = snd_pcm_generic_poll_descriptors,
701 .poll_revents = snd_pcm_generic_poll_revents,
705 * \brief Creates a new File PCM
706 * \param pcmp Returns created PCM handle
707 * \param name Name of PCM
708 * \param fname Output filename (or NULL if file descriptor fd is available)
709 * \param fd Output file descriptor
710 * \param ifname Input filename (or NULL if file descriptor ifd is available)
711 * \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input
712 * redirection will be performed)
713 * \param trunc Truncate the file if it already exists
714 * \param fmt File format ("raw" or "wav" are available)
715 * \param perm File permission
716 * \param slave Slave PCM handle
717 * \param close_slave When set, the slave PCM handle is closed with copy PCM
718 * \retval zero on success otherwise a negative error code
719 * \warning Using of this function might be dangerous in the sense
720 * of compatibility reasons. The prototype might be freely
723 int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
724 const char *fname, int fd, const char *ifname, int ifd,
726 const char *fmt, int perm, snd_pcm_t *slave, int close_slave)
729 snd_pcm_file_t *file;
730 snd_pcm_file_format_t format;
731 struct timespec timespec;
736 strcmp(fmt, "raw") == 0)
737 format = SND_PCM_FILE_FORMAT_RAW;
738 else if (!strcmp(fmt, "wav"))
739 format = SND_PCM_FILE_FORMAT_WAV;
741 SNDERR("file format %s is unknown", fmt);
744 file = calloc(1, sizeof(snd_pcm_file_t));
749 /* opening output fname is delayed until writing,
750 when PCM params are known */
752 file->fname = strdup(fname);
757 ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */
759 SYSERR("open %s for reading failed", ifname);
763 file->ifname = strdup(ifname);
767 file->format = format;
768 file->gen.slave = slave;
769 file->gen.close_slave = close_slave;
771 err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode);
777 pcm->ops = &snd_pcm_file_ops;
778 pcm->fast_ops = &snd_pcm_file_fast_ops;
779 pcm->private_data = file;
780 pcm->poll_fd = slave->poll_fd;
781 pcm->poll_events = slave->poll_events;
782 pcm->mmap_shadow = 1;
783 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
784 pcm->monotonic = clock_gettime(CLOCK_MONOTONIC, ×pec) == 0;
788 snd_pcm_link_hw_ptr(pcm, slave);
789 snd_pcm_link_appl_ptr(pcm, slave);
794 /*! \page pcm_plugins
796 \section pcm_plugins_file Plugin: File
798 This plugin stores contents of a PCM stream to file or pipes the stream
799 to a command, and optionally uses an existing file as an input data source
800 (i.e., "virtual mic")
805 slave STR # Slave name
807 slave { # Slave definition
808 pcm STR # Slave PCM name
810 pcm { } # Slave PCM definition
812 file STR # Output filename (or shell command the stream
813 # will be piped to if STR starts with the pipe
815 # STR can contain format keys, replaced by
816 # real values corresponding to the stream:
817 # %r rate (replaced with: 48000)
818 # %c channels (replaced with: 2)
819 # %b bits per sample (replaced with: 16)
820 # %f sample format string
821 # (replaced with: S16_LE)
824 file INT # Output file descriptor number
825 infile STR # Input filename - only raw format
827 infile INT # Input file descriptor number
828 [format STR] # File format ("raw" or "wav")
829 [perm INT] # Output file permission (octal, def. 0600)
833 \subsection pcm_plugins_file_funcref Function reference
836 <LI>snd_pcm_file_open()
837 <LI>_snd_pcm_file_open()
843 * \brief Creates a new File PCM
844 * \param pcmp Returns created PCM handle
845 * \param name Name of PCM
846 * \param root Root configuration node
847 * \param conf Configuration node with File PCM description
848 * \param stream Stream type
849 * \param mode Stream mode
850 * \retval zero on success otherwise a negative error code
851 * \warning Using of this function might be dangerous in the sense
852 * of compatibility reasons. The prototype might be freely
855 int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
856 snd_config_t *root, snd_config_t *conf,
857 snd_pcm_stream_t stream, int mode)
859 snd_config_iterator_t i, next;
862 snd_config_t *slave = NULL, *sconf;
863 const char *fname = NULL, *ifname = NULL;
864 const char *format = NULL;
865 long fd = -1, ifd = -1, trunc = 1;
867 snd_config_for_each(i, next, conf) {
868 snd_config_t *n = snd_config_iterator_entry(i);
870 if (snd_config_get_id(n, &id) < 0)
872 if (snd_pcm_conf_generic_id(id))
874 if (strcmp(id, "slave") == 0) {
878 if (strcmp(id, "format") == 0) {
879 err = snd_config_get_string(n, &format);
881 SNDERR("Invalid type for %s", id);
886 if (strcmp(id, "file") == 0) {
887 err = snd_config_get_string(n, &fname);
889 err = snd_config_get_integer(n, &fd);
891 SNDERR("Invalid type for %s", id);
897 if (strcmp(id, "infile") == 0) {
898 err = snd_config_get_string(n, &ifname);
900 err = snd_config_get_integer(n, &ifd);
902 SNDERR("Invalid type for %s", id);
908 if (strcmp(id, "perm") == 0) {
909 err = snd_config_get_integer(n, &perm);
911 SNDERR("Invalid type for %s", id);
914 if ((perm & ~0777) != 0) {
915 SNDERR("The field perm must be a valid file permission");
920 if (strcmp(id, "truncate") == 0) {
921 err = snd_config_get_bool(n);
927 SNDERR("Unknown field %s", id);
933 if (snd_config_search(root, "defaults.pcm.file_format", &n) >= 0) {
934 err = snd_config_get_string(n, &format);
936 SNDERR("Invalid file format");
942 SNDERR("slave is not defined");
945 err = snd_pcm_slave_conf(root, slave, &sconf, 0);
948 if ((!fname || strlen(fname) == 0) && fd < 0 && !ifname) {
949 snd_config_delete(sconf);
950 SNDERR("file is not defined");
953 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
954 snd_config_delete(sconf);
957 err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd,
958 trunc, format, perm, spcm, 1);
964 SND_DLSYM_BUILD_VERSION(_snd_pcm_file_open, SND_PCM_DLSYM_VERSION);