153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <unistd.h>
2553a5a1b3Sopenharmony_ci#include <fcntl.h>
2653a5a1b3Sopenharmony_ci#include <errno.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ci#include <sndfile.h>
2953a5a1b3Sopenharmony_ci
3053a5a1b3Sopenharmony_ci#include <pulse/sample.h>
3153a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3253a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3353a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
3453a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3553a5a1b3Sopenharmony_ci#include <pulsecore/core-scache.h>
3653a5a1b3Sopenharmony_ci#include <pulsecore/sndfile-util.h>
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci#include "sound-file.h"
3953a5a1b3Sopenharmony_ci
4053a5a1b3Sopenharmony_ciint pa_sound_file_load(
4153a5a1b3Sopenharmony_ci        pa_mempool *pool,
4253a5a1b3Sopenharmony_ci        const char *fname,
4353a5a1b3Sopenharmony_ci        pa_sample_spec *ss,
4453a5a1b3Sopenharmony_ci        pa_channel_map *map,
4553a5a1b3Sopenharmony_ci        pa_memchunk *chunk,
4653a5a1b3Sopenharmony_ci        pa_proplist *p) {
4753a5a1b3Sopenharmony_ci
4853a5a1b3Sopenharmony_ci    SNDFILE *sf = NULL;
4953a5a1b3Sopenharmony_ci    SF_INFO sfi;
5053a5a1b3Sopenharmony_ci    int ret = -1;
5153a5a1b3Sopenharmony_ci    size_t l;
5253a5a1b3Sopenharmony_ci    sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL;
5353a5a1b3Sopenharmony_ci    void *ptr = NULL;
5453a5a1b3Sopenharmony_ci    int fd;
5553a5a1b3Sopenharmony_ci
5653a5a1b3Sopenharmony_ci    pa_assert(fname);
5753a5a1b3Sopenharmony_ci    pa_assert(ss);
5853a5a1b3Sopenharmony_ci    pa_assert(chunk);
5953a5a1b3Sopenharmony_ci
6053a5a1b3Sopenharmony_ci    pa_memchunk_reset(chunk);
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_ci    if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) {
6353a5a1b3Sopenharmony_ci        pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
6453a5a1b3Sopenharmony_ci        goto finish;
6553a5a1b3Sopenharmony_ci    }
6653a5a1b3Sopenharmony_ci
6753a5a1b3Sopenharmony_ci#ifdef HAVE_POSIX_FADVISE
6853a5a1b3Sopenharmony_ci    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
6953a5a1b3Sopenharmony_ci        pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
7053a5a1b3Sopenharmony_ci        goto finish;
7153a5a1b3Sopenharmony_ci    } else
7253a5a1b3Sopenharmony_ci        pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
7353a5a1b3Sopenharmony_ci#endif
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci    pa_zero(sfi);
7653a5a1b3Sopenharmony_ci    if (!(sf = sf_open_fd(fd, SFM_READ, &sfi, 1))) {
7753a5a1b3Sopenharmony_ci        pa_log("Failed to open file %s", fname);
7853a5a1b3Sopenharmony_ci        goto finish;
7953a5a1b3Sopenharmony_ci    }
8053a5a1b3Sopenharmony_ci
8153a5a1b3Sopenharmony_ci    fd = -1;
8253a5a1b3Sopenharmony_ci
8353a5a1b3Sopenharmony_ci    if (pa_sndfile_read_sample_spec(sf, ss) < 0) {
8453a5a1b3Sopenharmony_ci        pa_log("Failed to determine file sample format.");
8553a5a1b3Sopenharmony_ci        goto finish;
8653a5a1b3Sopenharmony_ci    }
8753a5a1b3Sopenharmony_ci
8853a5a1b3Sopenharmony_ci    if ((map && pa_sndfile_read_channel_map(sf, map) < 0)) {
8953a5a1b3Sopenharmony_ci        if (ss->channels > 2)
9053a5a1b3Sopenharmony_ci            pa_log("Failed to determine file channel map, synthesizing one.");
9153a5a1b3Sopenharmony_ci        pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_DEFAULT);
9253a5a1b3Sopenharmony_ci    }
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ci    if (p)
9553a5a1b3Sopenharmony_ci        pa_sndfile_init_proplist(sf, p);
9653a5a1b3Sopenharmony_ci
9753a5a1b3Sopenharmony_ci    if ((l = pa_frame_size(ss) * (size_t) sfi.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
9853a5a1b3Sopenharmony_ci        pa_log("File too large");
9953a5a1b3Sopenharmony_ci        goto finish;
10053a5a1b3Sopenharmony_ci    }
10153a5a1b3Sopenharmony_ci
10253a5a1b3Sopenharmony_ci    chunk->memblock = pa_memblock_new(pool, l);
10353a5a1b3Sopenharmony_ci    chunk->index = 0;
10453a5a1b3Sopenharmony_ci    chunk->length = l;
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci    readf_function = pa_sndfile_readf_function(ss);
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_ci    ptr = pa_memblock_acquire(chunk->memblock);
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_ci    if ((readf_function && readf_function(sf, ptr, sfi.frames) != sfi.frames) ||
11153a5a1b3Sopenharmony_ci        (!readf_function && sf_read_raw(sf, ptr, (sf_count_t) l) != (sf_count_t) l)) {
11253a5a1b3Sopenharmony_ci        pa_log("Premature file end");
11353a5a1b3Sopenharmony_ci        goto finish;
11453a5a1b3Sopenharmony_ci    }
11553a5a1b3Sopenharmony_ci
11653a5a1b3Sopenharmony_ci    ret = 0;
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_cifinish:
11953a5a1b3Sopenharmony_ci
12053a5a1b3Sopenharmony_ci    if (sf)
12153a5a1b3Sopenharmony_ci        sf_close(sf);
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    if (ptr)
12453a5a1b3Sopenharmony_ci        pa_memblock_release(chunk->memblock);
12553a5a1b3Sopenharmony_ci
12653a5a1b3Sopenharmony_ci    if (ret != 0 && chunk->memblock)
12753a5a1b3Sopenharmony_ci        pa_memblock_unref(chunk->memblock);
12853a5a1b3Sopenharmony_ci
12953a5a1b3Sopenharmony_ci    if (fd >= 0)
13053a5a1b3Sopenharmony_ci        pa_close(fd);
13153a5a1b3Sopenharmony_ci
13253a5a1b3Sopenharmony_ci    return ret;
13353a5a1b3Sopenharmony_ci}
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_ciint pa_sound_file_too_big_to_cache(const char *fname) {
13653a5a1b3Sopenharmony_ci
13753a5a1b3Sopenharmony_ci    SNDFILE*sf = NULL;
13853a5a1b3Sopenharmony_ci    SF_INFO sfi;
13953a5a1b3Sopenharmony_ci    pa_sample_spec ss;
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_ci    pa_assert(fname);
14253a5a1b3Sopenharmony_ci
14353a5a1b3Sopenharmony_ci    pa_zero(sfi);
14453a5a1b3Sopenharmony_ci    if (!(sf = sf_open(fname, SFM_READ, &sfi))) {
14553a5a1b3Sopenharmony_ci        pa_log("Failed to open file %s", fname);
14653a5a1b3Sopenharmony_ci        return -1;
14753a5a1b3Sopenharmony_ci    }
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ci    if (pa_sndfile_read_sample_spec(sf, &ss) < 0) {
15053a5a1b3Sopenharmony_ci        pa_log("Failed to determine file sample format.");
15153a5a1b3Sopenharmony_ci        sf_close(sf);
15253a5a1b3Sopenharmony_ci        return -1;
15353a5a1b3Sopenharmony_ci    }
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_ci    sf_close(sf);
15653a5a1b3Sopenharmony_ci
15753a5a1b3Sopenharmony_ci    if ((pa_frame_size(&ss) * (size_t) sfi.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
15853a5a1b3Sopenharmony_ci        pa_log("File too large: %s", fname);
15953a5a1b3Sopenharmony_ci        return 1;
16053a5a1b3Sopenharmony_ci    }
16153a5a1b3Sopenharmony_ci
16253a5a1b3Sopenharmony_ci    return 0;
16353a5a1b3Sopenharmony_ci}
164