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