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 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

View file

@ -42,6 +42,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.</p>
<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>
@ -56,7 +60,7 @@ Daemon</a> (ESOUND). In addition to the features ESOUND provides
<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>
@ -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>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
@ -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>
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>
@ -131,7 +132,9 @@ GNU libtool for source code configuration and shared library
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>
@ -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>
<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>
</body>

View file

@ -212,13 +212,13 @@ char *pa_scache_list_to_string(struct pa_core *c) {
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);

View file

@ -53,8 +53,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->modules = NULL;
c->namereg = NULL;
c->scache_idxset = NULL;
c->scache_hashmap = NULL;
c->scache = NULL;
c->autoload_hashmap = NULL;
@ -74,7 +73,7 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
pa_check_for_sigpipe();
return c;
};
}
void pa_core_free(struct pa_core *c) {
assert(c);
@ -97,8 +96,8 @@ void pa_core_free(struct pa_core *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);
@ -108,5 +107,5 @@ void pa_core_free(struct pa_core *c) {
pa_memblock_stat_unref(c->memblock_stat);
pa_xfree(c);
};
}

View file

@ -31,9 +31,9 @@
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;

View file

@ -384,24 +384,24 @@ static void glib_quit(struct pa_mainloop_api*a, int retval) {
}
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) {

View file

@ -24,7 +24,7 @@
#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)

View file

@ -50,7 +50,7 @@ enum pa_io_event_flags {
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

View file

@ -38,9 +38,6 @@
#include "idxset.h"
#include "xmalloc.h"
struct pa_base_event {
};
struct pa_io_event {
struct pa_mainloop *mainloop;
int dead;
@ -225,24 +222,24 @@ static void mainloop_quit(struct pa_mainloop_api*a, int retval) {
}
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) {
@ -282,7 +279,7 @@ static int io_foreach(void *p, uint32_t index, int *del, void*userdata) {
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;
@ -297,7 +294,7 @@ static int time_foreach(void *p, uint32_t index, int *del, void*userdata) {
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;
@ -312,7 +309,7 @@ static int defer_foreach(void *p, uint32_t index, int *del, void*userdata) {
pa_xfree(e);
*del = 1;
return 0;
};
}
void pa_mainloop_free(struct pa_mainloop* m) {
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) {
assert(tv);
struct timeval now;
uint32_t r;
assert(tv);
if (tv->tv_sec == 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) {
assert(m && c && m->base > m->buffer_fill);
int ret;
assert(m && c && m->base > m->buffer_fill);
if (!m->chunk.memblock)
return -1;

View file

@ -193,7 +193,7 @@ static void do_read(struct userdata *u) {
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;

View file

@ -146,7 +146,7 @@ static void do_read(struct userdata *u) {
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;

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;
} else {
assert(type == PA_NAMEREG_SINK);
} else if (type == PA_NAMEREG_SINK) {
if (!c->default_sink_name) {
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);
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);

View file

@ -26,7 +26,8 @@
enum pa_namereg_type {
PA_NAMEREG_SINK,
PA_NAMEREG_SOURCE
PA_NAMEREG_SOURCE,
PA_NAMEREG_SAMPLE
};
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_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 */
@ -105,7 +105,7 @@ enum pa_subscription_mask {
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() */
@ -122,7 +122,7 @@ enum pa_subscription_event_type {
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 */

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);
}
/** 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 */
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

View file

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

View file

@ -32,8 +32,8 @@
#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;

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;
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);
@ -482,7 +482,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v
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 */

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_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 },
@ -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) {
struct connection *c = userdata;
assert(c && t);
struct pa_tagstruct *reply;
assert(c && t);
if (!pa_tagstruct_eof(t)) {
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) {
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)) {
@ -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);
}
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;
@ -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_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);
@ -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);
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;
}
@ -1091,8 +1108,10 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t
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);
}
@ -1129,11 +1148,13 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin
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);
@ -1145,9 +1166,11 @@ static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uin
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);
}
}

View file

@ -29,8 +29,8 @@
#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:

View file

@ -35,9 +35,11 @@
#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)
@ -45,25 +47,32 @@ static void free_entry(struct pa_scache_entry *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;
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
@ -78,35 +87,31 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp
}
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) {
c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
assert(c->scache);
}
if (!c->scache_idxset) {
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_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);
@ -122,14 +127,9 @@ static void free_cb(void *p, void *userdata) {
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;
}
}
@ -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;
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)
@ -153,19 +153,9 @@ const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) {
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;
}

View file

@ -35,7 +35,7 @@ struct pa_scache_entry {
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);

View file

@ -36,7 +36,7 @@
struct chunk {
struct chunk *next;
size_t length;
char text[];
char text[0];
};
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_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);