# If using GCC specifiy some additional parameters
if test "x$GCC" = "xyes" ; then
- CFLAGS="$CFLAGS -pipe -Wall -W -Wno-unused-parameter"
+ CFLAGS="$CFLAGS -pipe -W -Wall -Wno-unused-parameter -pedantic -std=c99"
fi
# LYNX documentation generation
<h2><a name="news">News</a></h2>
+<div class="news-date">Fri Aug 20 2004: </div> <p class="news-text"><a
+href="@PACKAGE_URL@polypaudio-0.2.tar.gz">Version 0.2</a> released;
+changes include: added sample cache, introspection API, client API
+documentation, module autoloading, glib support, a module for intercepting X11 bell events, and much more.</p>
<div class="news-date">Sat Jul 17 2004: </div> <p class="news-text"><a
href="@PACKAGE_URL@polypaudio-0.1.tar.gz">Version 0.1</a> released</p>
<tt>polypaudio</tt> has:</p>
<ul>
- <li>Extensible plugin architecture (<tt>dlopen()</tt>)</li>
+ <li>Extensible plugin architecture (by loading dynamic loadable modules with <tt>dlopen()</tt>)</li>
<li>Support for more than one sink/source</li>
<li>Better low latency behaviour</li>
<li>Embedabble into other software (the core is available as C library)</li>
<li>Simple command line interface for reconfiguring the daemon while running</li>
<li>Flexible, implicit sample type conversion and resampling</li>
<li>"Zero-Copy" architecture</li>
+ <li>Module autoloading</li>
</ul>
<p>Both the core and the client API are completely asynchronous making
a simplified synchronous API wrapper <tt>polyplib-simple</tt>
available. A simple main loop implementation is available as well.</p>
-<p><tt>polypaudio</tt> is the successor of my previous, ill-fated attempt to write a sound server <a href="http://asd.sf.net/">asd</a>.</p>
+<p><tt>polypaudio</tt> is the successor of my previous, ill-fated
+attempt to write a sound server <a
+href="http://asd.sf.net/">asd</a>.</p>
+
+<p>A GTK GUI manager application for polypaudio is the <a
+href="http://0pointer.de/projects/paman/">Polypaudio Manager</a>.</p>
<h2><a name="status">Status</a></h2>
-<p>Version @PACKAGE_VERSION@ is quite usable. <tt>polypaudio</tt> does
-not yet match all ESOUND features: currently a sample cache and
-automatic releasing of unused sound drivers are missing. Have a look
-on the more extensive <a
-href="http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/doc/todo?view=markup">TODO
-list</a>.</p>
+<p>Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.</p>
<h2><a name="documentation">Documentation</a></h2>
-<p>There is some prelimenary documentation available: <a
+<p>There is some preliminary documentation available: <a
href="modules.html"><tt>modules.html</tt></a>, <a
href="cli.html"><tt>cli.html</tt></a>, <a
-href="daemon.html"><tt>daemeon.html</tt></a>.</p>
+href="daemon.html"><tt>daemon.html</tt></a>.</p>
-<p>Documentation for developing with <tt>polypaudio</tt> is not yet
-available. Read the source, Luke! There are some example application
-available: for the <a
-href="http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/polyp/pacat.c?view=markup">asynchronous
-API</a> and for the <a
-href="http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/polyp/pacat-simple.c?view=markup">simple,
-synchronous API</a>.</p>
+<p>You may browser the <a href="http://www.doxygen.org/">Doxygen</a> generated <a
+href="http://0pointer.de/lennart/projects/polypaudio/doxygen/">programing
+documentation</a> for the client API. (Run <tt>make doxygen</tt> to generate this documentation from the source tree)</p>
<h3>First Steps</h3>
management.</p>
<p><tt>polypaudio</tt> needs <a
-href="http://www.mega-nerd.com/SRC/">Secret Rabbit Code (aka <tt>libsamplerate</tt>)</a> and <a href="http://www.alsa-project.org/">alsa-lib</a>.</p>
+href="http://www.mega-nerd.com/SRC/">Secret Rabbit Code (aka
+<tt>libsamplerate</tt>)</a>, <a href="http://www.mega-nerd.com/SND"><tt>libsndfile</tt></a> and <a
+href="http://www.alsa-project.org/">alsa-lib</a>.</p>
<h2><a name="installation">Installation</a></h2>
<p>If you want to be notified whenever I release a new version of this software use the subscription feature of <a href="http://freshmeat.net/projects/polypaudio/">Freshmeat</a>.</p>
<hr/>
-<address class="grey">Lennart Poettering <@PACKAGE_BUGREPORT@>, July 2004</address>
+<address class="grey">Lennart Poettering <@PACKAGE_BUGREPORT@>, August 2004</address>
<div class="grey"><i>$Id$</i></div>
</body>
s = pa_strbuf_new();
assert(s);
- pa_strbuf_printf(s, "%u cache entries available.\n", c->scache_hashmap ? pa_hashmap_ncontents(c->scache_hashmap) : 0);
+ pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_ncontents(c->scache) : 0);
- if (c->scache_hashmap) {
+ if (c->scache) {
struct pa_scache_entry *e;
- void *state = NULL;
+ uint32_t index = PA_IDXSET_INVALID;
- while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) {
+ for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) {
double l;
char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH];
pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec);
c->modules = NULL;
c->namereg = NULL;
- c->scache_idxset = NULL;
- c->scache_hashmap = NULL;
+ c->scache = NULL;
c->autoload_hashmap = NULL;
pa_check_for_sigpipe();
return c;
-};
+}
void pa_core_free(struct pa_core *c) {
assert(c);
assert(pa_idxset_isempty(c->sink_inputs));
pa_idxset_free(c->sink_inputs, NULL, NULL);
- pa_namereg_free(c);
pa_scache_free(c);
+ pa_namereg_free(c);
pa_autoload_free(c);
pa_subscription_free_all(c);
pa_memblock_stat_unref(c->memblock_stat);
pa_xfree(c);
-};
+}
struct pa_core {
struct pa_mainloop_api *mainloop;
- struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache_idxset;
+ struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache;
- struct pa_hashmap *namereg, *scache_hashmap, *autoload_hashmap;
+ struct pa_hashmap *namereg, *autoload_hashmap;
char *default_source_name, *default_sink_name;
}
static const struct pa_mainloop_api vtable = {
- userdata: NULL,
+ .userdata = NULL,
- io_new: glib_io_new,
- io_enable: glib_io_enable,
- io_free: glib_io_free,
- io_set_destroy: glib_io_set_destroy,
+ .io_new = glib_io_new,
+ .io_enable = glib_io_enable,
+ .io_free = glib_io_free,
+ .io_set_destroy= glib_io_set_destroy,
- time_new : glib_time_new,
- time_restart : glib_time_restart,
- time_free : glib_time_free,
- time_set_destroy : glib_time_set_destroy,
+ .time_new = glib_time_new,
+ .time_restart = glib_time_restart,
+ .time_free = glib_time_free,
+ .time_set_destroy = glib_time_set_destroy,
- defer_new : glib_defer_new,
- defer_enable : glib_defer_enable,
- defer_free : glib_defer_free,
- defer_set_destroy : glib_defer_set_destroy,
+ .defer_new = glib_defer_new,
+ .defer_enable = glib_defer_enable,
+ .defer_free = glib_defer_free,
+ .defer_set_destroy = glib_defer_set_destroy,
- quit : glib_quit,
+ .quit = glib_quit,
};
struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) {
#define PA_LLIST_HEAD(t,name) t *name
-#define PA_LLIST_FIELDS(t) t *next, *prev;
+#define PA_LLIST_FIELDS(t) t *next, *prev
#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0)
PA_IO_EVENT_INPUT = 1, /**< Input event */
PA_IO_EVENT_OUTPUT = 2, /**< Output event */
PA_IO_EVENT_HANGUP = 4, /**< Hangup event */
- PA_IO_EVENT_ERROR = 8, /**< Error event */
+ PA_IO_EVENT_ERROR = 8 /**< Error event */
};
/** \struct pa_io_event
#include "idxset.h"
#include "xmalloc.h"
-struct pa_base_event {
-};
-
struct pa_io_event {
struct pa_mainloop *mainloop;
int dead;
}
static const struct pa_mainloop_api vtable = {
- userdata: NULL,
+ .userdata = NULL,
- io_new: mainloop_io_new,
- io_enable: mainloop_io_enable,
- io_free: mainloop_io_free,
- io_set_destroy: mainloop_io_set_destroy,
+ .io_new= mainloop_io_new,
+ .io_enable= mainloop_io_enable,
+ .io_free= mainloop_io_free,
+ .io_set_destroy= mainloop_io_set_destroy,
- time_new : mainloop_time_new,
- time_restart : mainloop_time_restart,
- time_free : mainloop_time_free,
- time_set_destroy : mainloop_time_set_destroy,
+ .time_new = mainloop_time_new,
+ .time_restart = mainloop_time_restart,
+ .time_free = mainloop_time_free,
+ .time_set_destroy = mainloop_time_set_destroy,
- defer_new : mainloop_defer_new,
- defer_enable : mainloop_defer_enable,
- defer_free : mainloop_defer_free,
- defer_set_destroy : mainloop_defer_set_destroy,
+ .defer_new = mainloop_defer_new,
+ .defer_enable = mainloop_defer_enable,
+ .defer_free = mainloop_defer_free,
+ .defer_set_destroy = mainloop_defer_set_destroy,
- quit : mainloop_quit,
+ .quit = mainloop_quit,
};
struct pa_mainloop *pa_mainloop_new(void) {
pa_xfree(e);
*del = 1;
return 0;
-};
+}
static int time_foreach(void *p, uint32_t index, int *del, void*userdata) {
struct pa_time_event *e = p;
pa_xfree(e);
*del = 1;
return 0;
-};
+}
static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) {
struct pa_defer_event *e = p;
pa_xfree(e);
*del = 1;
return 0;
-};
+}
void pa_mainloop_free(struct pa_mainloop* m) {
int all = 1;
*/
static uint32_t age(struct timeval *tv) {
- assert(tv);
struct timeval now;
uint32_t r;
+ assert(tv);
if (tv->tv_sec == 0)
return 0;
}
int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) {
- assert(m && c && m->base > m->buffer_fill);
int ret;
+ assert(m && c && m->base > m->buffer_fill);
if (!m->chunk.memblock)
return -1;
in_post_memblocks(u, info.blocks);
in_clear_memblocks(u, u->in_fragments/2);
-};
+}
static void io_callback(struct pa_mainloop_api *m, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
struct userdata *u = userdata;
pa_source_post(u->source, &memchunk);
pa_memblock_unref(memchunk.memblock);
-};
+}
static void io_callback(struct pa_iochannel *io, void*userdata) {
struct userdata *u = userdata;
name = c->default_source_name;
- } else {
- assert(type == PA_NAMEREG_SINK);
+ } else if (type == PA_NAMEREG_SINK) {
if (!c->default_sink_name) {
struct pa_sink *s;
d = pa_idxset_get_by_index(c->sinks, index);
else if (type == PA_NAMEREG_SOURCE)
d = pa_idxset_get_by_index(c->sources, index);
-
+ else if (type == PA_NAMEREG_SAMPLE && c->scache)
+ d = pa_idxset_get_by_index(c->scache, index);
+
return d;
}
void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type) {
char **s;
- assert(c);
+ assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE));
s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name;
assert(s);
enum pa_namereg_type {
PA_NAMEREG_SINK,
- PA_NAMEREG_SOURCE
+ PA_NAMEREG_SOURCE,
+ PA_NAMEREG_SAMPLE
};
void pa_namereg_free(struct pa_core *c);
PA_STREAM_CREATING, /**< The stream is being created */
PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */
PA_STREAM_FAILED, /**< An error occured that made the stream invalid */
- PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */
+ PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */
};
/** The state of an operation */
enum pa_operation_state {
PA_OPERATION_RUNNING, /**< The operation is still running */
PA_OPERATION_DONE, /**< The operation has been completed */
- PA_OPERATION_CANCELED, /**< The operation has been canceled */
+ PA_OPERATION_CANCELED /**< The operation has been canceled */
};
/** An invalid index */
PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */
PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */
PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */
- PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */
+ PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64 /**< Sample cache events */
};
/** Subscription event types, as used by pa_context_subscribe() */
PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */
PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */
PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */
- PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, /**< A mask to extract the event operation from an event value */
+ PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */
};
/** Return one if an event type t matches an event mask bitfield */
return pa_operation_ref(o);
}
+
+/** Sample Cache **/
+
+static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+ struct pa_operation *o = userdata;
+ int eof = 1;
+ assert(pd && o && o->context && o->ref >= 1);
+
+ if (command != PA_COMMAND_REPLY) {
+ if (pa_context_handle_error(o->context, command, t) < 0)
+ goto finish;
+
+ eof = -1;
+ } else {
+
+ while (!pa_tagstruct_eof(t)) {
+ struct pa_sample_info i;
+
+ if (pa_tagstruct_getu32(t, &i.index) < 0 ||
+ pa_tagstruct_gets(t, &i.name) < 0 ||
+ pa_tagstruct_getu32(t, &i.volume) < 0 ||
+ pa_tagstruct_getu32(t, &i.duration) < 0 ||
+ pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0) {
+ pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+ goto finish;
+ }
+
+ if (o->callback) {
+ void (*cb)(struct pa_context *s, const struct pa_sample_info*i, int eof, void *userdata) = o->callback;
+ cb(o->context, &i, 0, o->userdata);
+ }
+ }
+ }
+
+ if (o->callback) {
+ void (*cb)(struct pa_context *s, const struct pa_sample_info*i, int eof, void *userdata) = o->callback;
+ cb(o->context, NULL, eof, o->userdata);
+ }
+
+finish:
+ pa_operation_done(o);
+ pa_operation_unref(o);
+}
+
+struct pa_operation* pa_context_get_sample_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) {
+ struct pa_tagstruct *t;
+ struct pa_operation *o;
+ uint32_t tag;
+ assert(c && cb && name);
+
+ o = pa_operation_new(c, NULL);
+ o->callback = cb;
+ o->userdata = userdata;
+
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO);
+ pa_tagstruct_putu32(t, tag = c->ctag++);
+ pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+ pa_tagstruct_puts(t, name);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o);
+
+ return pa_operation_ref(o);
+}
+
+struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) {
+ struct pa_tagstruct *t;
+ struct pa_operation *o;
+ uint32_t tag;
+ assert(c && cb);
+
+ o = pa_operation_new(c, NULL);
+ o->callback = cb;
+ o->userdata = userdata;
+
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO);
+ pa_tagstruct_putu32(t, tag = c->ctag++);
+ pa_tagstruct_putu32(t, index);
+ pa_tagstruct_puts(t, "");
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o);
+
+ return pa_operation_ref(o);
+}
+
+struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata) {
+ return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, cb, userdata);
+}
/** Get daemon memory block statistics */
struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata);
+struct pa_sample_info {
+ uint32_t index;
+ const char *name;
+ uint32_t volume;
+ struct pa_sample_spec sample_spec;
+ uint32_t duration;
+};
+
+struct pa_operation* pa_context_get_sample_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_sample_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata), void *userdata);
+
PA_C_DECL_END
#endif
***/
#include "cdecl.h"
+#include "polyplib-def.h"
/** \file
* Asynchronous operations */
#include "pstream-util.h"
struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) {
- assert(c && ss);
struct pa_stream *s;
+ assert(c && ss);
s = pa_xmalloc(sizeof(struct pa_stream));
s->ref = 1;
k = sizeof(int)*5+ESD_NAME_MAX;
s = sizeof(int)*6+ESD_NAME_MAX;
- nsamples = c->protocol->core->scache_idxset ? pa_idxset_ncontents(c->protocol->core->scache_idxset) : 0;
+ nsamples = c->protocol->core->scache ? pa_idxset_ncontents(c->protocol->core->scache) : 0;
response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1)));
assert(k);
struct pa_scache_entry *ce;
index = PA_IDXSET_INVALID;
- for (ce = pa_idxset_first(c->protocol->core->scache_idxset, &index); ce; ce = pa_idxset_next(c->protocol->core->scache_idxset, &index)) {
+ for (ce = pa_idxset_first(c->protocol->core->scache, &index); ce; ce = pa_idxset_next(c->protocol->core->scache, &index)) {
assert(t >= s*2);
/* id */
[PA_COMMAND_GET_MODULE_INFO] = { command_get_info },
[PA_COMMAND_GET_SINK_INPUT_INFO] = { command_get_info },
[PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = { command_get_info },
+ [PA_COMMAND_GET_SAMPLE_INFO] = { command_get_info },
[PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_MODULE_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_CLIENT_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = { command_get_info_list },
+ [PA_COMMAND_GET_SAMPLE_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info },
[PA_COMMAND_SUBSCRIBE] = { command_subscribe },
[PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume },
static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
struct connection *c = userdata;
- assert(c && t);
struct pa_tagstruct *reply;
+ assert(c && t);
if (!pa_tagstruct_eof(t)) {
protocol_error(c);
static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
struct connection *c = userdata;
- assert(c && t);
struct pa_tagstruct *reply;
struct playback_stream *s;
uint32_t index, latency;
+ assert(c && t);
if (pa_tagstruct_getu32(t, &index) < 0 ||
!pa_tagstruct_eof(t)) {
pa_tagstruct_put_sample_spec(t, &s->sample_spec);
}
+static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry *e) {
+ assert(t && e);
+ pa_tagstruct_putu32(t, e->index);
+ pa_tagstruct_puts(t, e->name);
+ pa_tagstruct_putu32(t, e->volume);
+ pa_tagstruct_putu32(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec));
+ pa_tagstruct_put_sample_spec(t, &e->sample_spec);
+}
+
static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
struct connection *c = userdata;
uint32_t index;
struct pa_module *module = NULL;
struct pa_sink_input *si = NULL;
struct pa_source_output *so = NULL;
+ struct pa_scache_entry *sce = NULL;
const char *name;
struct pa_tagstruct *reply;
assert(c && t);
module = pa_idxset_get_by_index(c->protocol->core->modules, index);
else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index);
- else {
- assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO);
+ else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
so = pa_idxset_get_by_index(c->protocol->core->source_outputs, index);
+ else {
+ assert(command == PA_COMMAND_GET_SAMPLE_INFO && name);
+ if (index != (uint32_t) -1)
+ sce = pa_idxset_get_by_index(c->protocol->core->scache, index);
+ else
+ sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0);
}
- if (!sink && !source && !client && !module && !si && !so) {
+ if (!sink && !source && !client && !module && !si && !so && !sce) {
pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY);
return;
}
module_fill_tagstruct(reply, module);
else if (si)
sink_input_fill_tagstruct(reply, si);
- else
+ else if (so)
source_output_fill_tagstruct(reply, so);
+ else
+ scache_fill_tagstruct(reply, sce);
pa_pstream_send_tagstruct(c->pstream, reply);
}
i = c->protocol->core->modules;
else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
i = c->protocol->core->sink_inputs;
- else {
- assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST);
+ else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
i = c->protocol->core->source_outputs;
+ else {
+ assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
+ i = c->protocol->core->scache;
}
-
+
for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) {
if (command == PA_COMMAND_GET_SINK_INFO_LIST)
sink_fill_tagstruct(reply, p);
module_fill_tagstruct(reply, p);
else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
sink_input_fill_tagstruct(reply, p);
- else {
- assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST);
+ else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
source_output_fill_tagstruct(reply, p);
+ else {
+ assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
+ scache_fill_tagstruct(reply, p);
}
}
#include "sample.h"
size_t pa_frame_size(const struct pa_sample_spec *spec) {
- assert(spec);
size_t b = 1;
+ assert(spec);
switch (spec->format) {
case PA_SAMPLE_U8:
#include "play-memchunk.h"
#include "xmalloc.h"
#include "subscribe.h"
+#include "namereg.h"
static void free_entry(struct pa_scache_entry *e) {
assert(e);
+ pa_namereg_unregister(e->core, e->name);
pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index);
pa_xfree(e->name);
if (e->memchunk.memblock)
pa_xfree(e);
}
-void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) {
+int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) {
struct pa_scache_entry *e;
int put;
assert(c && name);
- if (c->scache_hashmap && (e = pa_hashmap_get(c->scache_hashmap, name))) {
+ if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) {
put = 0;
if (e->memchunk.memblock)
pa_memblock_unref(e->memchunk.memblock);
assert(e->core == c);
} else {
+
put = 1;
e = pa_xmalloc(sizeof(struct pa_scache_entry));
+
+ if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) {
+ pa_xfree(e);
+ return -1;
+ }
+
e->name = pa_xstrdup(name);
e->core = c;
}
- e->volume = 0x100;
-
+ e->volume = PA_VOLUME_NORM;
+
if (ss)
e->sample_spec = *ss;
else
}
if (put) {
- if (!c->scache_hashmap) {
- c->scache_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
- assert(c->scache_hashmap);
- }
-
- if (!c->scache_idxset) {
- c->scache_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- assert(c->scache_idxset);
+ if (!c->scache) {
+ c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+ assert(c->scache);
}
- pa_idxset_put(c->scache_idxset, e, &e->index);
- pa_hashmap_put(c->scache_hashmap, e->name, e);
+ pa_idxset_put(c->scache, e, &e->index);
pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index);
- }
+ } else
+ pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index);
if (index)
*index = e->index;
+
+ return 0;
}
int pa_scache_remove_item(struct pa_core *c, const char *name) {
struct pa_scache_entry *e;
assert(c && name);
- if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name)))
+ if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
return -1;
- pa_hashmap_remove(c->scache_hashmap, name);
- if (pa_idxset_remove_by_data(c->scache_idxset, e, NULL) != e)
+ if (pa_idxset_remove_by_data(c->scache, e, NULL) != e)
assert(0);
free_entry(e);
void pa_scache_free(struct pa_core *c) {
assert(c);
- if (c->scache_hashmap) {
- pa_hashmap_free(c->scache_hashmap, free_cb, NULL);
- c->scache_hashmap = NULL;
- }
-
- if (c->scache_idxset) {
- pa_idxset_free(c->scache_idxset, NULL, NULL);
- c->scache_idxset = NULL;
+ if (c->scache) {
+ pa_idxset_free(c->scache, free_cb, NULL);
+ c->scache = NULL;
}
}
struct pa_scache_entry *e;
assert(c && name && sink);
- if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name)))
+ if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
return -1;
if (!e->memchunk.memblock)
struct pa_scache_entry *e;
assert(c && id != PA_IDXSET_INVALID);
- if (!c->scache_idxset || !(e = pa_idxset_get_by_index(c->scache_idxset, id)))
+ if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id)))
return NULL;
return e->name;
}
-
-uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) {
- struct pa_scache_entry *e;
- assert(c && name);
-
- if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name)))
- return PA_IDXSET_INVALID;
-
- return e->index;
-}
struct pa_memchunk memchunk;
};
-void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index);
+int pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index);
int pa_scache_remove_item(struct pa_core *c, const char *name);
int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume);
struct chunk {
struct chunk *next;
size_t length;
- char text[];
+ char text[0];
};
struct pa_strbuf {
char *pa_strbuf_tostring(struct pa_strbuf *sb);
char *pa_strbuf_tostring_free(struct pa_strbuf *sb);
-int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) __attribute__ ((format (printf, 2, 3)));;
+int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
void pa_strbuf_puts(struct pa_strbuf *sb, const char *t);
void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t m);