153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2008 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <stdlib.h> 2653a5a1b3Sopenharmony_ci#include <stdio.h> 2753a5a1b3Sopenharmony_ci#include <sys/types.h> 2853a5a1b3Sopenharmony_ci#include <dirent.h> 2953a5a1b3Sopenharmony_ci#include <sys/stat.h> 3053a5a1b3Sopenharmony_ci#include <errno.h> 3153a5a1b3Sopenharmony_ci#include <limits.h> 3253a5a1b3Sopenharmony_ci#include <time.h> 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci#ifdef HAVE_GLOB_H 3553a5a1b3Sopenharmony_ci#include <glob.h> 3653a5a1b3Sopenharmony_ci#endif 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#ifdef HAVE_WINDOWS_H 3953a5a1b3Sopenharmony_ci#include <windows.h> 4053a5a1b3Sopenharmony_ci#endif 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci#include <pulse/mainloop.h> 4353a5a1b3Sopenharmony_ci#include <pulse/channelmap.h> 4453a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 4553a5a1b3Sopenharmony_ci#include <pulse/util.h> 4653a5a1b3Sopenharmony_ci#include <pulse/volume.h> 4753a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 4853a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 4953a5a1b3Sopenharmony_ci 5053a5a1b3Sopenharmony_ci#include <pulsecore/sink-input.h> 5153a5a1b3Sopenharmony_ci#include <pulsecore/play-memchunk.h> 5253a5a1b3Sopenharmony_ci#include <pulsecore/core-subscribe.h> 5353a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h> 5453a5a1b3Sopenharmony_ci#include <pulsecore/sound-file.h> 5553a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h> 5653a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 5753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 5853a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 5953a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci#include "core-scache.h" 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci#define UNLOAD_POLL_TIME (60 * PA_USEC_PER_SEC) 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_cistatic void timeout_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) { 6653a5a1b3Sopenharmony_ci pa_core *c = userdata; 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci pa_assert(c); 6953a5a1b3Sopenharmony_ci pa_assert(c->mainloop == m); 7053a5a1b3Sopenharmony_ci pa_assert(c->scache_auto_unload_event == e); 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci pa_scache_unload_unused(c); 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_ci pa_core_rttime_restart(c, e, pa_rtclock_now() + UNLOAD_POLL_TIME); 7553a5a1b3Sopenharmony_ci} 7653a5a1b3Sopenharmony_ci 7753a5a1b3Sopenharmony_cistatic void free_entry(pa_scache_entry *e) { 7853a5a1b3Sopenharmony_ci pa_assert(e); 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci pa_namereg_unregister(e->core, e->name); 8153a5a1b3Sopenharmony_ci pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); 8253a5a1b3Sopenharmony_ci pa_hook_fire(&e->core->hooks[PA_CORE_HOOK_SAMPLE_CACHE_UNLINK], e); 8353a5a1b3Sopenharmony_ci pa_xfree(e->name); 8453a5a1b3Sopenharmony_ci pa_xfree(e->filename); 8553a5a1b3Sopenharmony_ci if (e->memchunk.memblock) 8653a5a1b3Sopenharmony_ci pa_memblock_unref(e->memchunk.memblock); 8753a5a1b3Sopenharmony_ci if (e->proplist) 8853a5a1b3Sopenharmony_ci pa_proplist_free(e->proplist); 8953a5a1b3Sopenharmony_ci pa_xfree(e); 9053a5a1b3Sopenharmony_ci} 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_cistatic pa_scache_entry* scache_add_item(pa_core *c, const char *name, bool *new_sample) { 9353a5a1b3Sopenharmony_ci pa_scache_entry *e; 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_ci pa_assert(c); 9653a5a1b3Sopenharmony_ci pa_assert(name); 9753a5a1b3Sopenharmony_ci pa_assert(new_sample); 9853a5a1b3Sopenharmony_ci 9953a5a1b3Sopenharmony_ci if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE))) { 10053a5a1b3Sopenharmony_ci if (e->memchunk.memblock) 10153a5a1b3Sopenharmony_ci pa_memblock_unref(e->memchunk.memblock); 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci pa_xfree(e->filename); 10453a5a1b3Sopenharmony_ci pa_proplist_clear(e->proplist); 10553a5a1b3Sopenharmony_ci 10653a5a1b3Sopenharmony_ci pa_assert(e->core == c); 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); 10953a5a1b3Sopenharmony_ci *new_sample = false; 11053a5a1b3Sopenharmony_ci } else { 11153a5a1b3Sopenharmony_ci e = pa_xnew(pa_scache_entry, 1); 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, true)) { 11453a5a1b3Sopenharmony_ci pa_xfree(e); 11553a5a1b3Sopenharmony_ci return NULL; 11653a5a1b3Sopenharmony_ci } 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_ci e->name = pa_xstrdup(name); 11953a5a1b3Sopenharmony_ci e->core = c; 12053a5a1b3Sopenharmony_ci e->proplist = pa_proplist_new(); 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci pa_idxset_put(c->scache, e, &e->index); 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); 12553a5a1b3Sopenharmony_ci *new_sample = true; 12653a5a1b3Sopenharmony_ci } 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_ci e->last_used_time = 0; 12953a5a1b3Sopenharmony_ci pa_memchunk_reset(&e->memchunk); 13053a5a1b3Sopenharmony_ci e->filename = NULL; 13153a5a1b3Sopenharmony_ci e->lazy = false; 13253a5a1b3Sopenharmony_ci e->last_used_time = 0; 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci pa_sample_spec_init(&e->sample_spec); 13553a5a1b3Sopenharmony_ci pa_channel_map_init(&e->channel_map); 13653a5a1b3Sopenharmony_ci pa_cvolume_init(&e->volume); 13753a5a1b3Sopenharmony_ci e->volume_is_set = false; 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci pa_proplist_sets(e->proplist, PA_PROP_MEDIA_ROLE, "event"); 14053a5a1b3Sopenharmony_ci 14153a5a1b3Sopenharmony_ci return e; 14253a5a1b3Sopenharmony_ci} 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ciint pa_scache_add_item( 14553a5a1b3Sopenharmony_ci pa_core *c, 14653a5a1b3Sopenharmony_ci const char *name, 14753a5a1b3Sopenharmony_ci const pa_sample_spec *ss, 14853a5a1b3Sopenharmony_ci const pa_channel_map *map, 14953a5a1b3Sopenharmony_ci const pa_memchunk *chunk, 15053a5a1b3Sopenharmony_ci pa_proplist *p, 15153a5a1b3Sopenharmony_ci uint32_t *idx) { 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci pa_scache_entry *e; 15453a5a1b3Sopenharmony_ci char st[PA_SAMPLE_SPEC_SNPRINT_MAX]; 15553a5a1b3Sopenharmony_ci pa_channel_map tmap; 15653a5a1b3Sopenharmony_ci bool new_sample; 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_ci pa_assert(c); 15953a5a1b3Sopenharmony_ci pa_assert(name); 16053a5a1b3Sopenharmony_ci pa_assert(!ss || pa_sample_spec_valid(ss)); 16153a5a1b3Sopenharmony_ci pa_assert(!map || (pa_channel_map_valid(map) && ss && pa_channel_map_compatible(map, ss))); 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci if (ss && !map) { 16453a5a1b3Sopenharmony_ci pa_channel_map_init_extend(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT); 16553a5a1b3Sopenharmony_ci map = &tmap; 16653a5a1b3Sopenharmony_ci } 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_ci if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) 16953a5a1b3Sopenharmony_ci return -1; 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_ci if (!(e = scache_add_item(c, name, &new_sample))) 17253a5a1b3Sopenharmony_ci return -1; 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci pa_sample_spec_init(&e->sample_spec); 17553a5a1b3Sopenharmony_ci pa_channel_map_init(&e->channel_map); 17653a5a1b3Sopenharmony_ci pa_cvolume_init(&e->volume); 17753a5a1b3Sopenharmony_ci e->volume_is_set = false; 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci if (ss) { 18053a5a1b3Sopenharmony_ci e->sample_spec = *ss; 18153a5a1b3Sopenharmony_ci pa_cvolume_reset(&e->volume, ss->channels); 18253a5a1b3Sopenharmony_ci } 18353a5a1b3Sopenharmony_ci 18453a5a1b3Sopenharmony_ci if (map) 18553a5a1b3Sopenharmony_ci e->channel_map = *map; 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci if (chunk) { 18853a5a1b3Sopenharmony_ci e->memchunk = *chunk; 18953a5a1b3Sopenharmony_ci pa_memblock_ref(e->memchunk.memblock); 19053a5a1b3Sopenharmony_ci } 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci if (p) 19353a5a1b3Sopenharmony_ci pa_proplist_update(e->proplist, PA_UPDATE_REPLACE, p); 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci if (idx) 19653a5a1b3Sopenharmony_ci *idx = e->index; 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci pa_log_debug("Created sample \"%s\" (#%d), %lu bytes with sample spec %s", 19953a5a1b3Sopenharmony_ci name, e->index, (unsigned long) e->memchunk.length, 20053a5a1b3Sopenharmony_ci pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec)); 20153a5a1b3Sopenharmony_ci 20253a5a1b3Sopenharmony_ci pa_hook_fire(&e->core->hooks[new_sample ? PA_CORE_HOOK_SAMPLE_CACHE_NEW : PA_CORE_HOOK_SAMPLE_CACHE_CHANGED], e); 20353a5a1b3Sopenharmony_ci 20453a5a1b3Sopenharmony_ci return 0; 20553a5a1b3Sopenharmony_ci} 20653a5a1b3Sopenharmony_ci 20753a5a1b3Sopenharmony_ciint pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx) { 20853a5a1b3Sopenharmony_ci pa_sample_spec ss; 20953a5a1b3Sopenharmony_ci pa_channel_map map; 21053a5a1b3Sopenharmony_ci pa_memchunk chunk; 21153a5a1b3Sopenharmony_ci int r; 21253a5a1b3Sopenharmony_ci pa_proplist *p; 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 21553a5a1b3Sopenharmony_ci char buf[MAX_PATH]; 21653a5a1b3Sopenharmony_ci 21753a5a1b3Sopenharmony_ci if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) 21853a5a1b3Sopenharmony_ci filename = buf; 21953a5a1b3Sopenharmony_ci#endif 22053a5a1b3Sopenharmony_ci 22153a5a1b3Sopenharmony_ci pa_assert(c); 22253a5a1b3Sopenharmony_ci pa_assert(name); 22353a5a1b3Sopenharmony_ci pa_assert(filename); 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci p = pa_proplist_new(); 22653a5a1b3Sopenharmony_ci pa_proplist_sets(p, PA_PROP_MEDIA_FILENAME, filename); 22753a5a1b3Sopenharmony_ci#ifdef SNDFILE_ENABLE 22853a5a1b3Sopenharmony_ci if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk, p) < 0) { 22953a5a1b3Sopenharmony_ci pa_proplist_free(p); 23053a5a1b3Sopenharmony_ci return -1; 23153a5a1b3Sopenharmony_ci } 23253a5a1b3Sopenharmony_ci#else 23353a5a1b3Sopenharmony_ci return -1; 23453a5a1b3Sopenharmony_ci#endif 23553a5a1b3Sopenharmony_ci r = pa_scache_add_item(c, name, &ss, &map, &chunk, p, idx); 23653a5a1b3Sopenharmony_ci pa_memblock_unref(chunk.memblock); 23753a5a1b3Sopenharmony_ci pa_proplist_free(p); 23853a5a1b3Sopenharmony_ci 23953a5a1b3Sopenharmony_ci return r; 24053a5a1b3Sopenharmony_ci} 24153a5a1b3Sopenharmony_ci 24253a5a1b3Sopenharmony_ciint pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx) { 24353a5a1b3Sopenharmony_ci pa_scache_entry *e; 24453a5a1b3Sopenharmony_ci bool new_sample; 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 24753a5a1b3Sopenharmony_ci char buf[MAX_PATH]; 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_ci if (ExpandEnvironmentStrings(filename, buf, MAX_PATH)) 25053a5a1b3Sopenharmony_ci filename = buf; 25153a5a1b3Sopenharmony_ci#endif 25253a5a1b3Sopenharmony_ci 25353a5a1b3Sopenharmony_ci pa_assert(c); 25453a5a1b3Sopenharmony_ci pa_assert(name); 25553a5a1b3Sopenharmony_ci pa_assert(filename); 25653a5a1b3Sopenharmony_ci 25753a5a1b3Sopenharmony_ci if (!(e = scache_add_item(c, name, &new_sample))) 25853a5a1b3Sopenharmony_ci return -1; 25953a5a1b3Sopenharmony_ci 26053a5a1b3Sopenharmony_ci e->lazy = true; 26153a5a1b3Sopenharmony_ci e->filename = pa_xstrdup(filename); 26253a5a1b3Sopenharmony_ci 26353a5a1b3Sopenharmony_ci pa_proplist_sets(e->proplist, PA_PROP_MEDIA_FILENAME, filename); 26453a5a1b3Sopenharmony_ci 26553a5a1b3Sopenharmony_ci if (!c->scache_auto_unload_event) 26653a5a1b3Sopenharmony_ci c->scache_auto_unload_event = pa_core_rttime_new(c, pa_rtclock_now() + UNLOAD_POLL_TIME, timeout_callback, c); 26753a5a1b3Sopenharmony_ci 26853a5a1b3Sopenharmony_ci if (idx) 26953a5a1b3Sopenharmony_ci *idx = e->index; 27053a5a1b3Sopenharmony_ci 27153a5a1b3Sopenharmony_ci pa_hook_fire(&e->core->hooks[new_sample ? PA_CORE_HOOK_SAMPLE_CACHE_NEW : PA_CORE_HOOK_SAMPLE_CACHE_CHANGED], e); 27253a5a1b3Sopenharmony_ci 27353a5a1b3Sopenharmony_ci return 0; 27453a5a1b3Sopenharmony_ci} 27553a5a1b3Sopenharmony_ci 27653a5a1b3Sopenharmony_ciint pa_scache_remove_item(pa_core *c, const char *name) { 27753a5a1b3Sopenharmony_ci pa_scache_entry *e; 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci pa_assert(c); 28053a5a1b3Sopenharmony_ci pa_assert(name); 28153a5a1b3Sopenharmony_ci 28253a5a1b3Sopenharmony_ci if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE))) 28353a5a1b3Sopenharmony_ci return -1; 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ci pa_assert_se(pa_idxset_remove_by_data(c->scache, e, NULL) == e); 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci pa_log_debug("Removed sample \"%s\"", name); 28853a5a1b3Sopenharmony_ci 28953a5a1b3Sopenharmony_ci free_entry(e); 29053a5a1b3Sopenharmony_ci 29153a5a1b3Sopenharmony_ci return 0; 29253a5a1b3Sopenharmony_ci} 29353a5a1b3Sopenharmony_ci 29453a5a1b3Sopenharmony_civoid pa_scache_free_all(pa_core *c) { 29553a5a1b3Sopenharmony_ci pa_assert(c); 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci pa_idxset_remove_all(c->scache, (pa_free_cb_t) free_entry); 29853a5a1b3Sopenharmony_ci 29953a5a1b3Sopenharmony_ci if (c->scache_auto_unload_event) { 30053a5a1b3Sopenharmony_ci c->mainloop->time_free(c->scache_auto_unload_event); 30153a5a1b3Sopenharmony_ci c->scache_auto_unload_event = NULL; 30253a5a1b3Sopenharmony_ci } 30353a5a1b3Sopenharmony_ci} 30453a5a1b3Sopenharmony_ci 30553a5a1b3Sopenharmony_ciint pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume, pa_proplist *p, uint32_t *sink_input_idx) { 30653a5a1b3Sopenharmony_ci pa_scache_entry *e; 30753a5a1b3Sopenharmony_ci pa_cvolume r; 30853a5a1b3Sopenharmony_ci pa_proplist *merged; 30953a5a1b3Sopenharmony_ci bool pass_volume; 31053a5a1b3Sopenharmony_ci 31153a5a1b3Sopenharmony_ci pa_assert(c); 31253a5a1b3Sopenharmony_ci pa_assert(name); 31353a5a1b3Sopenharmony_ci pa_assert(sink); 31453a5a1b3Sopenharmony_ci 31553a5a1b3Sopenharmony_ci if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE))) 31653a5a1b3Sopenharmony_ci return -1; 31753a5a1b3Sopenharmony_ci 31853a5a1b3Sopenharmony_ci merged = pa_proplist_new(); 31953a5a1b3Sopenharmony_ci pa_proplist_sets(merged, PA_PROP_MEDIA_NAME, name); 32053a5a1b3Sopenharmony_ci pa_proplist_sets(merged, PA_PROP_EVENT_ID, name); 32153a5a1b3Sopenharmony_ci 32253a5a1b3Sopenharmony_ci if (e->lazy && !e->memchunk.memblock) { 32353a5a1b3Sopenharmony_ci pa_channel_map old_channel_map = e->channel_map; 32453a5a1b3Sopenharmony_ci#ifdef SNDFILE_ENABLE 32553a5a1b3Sopenharmony_ci if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, merged) < 0) 32653a5a1b3Sopenharmony_ci goto fail; 32753a5a1b3Sopenharmony_ci#else 32853a5a1b3Sopenharmony_ci goto fail; 32953a5a1b3Sopenharmony_ci#endif 33053a5a1b3Sopenharmony_ci pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci if (e->volume_is_set) { 33353a5a1b3Sopenharmony_ci if (pa_cvolume_valid(&e->volume)) 33453a5a1b3Sopenharmony_ci pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map); 33553a5a1b3Sopenharmony_ci else 33653a5a1b3Sopenharmony_ci pa_cvolume_reset(&e->volume, e->sample_spec.channels); 33753a5a1b3Sopenharmony_ci } 33853a5a1b3Sopenharmony_ci } 33953a5a1b3Sopenharmony_ci 34053a5a1b3Sopenharmony_ci if (!e->memchunk.memblock) 34153a5a1b3Sopenharmony_ci goto fail; 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name); 34453a5a1b3Sopenharmony_ci 34553a5a1b3Sopenharmony_ci pass_volume = true; 34653a5a1b3Sopenharmony_ci 34753a5a1b3Sopenharmony_ci if (e->volume_is_set && PA_VOLUME_IS_VALID(volume)) { 34853a5a1b3Sopenharmony_ci pa_cvolume_set(&r, e->sample_spec.channels, volume); 34953a5a1b3Sopenharmony_ci pa_sw_cvolume_multiply(&r, &r, &e->volume); 35053a5a1b3Sopenharmony_ci } else if (e->volume_is_set) 35153a5a1b3Sopenharmony_ci r = e->volume; 35253a5a1b3Sopenharmony_ci else if (PA_VOLUME_IS_VALID(volume)) 35353a5a1b3Sopenharmony_ci pa_cvolume_set(&r, e->sample_spec.channels, volume); 35453a5a1b3Sopenharmony_ci else 35553a5a1b3Sopenharmony_ci pass_volume = false; 35653a5a1b3Sopenharmony_ci 35753a5a1b3Sopenharmony_ci pa_proplist_update(merged, PA_UPDATE_REPLACE, e->proplist); 35853a5a1b3Sopenharmony_ci 35953a5a1b3Sopenharmony_ci if (p) 36053a5a1b3Sopenharmony_ci pa_proplist_update(merged, PA_UPDATE_REPLACE, p); 36153a5a1b3Sopenharmony_ci 36253a5a1b3Sopenharmony_ci if (pa_play_memchunk(sink, 36353a5a1b3Sopenharmony_ci &e->sample_spec, &e->channel_map, 36453a5a1b3Sopenharmony_ci &e->memchunk, 36553a5a1b3Sopenharmony_ci pass_volume ? &r : NULL, 36653a5a1b3Sopenharmony_ci merged, 36753a5a1b3Sopenharmony_ci PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND, sink_input_idx) < 0) 36853a5a1b3Sopenharmony_ci goto fail; 36953a5a1b3Sopenharmony_ci 37053a5a1b3Sopenharmony_ci pa_proplist_free(merged); 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci if (e->lazy) 37353a5a1b3Sopenharmony_ci time(&e->last_used_time); 37453a5a1b3Sopenharmony_ci 37553a5a1b3Sopenharmony_ci return 0; 37653a5a1b3Sopenharmony_ci 37753a5a1b3Sopenharmony_cifail: 37853a5a1b3Sopenharmony_ci pa_proplist_free(merged); 37953a5a1b3Sopenharmony_ci return -1; 38053a5a1b3Sopenharmony_ci} 38153a5a1b3Sopenharmony_ci 38253a5a1b3Sopenharmony_ciint pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_volume_t volume, pa_proplist *p, uint32_t *sink_input_idx) { 38353a5a1b3Sopenharmony_ci pa_sink *sink; 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci pa_assert(c); 38653a5a1b3Sopenharmony_ci pa_assert(name); 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_ci if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) 38953a5a1b3Sopenharmony_ci return -1; 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci return pa_scache_play_item(c, name, sink, volume, p, sink_input_idx); 39253a5a1b3Sopenharmony_ci} 39353a5a1b3Sopenharmony_ci 39453a5a1b3Sopenharmony_ciconst char *pa_scache_get_name_by_id(pa_core *c, uint32_t id) { 39553a5a1b3Sopenharmony_ci pa_scache_entry *e; 39653a5a1b3Sopenharmony_ci 39753a5a1b3Sopenharmony_ci pa_assert(c); 39853a5a1b3Sopenharmony_ci pa_assert(id != PA_IDXSET_INVALID); 39953a5a1b3Sopenharmony_ci 40053a5a1b3Sopenharmony_ci if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id))) 40153a5a1b3Sopenharmony_ci return NULL; 40253a5a1b3Sopenharmony_ci 40353a5a1b3Sopenharmony_ci return e->name; 40453a5a1b3Sopenharmony_ci} 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ciuint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { 40753a5a1b3Sopenharmony_ci pa_scache_entry *e; 40853a5a1b3Sopenharmony_ci 40953a5a1b3Sopenharmony_ci pa_assert(c); 41053a5a1b3Sopenharmony_ci pa_assert(name); 41153a5a1b3Sopenharmony_ci 41253a5a1b3Sopenharmony_ci if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE))) 41353a5a1b3Sopenharmony_ci return PA_IDXSET_INVALID; 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci return e->index; 41653a5a1b3Sopenharmony_ci} 41753a5a1b3Sopenharmony_ci 41853a5a1b3Sopenharmony_cisize_t pa_scache_total_size(pa_core *c) { 41953a5a1b3Sopenharmony_ci pa_scache_entry *e; 42053a5a1b3Sopenharmony_ci uint32_t idx; 42153a5a1b3Sopenharmony_ci size_t sum = 0; 42253a5a1b3Sopenharmony_ci 42353a5a1b3Sopenharmony_ci pa_assert(c); 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci if (!c->scache || !pa_idxset_size(c->scache)) 42653a5a1b3Sopenharmony_ci return 0; 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(e, c->scache, idx) 42953a5a1b3Sopenharmony_ci if (e->memchunk.memblock) 43053a5a1b3Sopenharmony_ci sum += e->memchunk.length; 43153a5a1b3Sopenharmony_ci 43253a5a1b3Sopenharmony_ci return sum; 43353a5a1b3Sopenharmony_ci} 43453a5a1b3Sopenharmony_ci 43553a5a1b3Sopenharmony_civoid pa_scache_unload_unused(pa_core *c) { 43653a5a1b3Sopenharmony_ci pa_scache_entry *e; 43753a5a1b3Sopenharmony_ci time_t now; 43853a5a1b3Sopenharmony_ci uint32_t idx; 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci pa_assert(c); 44153a5a1b3Sopenharmony_ci 44253a5a1b3Sopenharmony_ci if (!c->scache || !pa_idxset_size(c->scache)) 44353a5a1b3Sopenharmony_ci return; 44453a5a1b3Sopenharmony_ci 44553a5a1b3Sopenharmony_ci time(&now); 44653a5a1b3Sopenharmony_ci 44753a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(e, c->scache, idx) { 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci if (!e->lazy || !e->memchunk.memblock) 45053a5a1b3Sopenharmony_ci continue; 45153a5a1b3Sopenharmony_ci 45253a5a1b3Sopenharmony_ci if (e->last_used_time + c->scache_idle_time > now) 45353a5a1b3Sopenharmony_ci continue; 45453a5a1b3Sopenharmony_ci 45553a5a1b3Sopenharmony_ci pa_memblock_unref(e->memchunk.memblock); 45653a5a1b3Sopenharmony_ci pa_memchunk_reset(&e->memchunk); 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); 45953a5a1b3Sopenharmony_ci } 46053a5a1b3Sopenharmony_ci} 46153a5a1b3Sopenharmony_ci 46253a5a1b3Sopenharmony_cistatic void add_file(pa_core *c, const char *pathname) { 46353a5a1b3Sopenharmony_ci struct stat st; 46453a5a1b3Sopenharmony_ci const char *e; 46553a5a1b3Sopenharmony_ci 46653a5a1b3Sopenharmony_ci pa_core_assert_ref(c); 46753a5a1b3Sopenharmony_ci pa_assert(pathname); 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci e = pa_path_get_filename(pathname); 47053a5a1b3Sopenharmony_ci 47153a5a1b3Sopenharmony_ci if (stat(pathname, &st) < 0) { 47253a5a1b3Sopenharmony_ci pa_log("stat('%s'): %s", pathname, pa_cstrerror(errno)); 47353a5a1b3Sopenharmony_ci return; 47453a5a1b3Sopenharmony_ci } 47553a5a1b3Sopenharmony_ci 47653a5a1b3Sopenharmony_ci#if defined(S_ISREG) && defined(S_ISLNK) 47753a5a1b3Sopenharmony_ci if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) 47853a5a1b3Sopenharmony_ci#endif 47953a5a1b3Sopenharmony_ci pa_scache_add_file_lazy(c, e, pathname, NULL); 48053a5a1b3Sopenharmony_ci} 48153a5a1b3Sopenharmony_ci 48253a5a1b3Sopenharmony_ciint pa_scache_add_directory_lazy(pa_core *c, const char *pathname) { 48353a5a1b3Sopenharmony_ci DIR *dir; 48453a5a1b3Sopenharmony_ci 48553a5a1b3Sopenharmony_ci pa_core_assert_ref(c); 48653a5a1b3Sopenharmony_ci pa_assert(pathname); 48753a5a1b3Sopenharmony_ci 48853a5a1b3Sopenharmony_ci /* First try to open this as directory */ 48953a5a1b3Sopenharmony_ci if (!(dir = opendir(pathname))) { 49053a5a1b3Sopenharmony_ci#ifdef HAVE_GLOB_H 49153a5a1b3Sopenharmony_ci glob_t p; 49253a5a1b3Sopenharmony_ci unsigned int i; 49353a5a1b3Sopenharmony_ci /* If that fails, try to open it as shell glob */ 49453a5a1b3Sopenharmony_ci 49553a5a1b3Sopenharmony_ci if (glob(pathname, GLOB_ERR|GLOB_NOSORT, NULL, &p) < 0) { 49653a5a1b3Sopenharmony_ci pa_log("failed to open directory '%s': %s", pathname, pa_cstrerror(errno)); 49753a5a1b3Sopenharmony_ci return -1; 49853a5a1b3Sopenharmony_ci } 49953a5a1b3Sopenharmony_ci 50053a5a1b3Sopenharmony_ci for (i = 0; i < p.gl_pathc; i++) 50153a5a1b3Sopenharmony_ci add_file(c, p.gl_pathv[i]); 50253a5a1b3Sopenharmony_ci 50353a5a1b3Sopenharmony_ci globfree(&p); 50453a5a1b3Sopenharmony_ci#else 50553a5a1b3Sopenharmony_ci return -1; 50653a5a1b3Sopenharmony_ci#endif 50753a5a1b3Sopenharmony_ci } else { 50853a5a1b3Sopenharmony_ci struct dirent *e; 50953a5a1b3Sopenharmony_ci 51053a5a1b3Sopenharmony_ci while ((e = readdir(dir))) { 51153a5a1b3Sopenharmony_ci char *p; 51253a5a1b3Sopenharmony_ci 51353a5a1b3Sopenharmony_ci if (e->d_name[0] == '.') 51453a5a1b3Sopenharmony_ci continue; 51553a5a1b3Sopenharmony_ci 51653a5a1b3Sopenharmony_ci p = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", pathname, e->d_name); 51753a5a1b3Sopenharmony_ci add_file(c, p); 51853a5a1b3Sopenharmony_ci pa_xfree(p); 51953a5a1b3Sopenharmony_ci } 52053a5a1b3Sopenharmony_ci 52153a5a1b3Sopenharmony_ci closedir(dir); 52253a5a1b3Sopenharmony_ci } 52353a5a1b3Sopenharmony_ci 52453a5a1b3Sopenharmony_ci return 0; 52553a5a1b3Sopenharmony_ci} 526