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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #include "pcm_local.h"
33 #include "pcm_plugin.h"
36 /* entry for static linking */
37 const char *_snd_module_pcm_file = "";
42 /* keys to be replaced by real values in the filename */
43 #define LEADING_KEY '%' /* i.e. %r, %c, %b ... */
45 #define CHANNELS_KEY 'c'
46 #define BWIDTH_KEY 'b'
47 #define FORMAT_KEY 'f'
49 /* maximum length of a value */
50 #define VALUE_MAXLEN 64
52 typedef enum _snd_pcm_file_format {
53 SND_PCM_FILE_FORMAT_RAW,
54 SND_PCM_FILE_FORMAT_WAV
55 } snd_pcm_file_format_t;
57 /* WAV format chunk */
68 snd_pcm_generic_t gen;
77 snd_pcm_uframes_t appl_ptr;
78 snd_pcm_uframes_t file_ptr_bytes;
79 snd_pcm_uframes_t wbuf_size;
80 snd_pcm_uframes_t rbuf_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;
91 char ifmmap_overwritten;
94 #if __BYTE_ORDER == __LITTLE_ENDIAN
95 #define TO_LE32(x) (x)
96 #define TO_LE16(x) (x)
98 #define TO_LE32(x) bswap_32(x)
99 #define TO_LE16(x) bswap_16(x)
102 static int snd_pcm_file_append_value(char **string_p, char **index_ch_p,
103 int *len_p, const char *value)
105 char *string, *index_ch;
106 int index, len, value_len;
107 /* input pointer values */
109 string = *(string_p);
110 index_ch = *(index_ch_p);
112 value_len = strlen(value);
113 /* reallocation to accommodate the value */
114 index = index_ch - string;
116 string = realloc(string, len + 1);
119 index_ch = string + index;
120 /* concatenating the new value */
121 strcpy(index_ch, value);
122 index_ch += value_len;
125 *(string_p) = string;
126 *(index_ch_p) = index_ch;
130 static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
132 char value[VALUE_MAXLEN];
133 char *fname = file->fname;
134 char *new_fname = NULL;
135 char *old_last_ch, *old_index_ch, *new_index_ch;
136 int old_len, new_len, err;
138 snd_pcm_t *pcm = file->gen.slave;
140 /* we want to keep fname, const */
141 old_len = new_len = strlen(fname);
142 old_last_ch = fname + old_len - 1;
143 new_fname = malloc(new_len + 1);
147 old_index_ch = fname; /* first character of the old name */
148 new_index_ch = new_fname; /* first char of the new name */
150 while (old_index_ch <= old_last_ch) {
151 if (*(old_index_ch) == LEADING_KEY &&
152 old_index_ch != old_last_ch) {
153 /* is %, not last char, skipping and checking
155 switch (*(++old_index_ch)) {
157 snprintf(value, sizeof(value), "%d",
159 err = snd_pcm_file_append_value(&new_fname,
160 &new_index_ch, &new_len, value);
166 snprintf(value, sizeof(value), "%d",
168 err = snd_pcm_file_append_value(&new_fname,
169 &new_index_ch, &new_len, value);
175 snprintf(value, sizeof(value), "%d",
176 pcm->frame_bits/pcm->channels);
177 err = snd_pcm_file_append_value(&new_fname,
178 &new_index_ch, &new_len, value);
184 err = snd_pcm_file_append_value(&new_fname,
185 &new_index_ch, &new_len,
186 snd_pcm_format_name(pcm->format));
192 /* non-key char, just copying */
193 *(new_index_ch++) = *(old_index_ch);
198 /* plain copying, shifting both strings to next chars */
199 *(new_index_ch++) = *(old_index_ch++);
202 /* closing the new string */
203 *(new_index_ch) = '\0';
204 *(new_fname_p) = new_fname;
209 static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
213 /* fname can contain keys, generating final_fname */
214 err = snd_pcm_file_replace_fname(file, &(file->final_fname));
217 /*printf("DEBUG - original fname: %s, final fname: %s\n",
218 file->fname, file->final_fname);*/
220 if (file->final_fname[0] == '|') {
224 pipe = popen(file->final_fname + 1, "w");
226 SYSERR("running %s for writing failed",
230 fd = dup(fileno(pipe));
234 SYSERR("unable to dup pipe file handle for command %s",
240 fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC,
243 fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL,
246 char *tmpfname = NULL;
248 len = strlen(file->final_fname) + 6;
249 tmpfname = malloc(len);
252 for (idx = 1; idx < 10000; idx++) {
253 snprintf(tmpfname, len,
254 "%s.%04d", file->final_fname,
257 O_WRONLY|O_CREAT|O_EXCL,
260 free(file->final_fname);
261 file->final_fname = tmpfname;
266 SYSERR("open %s for writing failed",
278 /* fill areas with data from input file, return bytes red */
279 static int snd_pcm_file_areas_read_infile(snd_pcm_t *pcm,
280 const snd_pcm_channel_area_t *areas,
281 snd_pcm_uframes_t offset,
282 snd_pcm_uframes_t frames)
284 snd_pcm_file_t *file = pcm->private_data;
285 snd_pcm_channel_area_t areas_if[pcm->channels];
291 if (file->rbuf == NULL)
294 if (file->rbuf_size < frames) {
295 SYSERR("requested more frames than pcm buffer");
299 bytes = snd_pcm_frames_to_bytes(pcm, frames);
302 bytes = read(file->ifd, file->rbuf, bytes);
304 SYSERR("read from file failed, error: %d", bytes);
308 snd_pcm_areas_from_buf(pcm, areas_if, file->rbuf);
309 snd_pcm_areas_copy(areas, offset, areas_if, 0, pcm->channels, snd_pcm_bytes_to_frames(pcm, bytes), pcm->format);
314 static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
316 fmt->fmt = TO_LE16(0x01);
317 fmt->chan = TO_LE16(pcm->channels);
318 fmt->rate = TO_LE32(pcm->rate);
319 fmt->bwidth = pcm->frame_bits / 8;
320 fmt->bps = fmt->bwidth * pcm->rate;
321 fmt->bits = snd_pcm_format_width(pcm->format);
322 fmt->bps = TO_LE32(fmt->bps);
323 fmt->bwidth = TO_LE16(fmt->bwidth);
324 fmt->bits = TO_LE16(fmt->bits);
327 static int write_wav_header(snd_pcm_t *pcm)
329 snd_pcm_file_t *file = pcm->private_data;
330 static const char header[] = {
337 static const char header2[] = {
342 setup_wav_header(pcm, &file->wav_header);
344 if (write(file->fd, header, sizeof(header)) != sizeof(header) ||
345 write(file->fd, &file->wav_header, sizeof(file->wav_header)) !=
346 sizeof(file->wav_header) ||
347 write(file->fd, header2, sizeof(header2)) != sizeof(header2)) {
349 SYSERR("%s write header failed, file data may be corrupt", file->fname);
355 /* fix up the length fields in WAV header */
356 static void fixup_wav_header(snd_pcm_t *pcm)
358 snd_pcm_file_t *file = pcm->private_data;
362 if (lseek(file->fd, 4, SEEK_SET) == 4) {
363 len = (file->filelen + 0x24) > 0x7fffffff ?
364 0x7fffffff : (int)(file->filelen + 0x24);
366 ret = write(file->fd, &len, 4);
371 if (lseek(file->fd, 0x28, SEEK_SET) == 0x28) {
372 len = file->filelen > 0x7fffffff ?
373 0x7fffffff : (int)file->filelen;
375 ret = write(file->fd, &len, 4);
380 #endif /* DOC_HIDDEN */
384 /* return error code in case write failed */
385 static int snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
387 snd_pcm_file_t *file = pcm->private_data;
388 snd_pcm_sframes_t err = 0;
389 assert(bytes <= file->wbuf_used_bytes);
391 if (file->format == SND_PCM_FILE_FORMAT_WAV &&
392 !file->wav_header.fmt) {
393 err = write_wav_header(pcm);
400 size_t cont = file->wbuf_size_bytes - file->file_ptr_bytes;
403 err = write(file->fd, file->wbuf + file->file_ptr_bytes, n);
405 SYSERR("%s write failed, file data may be corrupt", file->fname);
409 file->wbuf_used_bytes -= err;
410 file->file_ptr_bytes += err;
411 if (file->file_ptr_bytes == file->wbuf_size_bytes)
412 file->file_ptr_bytes = 0;
413 file->filelen += err;
414 if ((snd_pcm_uframes_t)err != n)
420 static int snd_pcm_file_add_frames(snd_pcm_t *pcm,
421 const snd_pcm_channel_area_t *areas,
422 snd_pcm_uframes_t offset,
423 snd_pcm_uframes_t frames)
425 snd_pcm_file_t *file = pcm->private_data;
428 snd_pcm_uframes_t n = frames;
429 snd_pcm_uframes_t cont = file->wbuf_size - file->appl_ptr;
430 snd_pcm_uframes_t avail = file->wbuf_size - snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
435 snd_pcm_areas_copy(file->wbuf_areas, file->appl_ptr,
437 pcm->channels, n, pcm->format);
441 if (file->appl_ptr == file->wbuf_size)
443 file->wbuf_used_bytes += snd_pcm_frames_to_bytes(pcm, n);
444 if (file->wbuf_used_bytes > file->buffer_bytes) {
445 err = snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes - file->buffer_bytes);
449 assert(file->wbuf_used_bytes < file->wbuf_size_bytes);
454 static int snd_pcm_file_close(snd_pcm_t *pcm)
456 snd_pcm_file_t *file = pcm->private_data;
458 if (file->wav_header.fmt)
459 fixup_wav_header(pcm);
460 free((void *)file->fname);
466 free((void *)file->ifname);
469 return snd_pcm_generic_close(pcm);
472 static int snd_pcm_file_reset(snd_pcm_t *pcm)
474 snd_pcm_file_t *file = pcm->private_data;
475 int err = snd_pcm_reset(file->gen.slave);
477 /* FIXME: Questionable here */
478 snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
479 assert(file->wbuf_used_bytes == 0);
484 static int snd_pcm_file_drop(snd_pcm_t *pcm)
486 snd_pcm_file_t *file = pcm->private_data;
487 int err = snd_pcm_drop(file->gen.slave);
489 /* FIXME: Questionable here */
490 snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
491 assert(file->wbuf_used_bytes == 0);
497 static int snd_pcm_file_drain(snd_pcm_t *pcm)
499 snd_pcm_file_t *file = pcm->private_data;
500 int err = snd_pcm_drain(file->gen.slave);
503 snd_pcm_file_write_bytes(pcm, file->wbuf_used_bytes);
504 assert(file->wbuf_used_bytes == 0);
505 __snd_pcm_unlock(pcm);
510 static snd_pcm_sframes_t snd_pcm_file_rewindable(snd_pcm_t *pcm)
512 snd_pcm_file_t *file = pcm->private_data;
513 snd_pcm_sframes_t res = snd_pcm_rewindable(file->gen.slave);
514 snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
520 static snd_pcm_sframes_t snd_pcm_file_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
522 snd_pcm_file_t *file = pcm->private_data;
523 snd_pcm_sframes_t err;
526 n = snd_pcm_frames_to_bytes(pcm, frames);
527 if (n > file->wbuf_used_bytes)
528 frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_used_bytes);
529 err = snd_pcm_rewind(file->gen.slave, frames);
531 file->appl_ptr = (file->appl_ptr - err + file->wbuf_size) % file->wbuf_size;
532 n = snd_pcm_frames_to_bytes(pcm, err);
533 file->wbuf_used_bytes -= n;
538 static snd_pcm_sframes_t snd_pcm_file_forwardable(snd_pcm_t *pcm)
540 snd_pcm_file_t *file = pcm->private_data;
541 snd_pcm_sframes_t res = snd_pcm_forwardable(file->gen.slave);
542 snd_pcm_sframes_t n = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes);
548 static snd_pcm_sframes_t snd_pcm_file_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
550 snd_pcm_file_t *file = pcm->private_data;
551 snd_pcm_sframes_t err;
554 n = snd_pcm_frames_to_bytes(pcm, frames);
555 if (file->wbuf_used_bytes + n > file->wbuf_size_bytes)
556 frames = snd_pcm_bytes_to_frames(pcm, file->wbuf_size_bytes - file->wbuf_used_bytes);
557 err = INTERNAL(snd_pcm_forward)(file->gen.slave, frames);
559 file->appl_ptr = (file->appl_ptr + err) % file->wbuf_size;
560 n = snd_pcm_frames_to_bytes(pcm, err);
561 file->wbuf_used_bytes += n;
567 static snd_pcm_sframes_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
569 snd_pcm_file_t *file = pcm->private_data;
570 snd_pcm_channel_area_t areas[pcm->channels];
571 snd_pcm_sframes_t n = _snd_pcm_writei(file->gen.slave, buffer, size);
573 snd_pcm_areas_from_buf(pcm, areas, (void*) buffer);
575 snd_pcm_file_add_frames(pcm, areas, 0, n);
576 __snd_pcm_unlock(pcm);
582 static snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
584 snd_pcm_file_t *file = pcm->private_data;
585 snd_pcm_channel_area_t areas[pcm->channels];
586 snd_pcm_sframes_t n = _snd_pcm_writen(file->gen.slave, bufs, size);
588 snd_pcm_areas_from_bufs(pcm, areas, bufs);
590 snd_pcm_file_add_frames(pcm, areas, 0, n);
591 __snd_pcm_unlock(pcm);
597 static snd_pcm_sframes_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
599 snd_pcm_file_t *file = pcm->private_data;
600 snd_pcm_channel_area_t areas[pcm->channels];
601 snd_pcm_sframes_t frames;
603 frames = _snd_pcm_readi(file->gen.slave, buffer, size);
607 snd_pcm_areas_from_buf(pcm, areas, buffer);
608 snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
610 snd_pcm_file_add_frames(pcm, areas, 0, frames);
611 __snd_pcm_unlock(pcm);
617 static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
619 snd_pcm_file_t *file = pcm->private_data;
620 snd_pcm_channel_area_t areas[pcm->channels];
621 snd_pcm_sframes_t frames;
623 frames = _snd_pcm_readn(file->gen.slave, bufs, size);
627 snd_pcm_areas_from_bufs(pcm, areas, bufs);
628 snd_pcm_file_areas_read_infile(pcm, areas, 0, frames);
630 snd_pcm_file_add_frames(pcm, areas, 0, frames);
631 __snd_pcm_unlock(pcm);
636 static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
637 snd_pcm_uframes_t offset,
638 snd_pcm_uframes_t size)
640 snd_pcm_file_t *file = pcm->private_data;
641 snd_pcm_uframes_t ofs;
642 snd_pcm_uframes_t siz = size;
643 const snd_pcm_channel_area_t *areas;
644 snd_pcm_sframes_t result;
646 file->ifmmap_overwritten = 0;
648 result = snd_pcm_mmap_begin(file->gen.slave, &areas, &ofs, &siz);
650 assert(ofs == offset && siz == size);
651 result = snd_pcm_mmap_commit(file->gen.slave, ofs, siz);
653 snd_pcm_file_add_frames(pcm, areas, ofs, result);
658 static int snd_pcm_file_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
659 snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
661 snd_pcm_file_t *file = pcm->private_data;
664 result = snd_pcm_mmap_begin(file->gen.slave, areas, offset, frames);
668 if (pcm->stream != SND_PCM_STREAM_CAPTURE)
671 /* user may run mmap_begin without mmap_commit multiple times in row */
672 if (file->ifmmap_overwritten)
674 file->ifmmap_overwritten = 1;
676 snd_pcm_file_areas_read_infile(pcm, *areas, *offset, *frames);
681 static int snd_pcm_file_hw_free(snd_pcm_t *pcm)
683 snd_pcm_file_t *file = pcm->private_data;
685 free(file->wbuf_areas);
686 free(file->final_fname);
689 file->wbuf_areas = NULL;
690 file->final_fname = NULL;
692 return snd_pcm_hw_free(file->gen.slave);
695 static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
697 snd_pcm_file_t *file = pcm->private_data;
698 unsigned int channel;
699 snd_pcm_t *slave = file->gen.slave;
700 int err = _snd_pcm_hw_params_internal(slave, params);
703 file->buffer_bytes = snd_pcm_frames_to_bytes(slave, slave->buffer_size);
704 file->wbuf_size = slave->buffer_size * 2;
705 file->wbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->wbuf_size);
706 file->wbuf_used_bytes = 0;
707 file->ifmmap_overwritten = 0;
709 file->wbuf = malloc(file->wbuf_size_bytes);
710 if (file->wbuf == NULL) {
711 snd_pcm_file_hw_free(pcm);
714 file->wbuf_areas = malloc(sizeof(*file->wbuf_areas) * slave->channels);
715 if (file->wbuf_areas == NULL) {
716 snd_pcm_file_hw_free(pcm);
720 file->rbuf_size = slave->buffer_size;
721 file->rbuf_size_bytes = snd_pcm_frames_to_bytes(slave, file->rbuf_size);
722 file->rbuf_used_bytes = 0;
723 file->rbuf = malloc(file->rbuf_size_bytes);
724 if (file->rbuf == NULL) {
725 snd_pcm_file_hw_free(pcm);
728 file->appl_ptr = file->file_ptr_bytes = 0;
729 for (channel = 0; channel < slave->channels; ++channel) {
730 snd_pcm_channel_area_t *a = &file->wbuf_areas[channel];
731 a->addr = file->wbuf;
732 a->first = slave->sample_bits * channel;
733 a->step = slave->frame_bits;
736 err = snd_pcm_file_open_output_file(file);
738 SYSERR("failed opening output file %s", file->fname);
743 /* pointer may have changed - e.g if plug is used. */
744 snd_pcm_unlink_hw_ptr(pcm, file->gen.slave);
745 snd_pcm_unlink_appl_ptr(pcm, file->gen.slave);
747 snd_pcm_link_hw_ptr(pcm, file->gen.slave);
748 snd_pcm_link_appl_ptr(pcm, file->gen.slave);
753 static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
755 snd_pcm_file_t *file = pcm->private_data;
757 snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
759 snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
760 if (file->final_fname)
761 snd_output_printf(out, "Final file PCM (file=%s)\n",
765 snd_output_printf(out, "Its setup is:\n");
766 snd_pcm_dump_setup(pcm, out);
768 snd_output_printf(out, "Slave: ");
769 snd_pcm_dump(file->gen.slave, out);
772 static const snd_pcm_ops_t snd_pcm_file_ops = {
773 .close = snd_pcm_file_close,
774 .info = snd_pcm_generic_info,
775 .hw_refine = snd_pcm_generic_hw_refine,
776 .hw_params = snd_pcm_file_hw_params,
777 .hw_free = snd_pcm_file_hw_free,
778 .sw_params = snd_pcm_generic_sw_params,
779 .channel_info = snd_pcm_generic_channel_info,
780 .dump = snd_pcm_file_dump,
781 .nonblock = snd_pcm_generic_nonblock,
782 .async = snd_pcm_generic_async,
783 .mmap = snd_pcm_generic_mmap,
784 .munmap = snd_pcm_generic_munmap,
785 .query_chmaps = snd_pcm_generic_query_chmaps,
786 .get_chmap = snd_pcm_generic_get_chmap,
787 .set_chmap = snd_pcm_generic_set_chmap,
790 static const snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
791 .status = snd_pcm_generic_status,
792 .state = snd_pcm_generic_state,
793 .hwsync = snd_pcm_generic_hwsync,
794 .delay = snd_pcm_generic_delay,
795 .prepare = snd_pcm_generic_prepare,
796 .reset = snd_pcm_file_reset,
797 .start = snd_pcm_generic_start,
798 .drop = snd_pcm_file_drop,
799 .drain = snd_pcm_file_drain,
800 .pause = snd_pcm_generic_pause,
801 .rewindable = snd_pcm_file_rewindable,
802 .rewind = snd_pcm_file_rewind,
803 .forwardable = snd_pcm_file_forwardable,
804 .forward = snd_pcm_file_forward,
805 .resume = snd_pcm_generic_resume,
806 .link = snd_pcm_generic_link,
807 .link_slaves = snd_pcm_generic_link_slaves,
808 .unlink = snd_pcm_generic_unlink,
809 .writei = snd_pcm_file_writei,
810 .writen = snd_pcm_file_writen,
811 .readi = snd_pcm_file_readi,
812 .readn = snd_pcm_file_readn,
813 .avail_update = snd_pcm_generic_avail_update,
814 .mmap_commit = snd_pcm_file_mmap_commit,
815 .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
816 .poll_descriptors = snd_pcm_generic_poll_descriptors,
817 .poll_revents = snd_pcm_generic_poll_revents,
818 .htimestamp = snd_pcm_generic_htimestamp,
819 .mmap_begin = snd_pcm_file_mmap_begin,
823 * \brief Creates a new File PCM
824 * \param pcmp Returns created PCM handle
825 * \param name Name of PCM
826 * \param fname Output filename (or NULL if file descriptor fd is available)
827 * \param fd Output file descriptor
828 * \param ifname Input filename (or NULL if file descriptor ifd is available)
829 * \param ifd Input file descriptor (if (ifd < 0) && (ifname == NULL), no input
830 * redirection will be performed)
831 * \param trunc Truncate the file if it already exists
832 * \param fmt File format ("raw" or "wav" are available)
833 * \param perm File permission
834 * \param slave Slave PCM handle
835 * \param close_slave When set, the slave PCM handle is closed with copy PCM
836 * \param stream the direction of PCM stream
837 * \retval zero on success otherwise a negative error code
838 * \warning Using of this function might be dangerous in the sense
839 * of compatibility reasons. The prototype might be freely
842 int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
843 const char *fname, int fd, const char *ifname, int ifd,
845 const char *fmt, int perm, snd_pcm_t *slave, int close_slave,
846 snd_pcm_stream_t stream)
849 snd_pcm_file_t *file;
850 snd_pcm_file_format_t format;
851 struct timespec timespec;
856 strcmp(fmt, "raw") == 0)
857 format = SND_PCM_FILE_FORMAT_RAW;
858 else if (!strcmp(fmt, "wav"))
859 format = SND_PCM_FILE_FORMAT_WAV;
861 SNDERR("file format %s is unknown", fmt);
864 file = calloc(1, sizeof(snd_pcm_file_t));
869 /* opening output fname is delayed until writing,
870 when PCM params are known */
872 file->fname = strdup(fname);
876 if (ifname && (stream == SND_PCM_STREAM_CAPTURE)) {
877 ifd = open(ifname, O_RDONLY); /* TODO: mind blocking mode */
879 SYSERR("open %s for reading failed", ifname);
884 file->ifname = strdup(ifname);
888 file->format = format;
889 file->gen.slave = slave;
890 file->gen.close_slave = close_slave;
892 err = snd_pcm_new(&pcm, SND_PCM_TYPE_FILE, name, slave->stream, slave->mode);
899 pcm->ops = &snd_pcm_file_ops;
900 pcm->fast_ops = &snd_pcm_file_fast_ops;
901 pcm->private_data = file;
902 pcm->poll_fd = slave->poll_fd;
903 pcm->poll_events = slave->poll_events;
904 pcm->mmap_shadow = 1;
905 pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
906 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
907 if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0)
908 pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
910 pcm->stream = stream;
911 snd_pcm_link_hw_ptr(pcm, slave);
912 snd_pcm_link_appl_ptr(pcm, slave);
917 /*! \page pcm_plugins
919 \section pcm_plugins_file Plugin: File
921 This plugin stores contents of a PCM stream to file or pipes the stream
922 to a command, and optionally uses an existing file as an input data source
923 (i.e., "virtual mic")
928 slave STR # Slave name
930 slave { # Slave definition
931 pcm STR # Slave PCM name
933 pcm { } # Slave PCM definition
935 file STR # Output filename (or shell command the stream
936 # will be piped to if STR starts with the pipe
938 # STR can contain format keys, replaced by
939 # real values corresponding to the stream:
940 # %r rate (replaced with: 48000)
941 # %c channels (replaced with: 2)
942 # %b bits per sample (replaced with: 16)
943 # %f sample format string
944 # (replaced with: S16_LE)
947 file INT # Output file descriptor number
948 infile STR # Input filename - only raw format
950 infile INT # Input file descriptor number
951 [format STR] # File format ("raw" or "wav")
952 [perm INT] # Output file permission (octal, def. 0600)
956 \subsection pcm_plugins_file_funcref Function reference
959 <LI>snd_pcm_file_open()
960 <LI>_snd_pcm_file_open()
966 * \brief Creates a new File PCM
967 * \param pcmp Returns created PCM handle
968 * \param name Name of PCM
969 * \param root Root configuration node
970 * \param conf Configuration node with File PCM description
971 * \param stream Stream type
972 * \param mode Stream mode
973 * \retval zero on success otherwise a negative error code
974 * \warning Using of this function might be dangerous in the sense
975 * of compatibility reasons. The prototype might be freely
978 int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
979 snd_config_t *root, snd_config_t *conf,
980 snd_pcm_stream_t stream, int mode)
982 snd_config_iterator_t i, next;
985 snd_config_t *slave = NULL, *sconf;
986 const char *fname = NULL, *ifname = NULL;
987 const char *format = NULL;
988 long fd = -1, ifd = -1, trunc = 1;
990 snd_config_for_each(i, next, conf) {
991 snd_config_t *n = snd_config_iterator_entry(i);
993 if (snd_config_get_id(n, &id) < 0)
995 if (snd_pcm_conf_generic_id(id))
997 if (strcmp(id, "slave") == 0) {
1001 if (strcmp(id, "format") == 0) {
1002 err = snd_config_get_string(n, &format);
1004 SNDERR("Invalid type for %s", id);
1009 if (strcmp(id, "file") == 0) {
1010 err = snd_config_get_string(n, &fname);
1012 err = snd_config_get_integer(n, &fd);
1014 SNDERR("Invalid type for %s", id);
1020 if (strcmp(id, "infile") == 0) {
1021 err = snd_config_get_string(n, &ifname);
1023 err = snd_config_get_integer(n, &ifd);
1025 SNDERR("Invalid type for %s", id);
1031 if (strcmp(id, "perm") == 0) {
1032 err = snd_config_get_integer(n, &perm);
1034 SNDERR("Invalid type for %s", id);
1037 if ((perm & ~0777) != 0) {
1038 SNDERR("The field perm must be a valid file permission");
1043 if (strcmp(id, "truncate") == 0) {
1044 err = snd_config_get_bool(n);
1050 SNDERR("Unknown field %s", id);
1056 if (snd_config_search(root, "defaults.pcm.file_format", &n) >= 0) {
1057 err = snd_config_get_string(n, &format);
1059 SNDERR("Invalid file format");
1065 SNDERR("slave is not defined");
1068 err = snd_pcm_slave_conf(root, slave, &sconf, 0);
1071 if ((!fname || strlen(fname) == 0) && fd < 0) {
1072 snd_config_delete(sconf);
1073 SNDERR("file is not defined");
1076 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
1077 snd_config_delete(sconf);
1080 err = snd_pcm_file_open(pcmp, name, fname, fd, ifname, ifd,
1081 trunc, format, perm, spcm, 1, stream);
1083 snd_pcm_close(spcm);
1087 SND_DLSYM_BUILD_VERSION(_snd_pcm_file_open, SND_PCM_DLSYM_VERSION);