~ubuntu-branches/ubuntu/maverick/alsa-lib/maverick-proposed

« back to all changes in this revision

Viewing changes to src/pcm/pcm_file.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-05-26 08:57:32 UTC
  • mfrom: (1.1.11 upstream) (2.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20090526085732-wuuhzl1y30f1fnyd
Tags: 1.0.20-1ubuntu1
* Merge from debian unstable, remaining changes:
  - debian/rules:
    + Install into /usr/lib32/ on amd64 for the lib32asound2 package
    + Don't bail when removing include/alsa
  - debian/control: Add Vcs-Bzr URI
  - Add configuration files for bluetooth/bluez-alsa and pulseaudio
  - debian/libasound2.install: Ship smixer plugins for native and bi-arch
    packages
  - drop libcxxtools-dev build dependency, its in universe

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <endian.h>
30
30
#include <byteswap.h>
31
31
#include <ctype.h>
 
32
#include <string.h>
32
33
#include "pcm_local.h"
33
34
#include "pcm_plugin.h"
34
35
 
39
40
 
40
41
#ifndef DOC_HIDDEN
41
42
 
 
43
/* keys to be replaced by real values in the filename */
 
44
#define LEADING_KEY     '%'     /* i.e. %r, %c, %b ... */
 
45
#define RATE_KEY        'r'
 
46
#define CHANNELS_KEY    'c'
 
47
#define BWIDTH_KEY      'b'
 
48
#define FORMAT_KEY      'f'
 
49
 
 
50
/* maximum length of a value */
 
51
#define VALUE_MAXLEN    64
 
52
 
42
53
typedef enum _snd_pcm_file_format {
43
54
        SND_PCM_FILE_FORMAT_RAW,
44
55
        SND_PCM_FILE_FORMAT_WAV
57
68
typedef struct {
58
69
        snd_pcm_generic_t gen;
59
70
        char *fname;
 
71
        char *final_fname;
 
72
        int trunc;
 
73
        int perm;
60
74
        int fd;
61
75
        char *ifname;
62
76
        int ifd;
84
98
#define TO_LE16(x)      bswap_16(x)
85
99
#endif
86
100
 
 
101
static int snd_pcm_file_append_value(char **string_p, char **index_ch_p,
 
102
                int *len_p, const char *value)
 
103
{
 
104
        char *string, *index_ch;
 
105
        int index, len, value_len;
 
106
        /* input pointer values */
 
107
        len = *(len_p);
 
108
        string = *(string_p);
 
109
        index_ch = *(index_ch_p);
 
110
 
 
111
        value_len = strlen(value);
 
112
        /* reallocation to accommodate the value */
 
113
        index = index_ch - string;
 
114
        len += value_len;
 
115
        string = realloc(string, len + 1);
 
116
        if (!string)
 
117
                return -ENOMEM;
 
118
        index_ch = string + index;
 
119
        /* concatenating the new value */
 
120
        strcpy(index_ch, value);
 
121
        index_ch += value_len;
 
122
        /* return values */
 
123
        *(len_p) = len;
 
124
        *(string_p) = string;
 
125
        *(index_ch_p) = index_ch;
 
126
        return 0;
 
127
}
 
128
 
 
129
static int snd_pcm_file_replace_fname(snd_pcm_file_t *file, char **new_fname_p)
 
130
{
 
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;
 
136
 
 
137
        snd_pcm_t *pcm = file->gen.slave;
 
138
 
 
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);
 
143
        if (!new_fname)
 
144
                return -ENOMEM;
 
145
 
 
146
        old_index_ch = fname;   /* first character of the old name */
 
147
        new_index_ch = new_fname;       /* first char of the new name */
 
148
 
 
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
 
153
                         next char */
 
154
                        switch (*(++old_index_ch)) {
 
155
                        case RATE_KEY:
 
156
                                snprintf(value, sizeof(value), "%d",
 
157
                                                pcm->rate);
 
158
                                err = snd_pcm_file_append_value(&new_fname,
 
159
                                        &new_index_ch, &new_len, value);
 
160
                                if (err < 0)
 
161
                                        return err;
 
162
                                break;
 
163
 
 
164
                        case CHANNELS_KEY:
 
165
                                snprintf(value, sizeof(value), "%d",
 
166
                                                pcm->channels);
 
167
                                err = snd_pcm_file_append_value(&new_fname,
 
168
                                        &new_index_ch, &new_len, value);
 
169
                                if (err < 0)
 
170
                                        return err;
 
171
                                break;
 
172
 
 
173
                        case BWIDTH_KEY:
 
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);
 
178
                                if (err < 0)
 
179
                                        return err;
 
180
                                break;
 
181
 
 
182
                        case FORMAT_KEY:
 
183
                                err = snd_pcm_file_append_value(&new_fname,
 
184
                                        &new_index_ch, &new_len,
 
185
                                        snd_pcm_format_name(pcm->format));
 
186
                                if (err < 0)
 
187
                                        return err;
 
188
                                break;
 
189
 
 
190
                        default:
 
191
                                /* non-key char, just copying */
 
192
                                *(new_index_ch++) = *(old_index_ch);
 
193
                        }
 
194
                        /* next old char */
 
195
                        old_index_ch++;
 
196
                } else {
 
197
                        /* plain copying, shifting both strings to next chars */
 
198
                        *(new_index_ch++) = *(old_index_ch++);
 
199
                }
 
200
        }
 
201
        /* closing the new string */
 
202
        *(new_index_ch) = '\0';
 
203
        *(new_fname_p) = new_fname;
 
204
        return 0;
 
205
 
 
206
}
 
207
 
 
208
static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
 
209
{
 
210
        int err, fd;
 
211
 
 
212
        /* fname can contain keys, generating final_fname */
 
213
        err = snd_pcm_file_replace_fname(file, &(file->final_fname));
 
214
        if (err < 0)
 
215
                return err;
 
216
        /*printf("DEBUG - original fname: %s, final fname: %s\n",
 
217
          file->fname, file->final_fname);*/
 
218
 
 
219
        if (file->final_fname[0] == '|') {
 
220
                /* pipe mode */
 
221
                FILE *pipe;
 
222
                /* clearing */
 
223
                pipe = popen(file->final_fname + 1, "w");
 
224
                if (!pipe) {
 
225
                        SYSERR("running %s for writing failed",
 
226
                                        file->final_fname);
 
227
                        return -errno;
 
228
                }
 
229
                fd = fileno(pipe);
 
230
        } else {
 
231
                if (file->trunc)
 
232
                        fd = open(file->final_fname, O_WRONLY|O_CREAT|O_TRUNC,
 
233
                                        file->perm);
 
234
                else {
 
235
                        fd = open(file->final_fname, O_WRONLY|O_CREAT|O_EXCL,
 
236
                                        file->perm);
 
237
                        if (fd < 0) {
 
238
                                char *tmpfname = NULL;
 
239
                                int idx, len;
 
240
                                len = strlen(file->final_fname) + 6;
 
241
                                tmpfname = malloc(len);
 
242
                                if (!tmpfname)
 
243
                                        return -ENOMEM;
 
244
                                for (idx = 1; idx < 10000; idx++) {
 
245
                                        snprintf(tmpfname, len,
 
246
                                                "%s.%04d", file->final_fname,
 
247
                                                idx);
 
248
                                        fd = open(tmpfname,
 
249
                                                        O_WRONLY|O_CREAT|O_EXCL,
 
250
                                                        file->perm);
 
251
                                        if (fd >= 0) {
 
252
                                                free(file->final_fname);
 
253
                                                file->final_fname = tmpfname;
 
254
                                                break;
 
255
                                        }
 
256
                                }
 
257
                                if (fd < 0) {
 
258
                                        SYSERR("open %s for writing failed",
 
259
                                                        file->final_fname);
 
260
                                        free(tmpfname);
 
261
                                        return -errno;
 
262
                                }
 
263
                        }
 
264
                }
 
265
        }
 
266
        file->fd = fd;
 
267
        return 0;
 
268
}
 
269
 
87
270
static void setup_wav_header(snd_pcm_t *pcm, struct wav_fmt *fmt)
88
271
{
89
272
        fmt->fmt = TO_LE16(0x01);
152
335
}
153
336
#endif /* DOC_HIDDEN */
154
337
 
 
338
 
 
339
 
155
340
static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
156
341
{
157
342
        snd_pcm_file_t *file = pcm->private_data;
442
627
                a->first = slave->sample_bits * channel;
443
628
                a->step = slave->frame_bits;
444
629
        }
 
630
        if (file->fd < 0) {
 
631
                err = snd_pcm_file_open_output_file(file);
 
632
                if (err < 0) {
 
633
                        SYSERR("failed opening output file %s", file->fname);
 
634
                        return err;
 
635
                }
 
636
        }
445
637
        return 0;
446
638
}
447
639
 
452
644
                snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
453
645
        else
454
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",
 
649
                                file->final_fname);
 
650
 
455
651
        if (pcm->setup) {
456
652
                snd_output_printf(out, "Its setup is:\n");
457
653
                snd_pcm_dump_setup(pcm, out);
533
729
        snd_pcm_file_t *file;
534
730
        snd_pcm_file_format_t format;
535
731
        struct timespec timespec;
536
 
        char *tmpname = NULL;
537
732
        int err;
538
733
 
539
734
        assert(pcmp);
546
741
                SNDERR("file format %s is unknown", fmt);
547
742
                return -EINVAL;
548
743
        }
549
 
        if (fname) {
550
 
                if (trunc)
551
 
                        fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, perm);
552
 
                else {
553
 
                        fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, perm);
554
 
                        if (fd < 0) {
555
 
                                int idx, len;
556
 
                                len = strlen(fname) + 6;
557
 
                                tmpname = malloc(len);
558
 
                                if (!tmpname)
559
 
                                        return -ENOMEM;
560
 
                                for (idx = 1; idx < 10000; idx++) {
561
 
                                        snprintf(tmpname, len,
562
 
                                                 "%s.%04d", fname, idx);
563
 
                                        fd = open(tmpname, O_WRONLY|O_CREAT|O_EXCL, perm);
564
 
                                        if (fd >= 0) {
565
 
                                                fname = tmpname;
566
 
                                                break;
567
 
                                        }
568
 
                                }
569
 
                        }
570
 
                }
571
 
                if (fd < 0) {
572
 
                        SYSERR("open %s for writing failed", fname);
573
 
                        free(tmpname);
574
 
                        return -errno;
575
 
                }
576
 
        }
577
744
        file = calloc(1, sizeof(snd_pcm_file_t));
578
745
        if (!file) {
579
 
                if (fname)
580
 
                        close(fd);
581
 
                free(tmpname);
582
746
                return -ENOMEM;
583
747
        }
584
748
 
 
749
        /* opening output fname is delayed until writing,
 
750
         when PCM params are known */
 
751
        if (fname)
 
752
                file->fname = strdup(fname);
 
753
        file->trunc = trunc;
 
754
        file->perm = perm;
 
755
 
585
756
        if (ifname) {
586
757
                ifd = open(ifname, O_RDONLY);   /* TODO: mind blocking mode */
587
758
                if (ifd < 0) {
588
759
                        SYSERR("open %s for reading failed", ifname);
589
 
                        if (fname)
590
 
                                close(fd);
591
760
                        free(file);
592
 
                        free(tmpname);
593
761
                        return -errno;
594
762
                }
595
 
        }
596
 
 
597
 
        if (fname)
598
 
                file->fname = strdup(fname);
599
 
        if (ifname)
600
763
                file->ifname = strdup(ifname);
 
764
        }
601
765
        file->fd = fd;
602
766
        file->ifd = ifd;
603
767
        file->format = format;
608
772
        if (err < 0) {
609
773
                free(file->fname);
610
774
                free(file);
611
 
                free(tmpname);
612
775
                return err;
613
776
        }
614
777
        pcm->ops = &snd_pcm_file_ops;
625
788
        snd_pcm_link_hw_ptr(pcm, slave);
626
789
        snd_pcm_link_appl_ptr(pcm, slave);
627
790
        *pcmp = pcm;
628
 
 
629
 
        free(tmpname);
630
791
        return 0;
631
792
}
632
793
 
634
795
 
635
796
\section pcm_plugins_file Plugin: File
636
797
 
637
 
This plugin stores contents of a PCM stream to file, and optionally
638
 
uses an existing file as an input data source (i.e., "virtual mic")
 
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")
639
801
 
640
802
\code
641
803
pcm.name {
647
809
                # or
648
810
                pcm { }         # Slave PCM definition
649
811
        }
650
 
        file STR                # Output filename
 
812
        file STR                # Output filename (or shell command the stream
 
813
                                # will be piped to if STR starts with the pipe
 
814
                                # char).
 
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)
 
822
                                # %%    replaced with %
651
823
        or
652
824
        file INT                # Output file descriptor number
653
825
        infile STR              # Input filename - only raw format
773
945
        err = snd_pcm_slave_conf(root, slave, &sconf, 0);
774
946
        if (err < 0)
775
947
                return err;
776
 
        if (!fname && fd < 0 && !ifname) {
 
948
        if ((!fname || strlen(fname) == 0) && fd < 0 && !ifname) {
777
949
                snd_config_delete(sconf);
778
950
                SNDERR("file is not defined");
779
951
                return -EINVAL;