add support for automatic termination of the daemon after the last client quit

remove all gcc warnings
add boolean types for tagstruct and modargs


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@178 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-09-04 00:27:36 +00:00
parent fb962b67db
commit 57e473b61c
23 changed files with 155 additions and 37 deletions

View file

@ -9,17 +9,13 @@
kill client/...
autoload management
- more complete pactl
- cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t)
- remove all gcc warnings
- make fragments settings runtime configurable
- logging
- automatic termination of daemon if unused
- add sample directory
- paman: show scache and sample size
- add timing parameter to write callback of stream in client API
** later ***
- xmlrpc/http
- dbus
- slp/rendezvous
- modinfo
- make alsa modules use mmap

View file

@ -51,6 +51,8 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name,
fprintf(stderr, "client: created %u \"%s\"\n", c->index, c->name);
pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index);
pa_core_check_quit(core);
return c;
}
@ -59,10 +61,14 @@ void pa_client_free(struct pa_client *c) {
assert(c && c->core);
pa_idxset_remove_by_data(c->core->clients, c, NULL);
pa_core_check_quit(c->core);
fprintf(stderr, "client: freed %u \"%s\"\n", c->index, c->name);
pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
pa_xfree(c->name);
pa_xfree(c);
}
void pa_client_kill(struct pa_client *c) {

View file

@ -75,6 +75,7 @@ void pa_cmdline_help(const char *argv0) {
" -d Disallow module loading after startup\n"
" -f Dont quit when the startup fails\n"
" -v Verbose startup\n"
" -X SECS Terminate the daemon after the last client quit and this time passed\n"
" -h Show this help\n"
" -V Show version\n", e, cfg);
@ -97,11 +98,12 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) {
cmdline->version =
cmdline->disallow_module_loading = 0;
cmdline->fail = 1;
cmdline->quit_after_last_client_time = -1;
buf = pa_strbuf_new();
assert(buf);
while ((c = getopt(argc, argv, "L:F:CDhfvrRVnd")) != -1) {
while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:")) != -1) {
switch (c) {
case 'L':
pa_strbuf_printf(buf, "load %s\n", optarg);
@ -139,6 +141,9 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) {
case 'd':
cmdline->disallow_module_loading = 1;
break;
case 'X':
cmdline->quit_after_last_client_time = atoi(optarg);
break;
default:
goto fail;
}

View file

@ -24,7 +24,7 @@
struct pa_cmdline {
int daemonize, help, fail, verbose, high_priority, stay_root, version, disallow_module_loading;
int daemonize, help, fail, verbose, high_priority, stay_root, version, disallow_module_loading, quit_after_last_client_time;
char *cli_commands;
};

View file

@ -71,6 +71,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->memblock_stat = pa_memblock_stat_new();
c->disallow_module_loading = 0;
c->quit_event = NULL;
c->quit_after_last_client_time = -1;
pa_check_for_sigpipe();
@ -102,6 +105,11 @@ void pa_core_free(struct pa_core *c) {
pa_namereg_free(c);
pa_autoload_free(c);
pa_subscription_free_all(c);
if (c->quit_event) {
c->mainloop->time_free(c->quit_event);
c->quit_event = NULL;
}
pa_xfree(c->default_source_name);
pa_xfree(c->default_sink_name);
@ -111,3 +119,23 @@ void pa_core_free(struct pa_core *c) {
pa_xfree(c);
}
static void quit_callback(struct pa_mainloop_api*m, struct pa_time_event *e, const struct timeval *tv, void *userdata) {
struct pa_core *c = userdata;
assert(c->quit_event = e);
m->quit(m, 0);
}
void pa_core_check_quit(struct pa_core *c) {
assert(c);
if (!c->quit_event && c->quit_after_last_client_time >= 0 && pa_idxset_ncontents(c->clients) == 0) {
struct timeval tv;
gettimeofday(&tv, NULL);
tv.tv_sec+= c->quit_after_last_client_time;
c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c);
} else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) {
c->mainloop->time_free(c->quit_event);
c->quit_event = NULL;
}
}

View file

@ -48,9 +48,15 @@ struct pa_core {
struct pa_memblock_stat *memblock_stat;
int disallow_module_loading;
int quit_after_last_client_time;
struct pa_time_event *quit_event;
};
struct pa_core* pa_core_new(struct pa_mainloop_api *m);
void pa_core_free(struct pa_core*c);
void pa_core_check_quit(struct pa_core *c);
#endif

View file

@ -213,6 +213,7 @@ int main(int argc, char *argv[]) {
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
c->disallow_module_loading = cmdline->disallow_module_loading;
c->quit_after_last_client_time = cmdline->quit_after_last_client_time;
fprintf(stderr, __FILE__": mainloop entry.\n");
if (pa_mainloop_run(mainloop, &retval) < 0)

View file

@ -207,6 +207,46 @@ int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *v
return 0;
}
int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value) {
const char *v;
char *e;
signed long l;
assert(ma && key && value);
if (!(v = pa_modargs_get_value(ma, key, NULL)))
return 0;
if (!*v)
return -1;
l = strtol(v, &e, 0);
if (*e)
return -1;
*value = (int32_t) l;
return 0;
}
int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value) {
const char *v;
assert(ma && key && value);
if (!(v = pa_modargs_get_value(ma, key, NULL)))
return 0;
if (!*v)
return -1;
if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on"))
*value = 1;
else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off"))
*value = 0;
else
return -1;
return 0;
}
int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss) {
const char *format;
uint32_t channels;

View file

@ -33,6 +33,8 @@ void pa_modargs_free(struct pa_modargs*ma);
const char *pa_modargs_get_value(struct pa_modargs *ma, const char *key, const char *def);
int pa_modargs_get_value_u32(struct pa_modargs *ma, const char *key, uint32_t *value);
int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *value);
int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value);
int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *ss);

View file

@ -50,7 +50,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) {
goto finish;
}
if (pa_modargs_get_value_u32(ma, "fd", &fd) < 0) {
if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) {
fprintf(stderr, __FILE__": invalid file descriptor.\n");
goto finish;
}

View file

@ -234,20 +234,21 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) {
goto fail;
}
if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) {
if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
fprintf(stderr, __FILE__": record= and playback= expect numeric arguments.\n");
goto fail;
}
mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
if (mode == 0) {
if (!playback && !record) {
fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n");
goto fail;
}
mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
nfrags = 12;
frag_size = 1024;
if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) {
if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) {
fprintf(stderr, __FILE__": failed to parse fragments arguments\n");
goto fail;
}

View file

@ -177,7 +177,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) {
int fd = -1;
int nfrags, frag_size, in_frag_size, out_frag_size;
int mode;
uint32_t record = 1, playback = 1;
int record = 1, playback = 1;
struct pa_sample_spec ss;
struct pa_modargs *ma = NULL;
assert(c && m);
@ -187,20 +187,21 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) {
goto fail;
}
if (pa_modargs_get_value_u32(ma, "record", &record) < 0 || pa_modargs_get_value_u32(ma, "playback", &playback) < 0) {
if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
fprintf(stderr, __FILE__": record= and playback= expect numeric argument.\n");
goto fail;
}
mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
if (mode == 0) {
if (!playback && !record) {
fprintf(stderr, __FILE__": neither playback nor record enabled for device.\n");
goto fail;
}
mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
nfrags = 12;
frag_size = 1024;
if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) {
if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || nfrags < 2 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0 || frag_size < 1) {
fprintf(stderr, __FILE__": failed to parse fragments arguments\n");
goto fail;
}

View file

@ -83,15 +83,16 @@ static const char* const valid_modargs[] = {
static struct pa_socket_server *create_socket_server(struct pa_core *c, struct pa_modargs *ma) {
struct pa_socket_server *s;
#ifdef USE_TCP_SOCKETS
uint32_t loopback = 1, port = IPV4_PORT;
int loopback = 1;
uint32_t port = IPV4_PORT;
if (pa_modargs_get_value_u32(ma, "loopback", &loopback) < 0) {
if (pa_modargs_get_value_boolean(ma, "loopback", &loopback) < 0) {
fprintf(stderr, "loopback= expects a numerical argument.\n");
return NULL;
}
if (pa_modargs_get_value_u32(ma, "port", &port) < 0) {
fprintf(stderr, "port= expects a numerical argument.\n");
if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) {
fprintf(stderr, "port= expects a numerical argument between 1 and 65535.\n");
return NULL;
}

View file

@ -117,6 +117,10 @@ fail:
static void pa_module_free(struct pa_module *m) {
assert(m && m->done && m->core);
if (m->core->disallow_module_loading)
return;
m->done(m->core, m);
lt_dlclose(m->dl);
@ -130,7 +134,6 @@ static void pa_module_free(struct pa_module *m) {
pa_xfree(m);
}
void pa_module_unload(struct pa_core *c, struct pa_module *m) {
assert(c && m);

View file

@ -140,7 +140,7 @@ struct pa_latency_info {
pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play */
pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */
int playing; /**< Non-zero when the stream is currently playing */
int queue_length; /**< Queue size in bytes. */
uint32_t queue_length; /**< Queue size in bytes. */
};
PA_C_DECL_END

View file

@ -331,7 +331,7 @@ static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t c
pa_tagstruct_gets(t, &i.name) < 0 ||
pa_tagstruct_gets(t, &i.argument) < 0 ||
pa_tagstruct_getu32(t, &i.n_used) < 0 ||
pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) {
pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish;
}

View file

@ -106,8 +106,8 @@ struct pa_module_info {
uint32_t index; /**< Index of the module */
const char*name, /**< Name of the module */
*argument; /**< Argument string of the module */
uint32_t n_used, /**< Usage counter or PA_INVALID_INDEX */
auto_unload; /**< Non-zero if this is an autoloaded module */
uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */
int auto_unload; /**< Non-zero if this is an autoloaded module */
};
/** Get some information about a module by its index */

View file

@ -329,7 +329,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman
} else if (pa_tagstruct_getu32(t, &i.buffer_usec) < 0 ||
pa_tagstruct_getu32(t, &i.sink_usec) < 0 ||
pa_tagstruct_getu32(t, &i.playing) < 0 ||
pa_tagstruct_get_boolean(t, &i.playing) < 0 ||
pa_tagstruct_getu32(t, &i.queue_length) < 0 ||
!pa_tagstruct_eof(t)) {
pa_context_fail(o->context, PA_ERROR_PROTOCOL);

View file

@ -830,7 +830,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma
pa_tagstruct_putu32(reply, tag);
pa_tagstruct_putu32(reply, pa_sink_input_get_latency(s->sink_input));
pa_tagstruct_putu32(reply, pa_sink_get_latency(s->sink_input->sink));
pa_tagstruct_putu32(reply, pa_memblockq_is_readable(s->memblockq));
pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq));
pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq));
pa_pstream_send_tagstruct(c->pstream, reply);
}
@ -1012,7 +1012,7 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu
pa_tagstruct_puts(t, module->name);
pa_tagstruct_puts(t, module->argument ? module->argument : "");
pa_tagstruct_putu32(t, module->n_used);
pa_tagstruct_putu32(t, module->auto_unload);
pa_tagstruct_put_boolean(t, module->auto_unload);
}
static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_input *s) {
@ -1505,10 +1505,10 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo
static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struct pa_module *m, struct pa_modargs *ma) {
struct pa_protocol_native *p;
uint32_t public;
int public;
assert(c && ma);
if (pa_modargs_get_value_u32(ma, "public", &public) < 0) {
if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) {
fprintf(stderr, __FILE__": public= expects numeric argument.\n");
return NULL;
}

View file

@ -366,7 +366,7 @@ fail:
struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) {
struct pa_protocol_simple* p = NULL;
uint32_t enable;
int enable;
assert(core && server && ma);
p = pa_xmalloc0(sizeof(struct pa_protocol_simple));
@ -385,14 +385,14 @@ struct pa_protocol_simple* pa_protocol_simple_new(struct pa_core *core, struct p
p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
enable = 0;
if (pa_modargs_get_value_u32(ma, "record", &enable) < 0) {
if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) {
fprintf(stderr, __FILE__": record= expects a numeric argument.\n");
goto fail;
}
p->mode = enable ? RECORD : 0;
enable = 1;
if (pa_modargs_get_value_u32(ma, "playback", &enable) < 0) {
if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) {
fprintf(stderr, __FILE__": playback= expects a numeric argument.\n");
goto fail;
}

View file

@ -172,7 +172,7 @@ uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) {
uint32_t pa_scache_total_size(struct pa_core *c) {
struct pa_scache_entry *e;
uint32_t index;
uint32_t sum;
uint32_t sum = 0;
if (!c->scache)
return 0;

View file

@ -40,7 +40,9 @@ enum tags {
TAG_U8 = 'B',
TAG_S8 = 'b',
TAG_SAMPLE_SPEC = 'a',
TAG_ARBITRARY = 'x'
TAG_ARBITRARY = 'x',
TAG_BOOLEAN_TRUE = '1',
TAG_BOOLEAN_FALSE = '0',
};
struct pa_tagstruct {
@ -125,7 +127,6 @@ void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample
t->length += 7;
}
void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) {
assert(t && p);
@ -137,6 +138,13 @@ void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t le
t->length += 5+length;
}
void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) {
assert(t);
extend(t, 1);
t->data[t->length] = b ? TAG_BOOLEAN_TRUE : TAG_BOOLEAN_FALSE;
t->length += 1;
}
int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) {
int error = 0;
size_t n;
@ -238,3 +246,21 @@ const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l) {
return t->data;
}
int pa_tagstruct_get_boolean(struct pa_tagstruct*t, int *b) {
assert(t && b);
if (t->rindex+1 > t->length)
return -1;
if (t->data[t->rindex] == TAG_BOOLEAN_TRUE)
*b = 1;
else if (t->data[t->rindex] == TAG_BOOLEAN_FALSE)
*b = 0;
else
return -1;
t->rindex +=1;
return 0;
}

View file

@ -38,12 +38,14 @@ void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i);
void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c);
void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss);
void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length);
void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b);
int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s);
int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i);
int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c);
int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss);
int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length);
int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b);
int pa_tagstruct_eof(struct pa_tagstruct*t);
const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l);