]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/core-scache.c
core: Add name to flist struct for more informative log messages
[pulseaudio] / src / pulsecore / core-scache.c
index 75fa2ff17eda05d7d56626f92d6b03062f23d3a2..5ec6159d67f9d9681c92aceda3b60e48e8019ff6 100644 (file)
@@ -6,7 +6,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
@@ -47,6 +47,7 @@
 #include <pulse/util.h>
 #include <pulse/volume.h>
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
 #include <pulse/volume.h>
 #include <pulse/xmalloc.h>
+#include <pulse/rtclock.h>
 
 #include <pulsecore/sink-input.h>
 #include <pulsecore/sample-util.h>
 
 #include <pulsecore/sink-input.h>
 #include <pulsecore/sample-util.h>
@@ -54,6 +55,7 @@
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/sound-file.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/sound-file.h>
+#include <pulsecore/core-rtclock.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-error.h>
 
 #include "core-scache.h"
 
 
 #include "core-scache.h"
 
-#define UNLOAD_POLL_TIME 60
+#define UNLOAD_POLL_TIME (60 * PA_USEC_PER_SEC)
 
 
-static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
+static void timeout_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
     pa_core *c = userdata;
     pa_core *c = userdata;
-    struct timeval ntv;
 
     pa_assert(c);
     pa_assert(c->mainloop == m);
 
     pa_assert(c);
     pa_assert(c->mainloop == m);
@@ -73,9 +74,7 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED
 
     pa_scache_unload_unused(c);
 
 
     pa_scache_unload_unused(c);
 
-    pa_gettimeofday(&ntv);
-    ntv.tv_sec += UNLOAD_POLL_TIME;
-    m->time_restart(e, &ntv);
+    pa_core_rttime_restart(c, e, pa_rtclock_now() + UNLOAD_POLL_TIME);
 }
 
 static void free_entry(pa_scache_entry *e) {
 }
 
 static void free_entry(pa_scache_entry *e) {
@@ -98,7 +97,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
     pa_assert(c);
     pa_assert(name);
 
     pa_assert(c);
     pa_assert(name);
 
-    if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) {
+    if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE))) {
         if (e->memchunk.memblock)
             pa_memblock_unref(e->memchunk.memblock);
 
         if (e->memchunk.memblock)
             pa_memblock_unref(e->memchunk.memblock);
 
@@ -111,7 +110,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
     } else {
         e = pa_xnew(pa_scache_entry, 1);
 
     } else {
         e = pa_xnew(pa_scache_entry, 1);
 
-        if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) {
+        if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, TRUE)) {
             pa_xfree(e);
             return NULL;
         }
             pa_xfree(e);
             return NULL;
         }
@@ -120,9 +119,6 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
         e->core = c;
         e->proplist = pa_proplist_new();
 
         e->core = c;
         e->proplist = pa_proplist_new();
 
-        if (!c->scache)
-            c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-
         pa_idxset_put(c->scache, e, &e->index);
 
         pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index);
         pa_idxset_put(c->scache, e, &e->index);
 
         pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index);
@@ -134,9 +130,10 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
     e->lazy = FALSE;
     e->last_used_time = 0;
 
     e->lazy = FALSE;
     e->last_used_time = 0;
 
-    memset(&e->sample_spec, 0, sizeof(e->sample_spec));
+    pa_sample_spec_init(&e->sample_spec);
     pa_channel_map_init(&e->channel_map);
     pa_channel_map_init(&e->channel_map);
-    pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX);
+    pa_cvolume_init(&e->volume);
+    e->volume_is_set = FALSE;
 
     pa_proplist_sets(e->proplist, PA_PROP_MEDIA_ROLE, "event");
 
 
     pa_proplist_sets(e->proplist, PA_PROP_MEDIA_ROLE, "event");
 
@@ -159,10 +156,12 @@ int pa_scache_add_item(
     pa_assert(c);
     pa_assert(name);
     pa_assert(!ss || pa_sample_spec_valid(ss));
     pa_assert(c);
     pa_assert(name);
     pa_assert(!ss || pa_sample_spec_valid(ss));
-    pa_assert(!map || (pa_channel_map_valid(map) && ss && ss->channels == map->channels));
+    pa_assert(!map || (pa_channel_map_valid(map) && ss && pa_channel_map_compatible(map, ss)));
 
 
-    if (ss && !map)
+    if (ss && !map) {
         pa_channel_map_init_extend(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT);
         pa_channel_map_init_extend(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT);
+        map = &tmap;
+    }
 
     if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX)
         return -1;
 
     if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX)
         return -1;
@@ -170,12 +169,14 @@ int pa_scache_add_item(
     if (!(e = scache_add_item(c, name)))
         return -1;
 
     if (!(e = scache_add_item(c, name)))
         return -1;
 
-    memset(&e->sample_spec, 0, sizeof(e->sample_spec));
+    pa_sample_spec_init(&e->sample_spec);
     pa_channel_map_init(&e->channel_map);
     pa_channel_map_init(&e->channel_map);
+    pa_cvolume_init(&e->volume);
+    e->volume_is_set = FALSE;
 
     if (ss) {
         e->sample_spec = *ss;
 
     if (ss) {
         e->sample_spec = *ss;
-        e->volume.channels = e->sample_spec.channels;
+        pa_cvolume_reset(&e->volume, ss->channels);
     }
 
     if (map)
     }
 
     if (map)
@@ -217,11 +218,14 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3
     pa_assert(name);
     pa_assert(filename);
 
     pa_assert(name);
     pa_assert(filename);
 
-    if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk) < 0)
-        return -1;
-
     p = pa_proplist_new();
     pa_proplist_sets(p, PA_PROP_MEDIA_FILENAME, filename);
     p = pa_proplist_new();
     pa_proplist_sets(p, PA_PROP_MEDIA_FILENAME, filename);
+
+    if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk, p) < 0) {
+        pa_proplist_free(p);
+        return -1;
+    }
+
     r = pa_scache_add_item(c, name, &ss, &map, &chunk, p, idx);
     pa_memblock_unref(chunk.memblock);
     pa_proplist_free(p);
     r = pa_scache_add_item(c, name, &ss, &map, &chunk, p, idx);
     pa_memblock_unref(chunk.memblock);
     pa_proplist_free(p);
@@ -251,12 +255,8 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename,
 
     pa_proplist_sets(e->proplist, PA_PROP_MEDIA_FILENAME, filename);
 
 
     pa_proplist_sets(e->proplist, PA_PROP_MEDIA_FILENAME, filename);
 
-    if (!c->scache_auto_unload_event) {
-        struct timeval ntv;
-        pa_gettimeofday(&ntv);
-        ntv.tv_sec += UNLOAD_POLL_TIME;
-        c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
-    }
+    if (!c->scache_auto_unload_event)
+        c->scache_auto_unload_event = pa_core_rttime_new(c, pa_rtclock_now() + UNLOAD_POLL_TIME, timeout_callback, c);
 
     if (idx)
         *idx = e->index;
 
     if (idx)
         *idx = e->index;
@@ -270,7 +270,7 @@ int pa_scache_remove_item(pa_core *c, const char *name) {
     pa_assert(c);
     pa_assert(name);
 
     pa_assert(c);
     pa_assert(name);
 
-    if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
+    if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE)))
         return -1;
 
     pa_assert_se(pa_idxset_remove_by_data(c->scache, e, NULL) == e);
         return -1;
 
     pa_assert_se(pa_idxset_remove_by_data(c->scache, e, NULL) == e);
@@ -282,68 +282,82 @@ int pa_scache_remove_item(pa_core *c, const char *name) {
     return 0;
 }
 
     return 0;
 }
 
-static void free_cb(void *p, PA_GCC_UNUSED void *userdata) {
-    pa_scache_entry *e = p;
-    pa_assert(e);
-
-    free_entry(e);
-}
+void pa_scache_free_all(pa_core *c) {
+    pa_scache_entry *e;
 
 
-void pa_scache_free(pa_core *c) {
     pa_assert(c);
 
     pa_assert(c);
 
-    if (c->scache) {
-        pa_idxset_free(c->scache, free_cb, NULL);
-        c->scache = NULL;
-    }
+    while ((e = pa_idxset_steal_first(c->scache, NULL)))
+        free_entry(e);
 
 
-    if (c->scache_auto_unload_event)
+    if (c->scache_auto_unload_event) {
         c->mainloop->time_free(c->scache_auto_unload_event);
         c->mainloop->time_free(c->scache_auto_unload_event);
+        c->scache_auto_unload_event = NULL;
+    }
 }
 
 int 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) {
     pa_scache_entry *e;
     pa_cvolume r;
     pa_proplist *merged;
 }
 
 int 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) {
     pa_scache_entry *e;
     pa_cvolume r;
     pa_proplist *merged;
+    pa_bool_t pass_volume;
 
     pa_assert(c);
     pa_assert(name);
     pa_assert(sink);
 
 
     pa_assert(c);
     pa_assert(name);
     pa_assert(sink);
 
-    if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1)))
+    if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE)))
         return -1;
 
         return -1;
 
+    merged = pa_proplist_new();
+    pa_proplist_sets(merged, PA_PROP_MEDIA_NAME, name);
+    pa_proplist_sets(merged, PA_PROP_EVENT_ID, name);
+
     if (e->lazy && !e->memchunk.memblock) {
     if (e->lazy && !e->memchunk.memblock) {
-        if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk) < 0)
-            return -1;
+        pa_channel_map old_channel_map = e->channel_map;
+
+        if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, merged) < 0)
+            goto fail;
 
         pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index);
 
 
         pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index);
 
-        if (e->volume.channels > e->sample_spec.channels)
-            e->volume.channels = e->sample_spec.channels;
+        if (e->volume_is_set) {
+            if (pa_cvolume_valid(&e->volume))
+                pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map);
+            else
+                pa_cvolume_reset(&e->volume, e->sample_spec.channels);
+        }
     }
 
     if (!e->memchunk.memblock)
     }
 
     if (!e->memchunk.memblock)
-        return -1;
+        goto fail;
 
     pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name);
 
 
     pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name);
 
-    pa_cvolume_set(&r, e->volume.channels, volume);
-    pa_sw_cvolume_multiply(&r, &r, &e->volume);
-
-    merged = pa_proplist_new();
+    pass_volume = TRUE;
 
 
-    pa_proplist_setf(merged, PA_PROP_MEDIA_NAME, "Sample %s", name);
+    if (e->volume_is_set && PA_VOLUME_IS_VALID(volume)) {
+        pa_cvolume_set(&r, e->sample_spec.channels, volume);
+        pa_sw_cvolume_multiply(&r, &r, &e->volume);
+    } else if (e->volume_is_set)
+        r = e->volume;
+    else if (PA_VOLUME_IS_VALID(volume))
+        pa_cvolume_set(&r, e->sample_spec.channels, volume);
+    else
+        pass_volume = FALSE;
 
     pa_proplist_update(merged, PA_UPDATE_REPLACE, e->proplist);
 
     if (p)
         pa_proplist_update(merged, PA_UPDATE_REPLACE, p);
 
 
     pa_proplist_update(merged, PA_UPDATE_REPLACE, e->proplist);
 
     if (p)
         pa_proplist_update(merged, PA_UPDATE_REPLACE, p);
 
-    if (pa_play_memchunk(sink, &e->sample_spec, &e->channel_map, &e->memchunk, &r, merged, sink_input_idx) < 0) {
-        pa_proplist_free(merged);
-        return -1;
-    }
+    if (pa_play_memchunk(sink,
+                         &e->sample_spec, &e->channel_map,
+                         &e->memchunk,
+                         pass_volume ? &r : NULL,
+                         merged,
+                         PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND, sink_input_idx) < 0)
+        goto fail;
 
     pa_proplist_free(merged);
 
 
     pa_proplist_free(merged);
 
@@ -351,15 +365,19 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t
         time(&e->last_used_time);
 
     return 0;
         time(&e->last_used_time);
 
     return 0;
+
+fail:
+    pa_proplist_free(merged);
+    return -1;
 }
 
 }
 
-int pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_bool_t autoload, pa_volume_t volume, pa_proplist *p, uint32_t *sink_input_idx) {
+int 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) {
     pa_sink *sink;
 
     pa_assert(c);
     pa_assert(name);
 
     pa_sink *sink;
 
     pa_assert(c);
     pa_assert(name);
 
-    if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, autoload)))
+    if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK)))
         return -1;
 
     return pa_scache_play_item(c, name, sink, volume, p, sink_input_idx);
         return -1;
 
     return pa_scache_play_item(c, name, sink, volume, p, sink_input_idx);
@@ -383,7 +401,7 @@ uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) {
     pa_assert(c);
     pa_assert(name);
 
     pa_assert(c);
     pa_assert(name);
 
-    if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
+    if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE)))
         return PA_IDXSET_INVALID;
 
     return e->index;
         return PA_IDXSET_INVALID;
 
     return e->index;
@@ -482,13 +500,14 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) {
         struct dirent *e;
 
         while ((e = readdir(dir))) {
         struct dirent *e;
 
         while ((e = readdir(dir))) {
-            char p[PATH_MAX];
+            char *p;
 
             if (e->d_name[0] == '.')
                 continue;
 
 
             if (e->d_name[0] == '.')
                 continue;
 
-            pa_snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name);
+            p = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", pathname, e->d_name);
             add_file(c, p);
             add_file(c, p);
+            pa_xfree(p);
         }
 
         closedir(dir);
         }
 
         closedir(dir);