]> code.delx.au - pulseaudio/blob - src/pulsecore/sound-file.c
get rid of svn $ keywords
[pulseaudio] / src / pulsecore / sound-file.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30
31 #include <sndfile.h>
32
33 #include <pulse/sample.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/macro.h>
36 #include <pulsecore/core-error.h>
37 #include <pulsecore/core-util.h>
38
39 #include "sound-file.h"
40 #include "core-scache.h"
41
42 int pa_sound_file_load(
43 pa_mempool *pool,
44 const char *fname,
45 pa_sample_spec *ss,
46 pa_channel_map *map,
47 pa_memchunk *chunk) {
48
49 SNDFILE *sf = NULL;
50 SF_INFO sfinfo;
51 int ret = -1;
52 size_t l;
53 sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL;
54 void *ptr = NULL;
55 int fd;
56
57 pa_assert(fname);
58 pa_assert(ss);
59 pa_assert(chunk);
60
61 pa_memchunk_reset(chunk);
62 memset(&sfinfo, 0, sizeof(sfinfo));
63
64 if ((fd = open(fname, O_RDONLY
65 #ifdef O_NOCTTY
66 |O_NOCTTY
67 #endif
68 )) < 0) {
69 pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
70 goto finish;
71 }
72
73 #ifdef HAVE_POSIX_FADVISE
74 if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
75 pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
76 goto finish;
77 } else
78 pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
79 #endif
80
81 if (!(sf = sf_open_fd(fd, SFM_READ, &sfinfo, 1))) {
82 pa_log("Failed to open file %s", fname);
83 pa_close(fd);
84 goto finish;
85 }
86
87 switch (sfinfo.format & SF_FORMAT_SUBMASK) {
88 case SF_FORMAT_PCM_16:
89 case SF_FORMAT_PCM_U8:
90 case SF_FORMAT_PCM_S8:
91 ss->format = PA_SAMPLE_S16NE;
92 readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short;
93 break;
94
95 case SF_FORMAT_ULAW:
96 ss->format = PA_SAMPLE_ULAW;
97 break;
98
99 case SF_FORMAT_ALAW:
100 ss->format = PA_SAMPLE_ALAW;
101 break;
102
103 case SF_FORMAT_FLOAT:
104 case SF_FORMAT_DOUBLE:
105 default:
106 ss->format = PA_SAMPLE_FLOAT32NE;
107 readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float;
108 break;
109 }
110
111 ss->rate = sfinfo.samplerate;
112 ss->channels = sfinfo.channels;
113
114 if (!pa_sample_spec_valid(ss)) {
115 pa_log("Unsupported sample format in file %s", fname);
116 goto finish;
117 }
118
119 if (map)
120 if (!pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT)) {
121 pa_log("Unsupported channel map in file %s", fname);
122 goto finish;
123 }
124
125 if ((l = pa_frame_size(ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
126 pa_log("File too large");
127 goto finish;
128 }
129
130 chunk->memblock = pa_memblock_new(pool, l);
131 chunk->index = 0;
132 chunk->length = l;
133
134 ptr = pa_memblock_acquire(chunk->memblock);
135
136 if ((readf_function && readf_function(sf, ptr, sfinfo.frames) != sfinfo.frames) ||
137 (!readf_function && sf_read_raw(sf, ptr, l) != (sf_count_t) l)) {
138 pa_log("Premature file end");
139 goto finish;
140 }
141
142 ret = 0;
143
144 finish:
145
146 if (sf)
147 sf_close(sf);
148
149 if (ptr)
150 pa_memblock_release(chunk->memblock);
151
152 if (ret != 0 && chunk->memblock)
153 pa_memblock_unref(chunk->memblock);
154
155 return ret;
156 }
157
158 int pa_sound_file_too_big_to_cache(const char *fname) {
159
160 SNDFILE*sf = NULL;
161 SF_INFO sfinfo;
162 pa_sample_spec ss;
163
164 pa_assert(fname);
165
166 if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) {
167 pa_log("Failed to open file %s", fname);
168 return -1;
169 }
170
171 sf_close(sf);
172
173 switch (sfinfo.format & SF_FORMAT_SUBMASK) {
174 case SF_FORMAT_PCM_16:
175 case SF_FORMAT_PCM_U8:
176 case SF_FORMAT_PCM_S8:
177 ss.format = PA_SAMPLE_S16NE;
178 break;
179
180 case SF_FORMAT_ULAW:
181 ss.format = PA_SAMPLE_ULAW;
182 break;
183
184 case SF_FORMAT_ALAW:
185 ss.format = PA_SAMPLE_ALAW;
186 break;
187
188 case SF_FORMAT_DOUBLE:
189 case SF_FORMAT_FLOAT:
190 default:
191 ss.format = PA_SAMPLE_FLOAT32NE;
192 break;
193 }
194
195 ss.rate = sfinfo.samplerate;
196 ss.channels = sfinfo.channels;
197
198 if (!pa_sample_spec_valid(&ss)) {
199 pa_log("Unsupported sample format in file %s", fname);
200 return -1;
201 }
202
203 if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
204 pa_log("File too large: %s", fname);
205 return 1;
206 }
207
208 return 0;
209 }