move sample cache to namereg

documentation


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@141 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-08-19 23:14:59 +00:00
parent e0fe68a2d4
commit f9b58fb0ea
27 changed files with 252 additions and 136 deletions

View file

@ -87,7 +87,7 @@ AC_SUBST(GLIB20_LIBS)
# If using GCC specifiy some additional parameters # If using GCC specifiy some additional parameters
if test "x$GCC" = "xyes" ; then 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 fi
# LYNX documentation generation # LYNX documentation generation

View file

@ -42,6 +42,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.</p>
<h2><a name="news">News</a></h2> <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 <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> href="@PACKAGE_URL@polypaudio-0.1.tar.gz">Version 0.1</a> released</p>
@ -56,7 +60,7 @@ Daemon</a> (ESOUND). In addition to the features ESOUND provides
<tt>polypaudio</tt> has:</p> <tt>polypaudio</tt> has:</p>
<ul> <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>Support for more than one sink/source</li>
<li>Better low latency behaviour</li> <li>Better low latency behaviour</li>
<li>Embedabble into other software (the core is available as C library)</li> <li>Embedabble into other software (the core is available as C library)</li>
@ -64,6 +68,7 @@ Daemon</a> (ESOUND). In addition to the features ESOUND provides
<li>Simple command line interface for reconfiguring the daemon while running</li> <li>Simple command line interface for reconfiguring the daemon while running</li>
<li>Flexible, implicit sample type conversion and resampling</li> <li>Flexible, implicit sample type conversion and resampling</li>
<li>"Zero-Copy" architecture</li> <li>"Zero-Copy" architecture</li>
<li>Module autoloading</li>
</ul> </ul>
<p>Both the core and the client API are completely asynchronous making <p>Both the core and the client API are completely asynchronous making
@ -74,31 +79,27 @@ available through <tt>polyplib</tt> is quite difficult to use there is
a simplified synchronous API wrapper <tt>polyplib-simple</tt> a simplified synchronous API wrapper <tt>polyplib-simple</tt>
available. A simple main loop implementation is available as well.</p> 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> <h2><a name="status">Status</a></h2>
<p>Version @PACKAGE_VERSION@ is quite usable. <tt>polypaudio</tt> does <p>Version @PACKAGE_VERSION@ is quite usable. It matches and supersedes ESOUND's feature set in nearly all areas.</p>
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>
<h2><a name="documentation">Documentation</a></h2> <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="modules.html"><tt>modules.html</tt></a>, <a
href="cli.html"><tt>cli.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 <p>You may browser the <a href="http://www.doxygen.org/">Doxygen</a> generated <a
available. Read the source, Luke! There are some example application href="http://0pointer.de/lennart/projects/polypaudio/doxygen/">programing
available: for the <a documentation</a> for the client API. (Run <tt>make doxygen</tt> to generate this documentation from the source tree)</p>
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>
<h3>First Steps</h3> <h3>First Steps</h3>
@ -131,7 +132,9 @@ GNU libtool for source code configuration and shared library
management.</p> management.</p>
<p><tt>polypaudio</tt> needs <a <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> <h2><a name="installation">Installation</a></h2>
@ -156,7 +159,7 @@ compilation and <tt>make install</tt> (as root) for installation of
<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> <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/> <hr/>
<address class="grey">Lennart Poettering &lt;@PACKAGE_BUGREPORT@&gt;, July 2004</address> <address class="grey">Lennart Poettering &lt;@PACKAGE_BUGREPORT@&gt;, August 2004</address>
<div class="grey"><i>$Id$</i></div> <div class="grey"><i>$Id$</i></div>
</body> </body>

View file

@ -212,13 +212,13 @@ char *pa_scache_list_to_string(struct pa_core *c) {
s = pa_strbuf_new(); s = pa_strbuf_new();
assert(s); 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; 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; double l;
char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH];
pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec);

View file

@ -53,8 +53,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->modules = NULL; c->modules = NULL;
c->namereg = NULL; c->namereg = NULL;
c->scache_idxset = NULL; c->scache = NULL;
c->scache_hashmap = NULL;
c->autoload_hashmap = NULL; c->autoload_hashmap = NULL;
@ -74,7 +73,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
pa_check_for_sigpipe(); pa_check_for_sigpipe();
return c; return c;
}; }
void pa_core_free(struct pa_core *c) { void pa_core_free(struct pa_core *c) {
assert(c); assert(c);
@ -97,8 +96,8 @@ void pa_core_free(struct pa_core *c) {
assert(pa_idxset_isempty(c->sink_inputs)); assert(pa_idxset_isempty(c->sink_inputs));
pa_idxset_free(c->sink_inputs, NULL, NULL); pa_idxset_free(c->sink_inputs, NULL, NULL);
pa_namereg_free(c);
pa_scache_free(c); pa_scache_free(c);
pa_namereg_free(c);
pa_autoload_free(c); pa_autoload_free(c);
pa_subscription_free_all(c); pa_subscription_free_all(c);
@ -108,5 +107,5 @@ void pa_core_free(struct pa_core *c) {
pa_memblock_stat_unref(c->memblock_stat); pa_memblock_stat_unref(c->memblock_stat);
pa_xfree(c); pa_xfree(c);
}; }

View file

@ -31,9 +31,9 @@
struct pa_core { struct pa_core {
struct pa_mainloop_api *mainloop; 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; char *default_source_name, *default_sink_name;

View file

@ -384,24 +384,24 @@ static void glib_quit(struct pa_mainloop_api*a, int retval) {
} }
static const struct pa_mainloop_api vtable = { static const struct pa_mainloop_api vtable = {
userdata: NULL, .userdata = NULL,
io_new: glib_io_new, .io_new = glib_io_new,
io_enable: glib_io_enable, .io_enable = glib_io_enable,
io_free: glib_io_free, .io_free = glib_io_free,
io_set_destroy: glib_io_set_destroy, .io_set_destroy= glib_io_set_destroy,
time_new : glib_time_new, .time_new = glib_time_new,
time_restart : glib_time_restart, .time_restart = glib_time_restart,
time_free : glib_time_free, .time_free = glib_time_free,
time_set_destroy : glib_time_set_destroy, .time_set_destroy = glib_time_set_destroy,
defer_new : glib_defer_new, .defer_new = glib_defer_new,
defer_enable : glib_defer_enable, .defer_enable = glib_defer_enable,
defer_free : glib_defer_free, .defer_free = glib_defer_free,
defer_set_destroy : glib_defer_set_destroy, .defer_set_destroy = glib_defer_set_destroy,
quit : glib_quit, .quit = glib_quit,
}; };
struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) {

View file

@ -24,7 +24,7 @@
#define PA_LLIST_HEAD(t,name) t *name #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) #define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0)

View file

@ -50,7 +50,7 @@ enum pa_io_event_flags {
PA_IO_EVENT_INPUT = 1, /**< Input event */ PA_IO_EVENT_INPUT = 1, /**< Input event */
PA_IO_EVENT_OUTPUT = 2, /**< Output event */ PA_IO_EVENT_OUTPUT = 2, /**< Output event */
PA_IO_EVENT_HANGUP = 4, /**< Hangup 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 /** \struct pa_io_event

View file

@ -38,9 +38,6 @@
#include "idxset.h" #include "idxset.h"
#include "xmalloc.h" #include "xmalloc.h"
struct pa_base_event {
};
struct pa_io_event { struct pa_io_event {
struct pa_mainloop *mainloop; struct pa_mainloop *mainloop;
int dead; int dead;
@ -225,24 +222,24 @@ static void mainloop_quit(struct pa_mainloop_api*a, int retval) {
} }
static const struct pa_mainloop_api vtable = { static const struct pa_mainloop_api vtable = {
userdata: NULL, .userdata = NULL,
io_new: mainloop_io_new, .io_new= mainloop_io_new,
io_enable: mainloop_io_enable, .io_enable= mainloop_io_enable,
io_free: mainloop_io_free, .io_free= mainloop_io_free,
io_set_destroy: mainloop_io_set_destroy, .io_set_destroy= mainloop_io_set_destroy,
time_new : mainloop_time_new, .time_new = mainloop_time_new,
time_restart : mainloop_time_restart, .time_restart = mainloop_time_restart,
time_free : mainloop_time_free, .time_free = mainloop_time_free,
time_set_destroy : mainloop_time_set_destroy, .time_set_destroy = mainloop_time_set_destroy,
defer_new : mainloop_defer_new, .defer_new = mainloop_defer_new,
defer_enable : mainloop_defer_enable, .defer_enable = mainloop_defer_enable,
defer_free : mainloop_defer_free, .defer_free = mainloop_defer_free,
defer_set_destroy : mainloop_defer_set_destroy, .defer_set_destroy = mainloop_defer_set_destroy,
quit : mainloop_quit, .quit = mainloop_quit,
}; };
struct pa_mainloop *pa_mainloop_new(void) { struct pa_mainloop *pa_mainloop_new(void) {
@ -282,7 +279,7 @@ static int io_foreach(void *p, uint32_t index, int *del, void*userdata) {
pa_xfree(e); pa_xfree(e);
*del = 1; *del = 1;
return 0; return 0;
}; }
static int time_foreach(void *p, uint32_t index, int *del, void*userdata) { static int time_foreach(void *p, uint32_t index, int *del, void*userdata) {
struct pa_time_event *e = p; struct pa_time_event *e = p;
@ -297,7 +294,7 @@ static int time_foreach(void *p, uint32_t index, int *del, void*userdata) {
pa_xfree(e); pa_xfree(e);
*del = 1; *del = 1;
return 0; return 0;
}; }
static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) { static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) {
struct pa_defer_event *e = p; struct pa_defer_event *e = p;
@ -312,7 +309,7 @@ static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) {
pa_xfree(e); pa_xfree(e);
*del = 1; *del = 1;
return 0; return 0;
}; }
void pa_mainloop_free(struct pa_mainloop* m) { void pa_mainloop_free(struct pa_mainloop* m) {
int all = 1; int all = 1;

View file

@ -189,9 +189,9 @@ int memblockq_pop(struct memblockq* bq, struct pa_memchunk *chunk) {
*/ */
static uint32_t age(struct timeval *tv) { static uint32_t age(struct timeval *tv) {
assert(tv);
struct timeval now; struct timeval now;
uint32_t r; uint32_t r;
assert(tv);
if (tv->tv_sec == 0) if (tv->tv_sec == 0)
return 0; return 0;

View file

@ -88,8 +88,8 @@ void pa_mcalign_push(struct pa_mcalign *m, const struct pa_memchunk *c) {
} }
int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) { int pa_mcalign_pop(struct pa_mcalign *m, struct pa_memchunk *c) {
assert(m && c && m->base > m->buffer_fill);
int ret; int ret;
assert(m && c && m->base > m->buffer_fill);
if (!m->chunk.memblock) if (!m->chunk.memblock)
return -1; return -1;

View file

@ -193,7 +193,7 @@ static void do_read(struct userdata *u) {
in_post_memblocks(u, info.blocks); in_post_memblocks(u, info.blocks);
in_clear_memblocks(u, u->in_fragments/2); 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) { 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; struct userdata *u = userdata;

View file

@ -146,7 +146,7 @@ static void do_read(struct userdata *u) {
pa_source_post(u->source, &memchunk); pa_source_post(u->source, &memchunk);
pa_memblock_unref(memchunk.memblock); pa_memblock_unref(memchunk.memblock);
}; }
static void io_callback(struct pa_iochannel *io, void*userdata) { static void io_callback(struct pa_iochannel *io, void*userdata) {
struct userdata *u = userdata; struct userdata *u = userdata;

View file

@ -134,8 +134,7 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t
name = c->default_source_name; name = c->default_source_name;
} else { } else if (type == PA_NAMEREG_SINK) {
assert(type == PA_NAMEREG_SINK);
if (!c->default_sink_name) { if (!c->default_sink_name) {
struct pa_sink *s; struct pa_sink *s;
@ -174,13 +173,15 @@ void* pa_namereg_get(struct pa_core *c, const char *name, enum pa_namereg_type t
d = pa_idxset_get_by_index(c->sinks, index); d = pa_idxset_get_by_index(c->sinks, index);
else if (type == PA_NAMEREG_SOURCE) else if (type == PA_NAMEREG_SOURCE)
d = pa_idxset_get_by_index(c->sources, index); 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; return d;
} }
void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type) { void pa_namereg_set_default(struct pa_core*c, const char *name, enum pa_namereg_type type) {
char **s; 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; s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name;
assert(s); assert(s);

View file

@ -26,7 +26,8 @@
enum pa_namereg_type { enum pa_namereg_type {
PA_NAMEREG_SINK, PA_NAMEREG_SINK,
PA_NAMEREG_SOURCE PA_NAMEREG_SOURCE,
PA_NAMEREG_SAMPLE
}; };
void pa_namereg_free(struct pa_core *c); void pa_namereg_free(struct pa_core *c);

View file

@ -47,14 +47,14 @@ enum pa_stream_state {
PA_STREAM_CREATING, /**< The stream is being created */ 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_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_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 */ /** The state of an operation */
enum pa_operation_state { enum pa_operation_state {
PA_OPERATION_RUNNING, /**< The operation is still running */ PA_OPERATION_RUNNING, /**< The operation is still running */
PA_OPERATION_DONE, /**< The operation has been completed */ 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 */ /** An invalid index */
@ -105,7 +105,7 @@ enum pa_subscription_mask {
PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */
PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */
PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client 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() */ /** Subscription event types, as used by pa_context_subscribe() */
@ -122,7 +122,7 @@ enum pa_subscription_event_type {
PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ 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_CHANGE = 16, /**< A property of the object was modified */
PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ 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 one if an event type t matches an event mask bitfield */

View file

@ -580,3 +580,92 @@ struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint
return pa_operation_ref(o); 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);
}

View file

@ -139,6 +139,18 @@ struct pa_stat_info {
/** Get daemon memory block statistics */ /** 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_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 PA_C_DECL_END
#endif #endif

View file

@ -23,6 +23,7 @@
***/ ***/
#include "cdecl.h" #include "cdecl.h"
#include "polyplib-def.h"
/** \file /** \file
* Asynchronous operations */ * Asynchronous operations */

View file

@ -32,8 +32,8 @@
#include "pstream-util.h" #include "pstream-util.h"
struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { 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; struct pa_stream *s;
assert(c && ss);
s = pa_xmalloc(sizeof(struct pa_stream)); s = pa_xmalloc(sizeof(struct pa_stream));
s->ref = 1; s->ref = 1;

View file

@ -427,7 +427,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v
k = sizeof(int)*5+ESD_NAME_MAX; k = sizeof(int)*5+ESD_NAME_MAX;
s = sizeof(int)*6+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))); response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1)));
assert(k); assert(k);
@ -482,7 +482,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v
struct pa_scache_entry *ce; struct pa_scache_entry *ce;
index = PA_IDXSET_INVALID; 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); assert(t >= s*2);
/* id */ /* id */

View file

@ -164,12 +164,14 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_GET_MODULE_INFO] = { command_get_info }, [PA_COMMAND_GET_MODULE_INFO] = { command_get_info },
[PA_COMMAND_GET_SINK_INPUT_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_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_SINK_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_SOURCE_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_MODULE_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_CLIENT_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_SINK_INPUT_INFO_LIST] = { command_get_info_list },
[PA_COMMAND_GET_SOURCE_OUTPUT_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_GET_SERVER_INFO] = { command_get_server_info },
[PA_COMMAND_SUBSCRIBE] = { command_subscribe }, [PA_COMMAND_SUBSCRIBE] = { command_subscribe },
[PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume }, [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume },
@ -763,8 +765,8 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm
static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
struct connection *c = userdata; struct connection *c = userdata;
assert(c && t);
struct pa_tagstruct *reply; struct pa_tagstruct *reply;
assert(c && t);
if (!pa_tagstruct_eof(t)) { if (!pa_tagstruct_eof(t)) {
protocol_error(c); protocol_error(c);
@ -789,10 +791,10 @@ static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag
static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { 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; struct connection *c = userdata;
assert(c && t);
struct pa_tagstruct *reply; struct pa_tagstruct *reply;
struct playback_stream *s; struct playback_stream *s;
uint32_t index, latency; uint32_t index, latency;
assert(c && t);
if (pa_tagstruct_getu32(t, &index) < 0 || if (pa_tagstruct_getu32(t, &index) < 0 ||
!pa_tagstruct_eof(t)) { !pa_tagstruct_eof(t)) {
@ -1021,6 +1023,15 @@ static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_sourc
pa_tagstruct_put_sample_spec(t, &s->sample_spec); 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) { 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; struct connection *c = userdata;
uint32_t index; uint32_t index;
@ -1030,6 +1041,7 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t
struct pa_module *module = NULL; struct pa_module *module = NULL;
struct pa_sink_input *si = NULL; struct pa_sink_input *si = NULL;
struct pa_source_output *so = NULL; struct pa_source_output *so = NULL;
struct pa_scache_entry *sce = NULL;
const char *name; const char *name;
struct pa_tagstruct *reply; struct pa_tagstruct *reply;
assert(c && t); assert(c && t);
@ -1067,12 +1079,17 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t
module = pa_idxset_get_by_index(c->protocol->core->modules, index); module = pa_idxset_get_by_index(c->protocol->core->modules, index);
else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index);
else { else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO);
so = pa_idxset_get_by_index(c->protocol->core->source_outputs, index); 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); pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY);
return; return;
} }
@ -1091,8 +1108,10 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t
module_fill_tagstruct(reply, module); module_fill_tagstruct(reply, module);
else if (si) else if (si)
sink_input_fill_tagstruct(reply, si); sink_input_fill_tagstruct(reply, si);
else else if (so)
source_output_fill_tagstruct(reply, so); source_output_fill_tagstruct(reply, so);
else
scache_fill_tagstruct(reply, sce);
pa_pstream_send_tagstruct(c->pstream, reply); pa_pstream_send_tagstruct(c->pstream, reply);
} }
@ -1129,11 +1148,13 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin
i = c->protocol->core->modules; i = c->protocol->core->modules;
else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
i = c->protocol->core->sink_inputs; i = c->protocol->core->sink_inputs;
else { else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST);
i = c->protocol->core->source_outputs; 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)) { for (p = pa_idxset_first(i, &index); p; p = pa_idxset_next(i, &index)) {
if (command == PA_COMMAND_GET_SINK_INFO_LIST) if (command == PA_COMMAND_GET_SINK_INFO_LIST)
sink_fill_tagstruct(reply, p); sink_fill_tagstruct(reply, p);
@ -1145,9 +1166,11 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin
module_fill_tagstruct(reply, p); module_fill_tagstruct(reply, p);
else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
sink_input_fill_tagstruct(reply, p); sink_input_fill_tagstruct(reply, p);
else { else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
assert(command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST);
source_output_fill_tagstruct(reply, p); source_output_fill_tagstruct(reply, p);
else {
assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
scache_fill_tagstruct(reply, p);
} }
} }

View file

@ -29,8 +29,8 @@
#include "sample.h" #include "sample.h"
size_t pa_frame_size(const struct pa_sample_spec *spec) { size_t pa_frame_size(const struct pa_sample_spec *spec) {
assert(spec);
size_t b = 1; size_t b = 1;
assert(spec);
switch (spec->format) { switch (spec->format) {
case PA_SAMPLE_U8: case PA_SAMPLE_U8:

View file

@ -35,9 +35,11 @@
#include "play-memchunk.h" #include "play-memchunk.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "subscribe.h" #include "subscribe.h"
#include "namereg.h"
static void free_entry(struct pa_scache_entry *e) { static void free_entry(struct pa_scache_entry *e) {
assert(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_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index);
pa_xfree(e->name); pa_xfree(e->name);
if (e->memchunk.memblock) if (e->memchunk.memblock)
@ -45,25 +47,32 @@ static void free_entry(struct pa_scache_entry *e) {
pa_xfree(e); 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; struct pa_scache_entry *e;
int put; int put;
assert(c && name); 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; put = 0;
if (e->memchunk.memblock) if (e->memchunk.memblock)
pa_memblock_unref(e->memchunk.memblock); pa_memblock_unref(e->memchunk.memblock);
assert(e->core == c); assert(e->core == c);
} else { } else {
put = 1; put = 1;
e = pa_xmalloc(sizeof(struct pa_scache_entry)); 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->name = pa_xstrdup(name);
e->core = c; e->core = c;
} }
e->volume = 0x100; e->volume = PA_VOLUME_NORM;
if (ss) if (ss)
e->sample_spec = *ss; e->sample_spec = *ss;
else else
@ -78,35 +87,31 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp
} }
if (put) { if (put) {
if (!c->scache_hashmap) { if (!c->scache) {
c->scache_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
assert(c->scache_hashmap); assert(c->scache);
} }
if (!c->scache_idxset) { pa_idxset_put(c->scache, e, &e->index);
c->scache_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
assert(c->scache_idxset);
}
pa_idxset_put(c->scache_idxset, e, &e->index);
pa_hashmap_put(c->scache_hashmap, e->name, e);
pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, 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) if (index)
*index = e->index; *index = e->index;
return 0;
} }
int pa_scache_remove_item(struct pa_core *c, const char *name) { int pa_scache_remove_item(struct pa_core *c, const char *name) {
struct pa_scache_entry *e; struct pa_scache_entry *e;
assert(c && name); 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; return -1;
pa_hashmap_remove(c->scache_hashmap, name); if (pa_idxset_remove_by_data(c->scache, e, NULL) != e)
if (pa_idxset_remove_by_data(c->scache_idxset, e, NULL) != e)
assert(0); assert(0);
free_entry(e); free_entry(e);
@ -122,14 +127,9 @@ static void free_cb(void *p, void *userdata) {
void pa_scache_free(struct pa_core *c) { void pa_scache_free(struct pa_core *c) {
assert(c); assert(c);
if (c->scache_hashmap) { if (c->scache) {
pa_hashmap_free(c->scache_hashmap, free_cb, NULL); pa_idxset_free(c->scache, free_cb, NULL);
c->scache_hashmap = NULL; c->scache = NULL;
}
if (c->scache_idxset) {
pa_idxset_free(c->scache_idxset, NULL, NULL);
c->scache_idxset = NULL;
} }
} }
@ -137,7 +137,7 @@ int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sin
struct pa_scache_entry *e; struct pa_scache_entry *e;
assert(c && name && sink); 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; return -1;
if (!e->memchunk.memblock) if (!e->memchunk.memblock)
@ -153,19 +153,9 @@ const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) {
struct pa_scache_entry *e; struct pa_scache_entry *e;
assert(c && id != PA_IDXSET_INVALID); 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 NULL;
return e->name; 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;
}

View file

@ -35,7 +35,7 @@ struct pa_scache_entry {
struct pa_memchunk memchunk; 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_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); int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume);

View file

@ -36,7 +36,7 @@
struct chunk { struct chunk {
struct chunk *next; struct chunk *next;
size_t length; size_t length;
char text[]; char text[0];
}; };
struct pa_strbuf { struct pa_strbuf {

View file

@ -29,7 +29,7 @@ void pa_strbuf_free(struct pa_strbuf *sb);
char *pa_strbuf_tostring(struct pa_strbuf *sb); char *pa_strbuf_tostring(struct pa_strbuf *sb);
char *pa_strbuf_tostring_free(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_puts(struct pa_strbuf *sb, const char *t);
void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t m); void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t m);