]> code.delx.au - pulseaudio/blob - src/pulsecore/sound-file.c
2d9b76ad6e4597deb836e78f3837c96f28b2efa0
[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.1 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 #include <pulsecore/core-scache.h>
39 #include <pulsecore/sndfile-util.h>
40
41 #include "sound-file.h"
42
43 int pa_sound_file_load(
44 pa_mempool *pool,
45 const char *fname,
46 pa_sample_spec *ss,
47 pa_channel_map *map,
48 pa_memchunk *chunk,
49 pa_proplist *p) {
50
51 SNDFILE *sf = NULL;
52 SF_INFO sfi;
53 int ret = -1;
54 size_t l;
55 sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL;
56 void *ptr = NULL;
57 int fd;
58
59 pa_assert(fname);
60 pa_assert(ss);
61 pa_assert(chunk);
62
63 pa_memchunk_reset(chunk);
64
65 if ((fd = open(fname, O_RDONLY
66 #ifdef O_NOCTTY
67 |O_NOCTTY
68 #endif
69 )) < 0) {
70 pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
71 goto finish;
72 }
73
74 #ifdef HAVE_POSIX_FADVISE
75 if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
76 pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
77 goto finish;
78 } else
79 pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
80 #endif
81
82 pa_zero(sfi);
83 if (!(sf = sf_open_fd(fd, SFM_READ, &sfi, 1))) {
84 pa_log("Failed to open file %s", fname);
85 goto finish;
86 }
87
88 fd = -1;
89
90 if (pa_sndfile_read_sample_spec(sf, ss) < 0) {
91 pa_log("Failed to determine file sample format.");
92 goto finish;
93 }
94
95 if ((map && pa_sndfile_read_channel_map(sf, map) < 0)) {
96 if (ss->channels > 2)
97 pa_log("Failed to determine file channel map, synthesizing one.");
98 pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_DEFAULT);
99 }
100
101 if (p)
102 pa_sndfile_init_proplist(sf, p);
103
104 if ((l = pa_frame_size(ss) * (size_t) sfi.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
105 pa_log("File too large");
106 goto finish;
107 }
108
109 chunk->memblock = pa_memblock_new(pool, l);
110 chunk->index = 0;
111 chunk->length = l;
112
113 readf_function = pa_sndfile_readf_function(ss);
114
115 ptr = pa_memblock_acquire(chunk->memblock);
116
117 if ((readf_function && readf_function(sf, ptr, sfi.frames) != sfi.frames) ||
118 (!readf_function && sf_read_raw(sf, ptr, (sf_count_t) l) != (sf_count_t) l)) {
119 pa_log("Premature file end");
120 goto finish;
121 }
122
123 ret = 0;
124
125 finish:
126
127 if (sf)
128 sf_close(sf);
129
130 if (ptr)
131 pa_memblock_release(chunk->memblock);
132
133 if (ret != 0 && chunk->memblock)
134 pa_memblock_unref(chunk->memblock);
135
136 if (fd >= 0)
137 pa_close(fd);
138
139 return ret;
140 }
141
142 int pa_sound_file_too_big_to_cache(const char *fname) {
143
144 SNDFILE*sf = NULL;
145 SF_INFO sfi;
146 pa_sample_spec ss;
147
148 pa_assert(fname);
149
150 pa_zero(sfi);
151 if (!(sf = sf_open(fname, SFM_READ, &sfi))) {
152 pa_log("Failed to open file %s", fname);
153 return -1;
154 }
155
156 if (pa_sndfile_read_sample_spec(sf, &ss) < 0) {
157 pa_log("Failed to determine file sample format.");
158 sf_close(sf);
159 return -1;
160 }
161
162 sf_close(sf);
163
164 if ((pa_frame_size(&ss) * (size_t) sfi.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
165 pa_log("File too large: %s", fname);
166 return 1;
167 }
168
169 return 0;
170 }