]> code.delx.au - pulseaudio/commitdiff
add support for automatic termination of the daemon after the last client quit
authorLennart Poettering <lennart@poettering.net>
Sat, 4 Sep 2004 00:27:36 +0000 (00:27 +0000)
committerLennart Poettering <lennart@poettering.net>
Sat, 4 Sep 2004 00:27:36 +0000 (00:27 +0000)
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

23 files changed:
doc/todo
polyp/client.c
polyp/cmdline.c
polyp/cmdline.h
polyp/core.c
polyp/core.h
polyp/main.c
polyp/modargs.c
polyp/modargs.h
polyp/module-native-protocol-fd.c
polyp/module-oss-mmap.c
polyp/module-oss.c
polyp/module-protocol-stub.c
polyp/module.c
polyp/polyplib-def.h
polyp/polyplib-introspect.c
polyp/polyplib-introspect.h
polyp/polyplib-stream.c
polyp/protocol-native.c
polyp/protocol-simple.c
polyp/scache.c
polyp/tagstruct.c
polyp/tagstruct.h

index bfc29fab083c6b33dbd45f6bd2e5f5f9082e01a0..5a1a247c88ebe941272fa49b61286cee5f53b608 100644 (file)
--- a/doc/todo
+++ b/doc/todo
@@ -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
index 0cb42466a30cf1c1abdd1f8e93e69bc6e21b42c1..c7fb1e07d09164aa657dd492487f19369b6289e6 100644 (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) {
index 265e0ec88e90b486aae81abe2643af0d1db9a181..aba20af1382b0984630225768aa8e3a40987ad7f 100644 (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;
         }
index 7330a7162000e052eae21f449baa213033246571..d1c438d1ca228d71616b5ee181bce555e7ca3b4c 100644 (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;
 };
 
index da6ace6a3e844da61fa1bd73d793cd87ce5b2ea4..4362f0cb52216a27b9fb8d6681d1ce71aee12f4d 100644 (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;
+    }
+}
index ffcd018bc2219ccdae1b26a49100f870aed7a7d2..513d8172972933275a90cbacf812c7bddbd7c0f4 100644 (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
index 1c09276e20af4d4e91887fbf48b67203fdfc0605..0f88a76e920571f1460b7942cc16cd380c0c7485 100644 (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)
index 87d99ad2838639b65fa85dc269e472a54ec51dd9..4874d808e95a289a986c24b7ba764d6f76e8aec3 100644 (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;
index 872fb14f140d875a1632059821c4febb93a3a559..705d9f43651581d59f7df284cf5f41c440a12adf 100644 (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);
 
index 58d09ffec6bd7249859e660bee0bfa1a9106f64e..213e291ed459a0cc50898dadcdd012646cd2fba1 100644 (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;
     }
index 5c3be1ad4839e1694c24e1425ea61d6acc90466b..8a0dd9a4bd0c8d87275ddcdc5b87a1abec4b1417 100644 (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;
     }
index 403716fd8aa5429cc84cc4fd38bae03f959b3045..4fd796245d659e446c5c86a88d10d255dc2b947c 100644 (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;
     }
index e681732fbe4f793c94dfa82586e4ba3485b74583..4d86c28ec2c6fb0dcc00cce92295718e2d86a833 100644 (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;
     }
     
index fc71495377b69d1146f3f28f856ca63bae34b498..a06b27541cb0a217972c1329d231a62e91d0619c 100644 (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);
 
index 6c3cd825ce730bdf39803f81195a5a06e556a1d5..f0ecc5c464b0442c468377136a7b650252de8fc9 100644 (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
index a4ecf5ee63fae28bd3722141070c5eee94262d40..b31a40c7a40f80efc6b8ce98eb80c669e242c5b8 100644 (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;
             }
index 1cc79d0fdce18c1bedcc4beb09ff413c0b84bca1..0a14fad091e4843dccec5b2776efb676448b31fe 100644 (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 */
index 220e4a14404ec86cf76c75e05737a8137e943cad..7170a32eb21f33d902130adc5906c90276cf774d 100644 (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);
index cce6cc6ca31dccdf6b48acc98bcadf27895564f7..2572810fb1bf31931d58b5d0a4ac06b72e9f48c6 100644 (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;
     }
index 41c1f484659b088b8512098731b26f66f06e492a..3ccb3068cdb174126badbc1a0cf6b4f07205021a 100644 (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;
     }
index b7a8ff026185df8180e368330e68bc32dfdb91f1..53e8a3fe286094aefe4505d2d3e66ab0a60f1d0b 100644 (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;
index 742f6b9cbc9bfa2c6b54641674d90869c65e14a1..5aa79e6c203262c8bcabfb1247fb8a0de130538e 100644 (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;
+}
+
+
index bcd7f456ae8f3cd7780ed7caa4f7861f2ce81367..9a91ee962f253922241652414e926a18880f88ea 100644 (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);