Revamp ggo help.
[paraslash.git] / audiod.c
index 03705089ff528f37aaf31a26ddf604ad884b1862..8552af6b07d2d4d977fe4f0587c552c42f1bf038 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2012 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -16,8 +16,8 @@
 #include "list.h"
 #include "sched.h"
 #include "ggo.h"
-#include "recv.h"
 #include "buffer_tree.h"
+#include "recv.h"
 #include "filter.h"
 #include "grab_client.h"
 #include "client.cmdline.h"
@@ -38,6 +38,8 @@ INIT_AUDIOD_ERRLISTS;
 /** define the array containing all supported audio formats */
 const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY NULL};
 
+DEFINE_RECEIVER_ARRAY;
+
 /** Defines how audiod handles one supported audio format. */
 struct audio_format_info {
        /** pointer to the receiver for this audio format */
@@ -341,10 +343,11 @@ static void parse_config_or_die(void)
                PARA_EMERG_LOG("can not read config file %s\n", config_file);
                goto err;
        }
-       if (ret)
+       if (ret) {
                audiod_cmdline_parser_config_file(config_file, &conf, &params);
+               daemon_set_loglevel(conf.loglevel_arg);
+       }
        free(config_file);
-       daemon_set_loglevel(conf.loglevel_arg);
        return;
 err:
        free(config_file);
@@ -494,7 +497,6 @@ static void open_filters(struct slot_info *s)
                fn->conf = a->filter_conf[i];
                fn->task.pre_select = f->pre_select;
                fn->task.post_select = f->post_select;
-
                fn->btrn = btr_new_node(&(struct btr_node_description)
                        EMBRACE(.name = f->name, .parent = parent,
                                .handler = f->execute, .context = fn));
@@ -990,7 +992,7 @@ static void signal_pre_select(struct sched *s, struct task *t)
        para_fd_set(st->fd, &s->rfds, &s->max_fileno);
 }
 
-static void signal_post_select(struct sched *s, __a_unused struct task *t)
+static int signal_post_select(struct sched *s, __a_unused struct task *t)
 {
        int signum;
 
@@ -1002,6 +1004,7 @@ static void signal_post_select(struct sched *s, __a_unused struct task *t)
                PARA_EMERG_LOG("terminating on signal %d\n", signum);
                clean_exit(EXIT_FAILURE, "caught deadly signal");
        }
+       return 0;
 }
 
 static void signal_setup_default(struct signal_task *st)
@@ -1017,7 +1020,7 @@ static void command_pre_select(struct sched *s, struct task *t)
        para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
 }
 
-static void command_post_select(struct sched *s, struct task *t)
+static int command_post_select(struct sched *s, struct task *t)
 {
        int ret;
        struct command_task *ct = container_of(t, struct command_task, task);
@@ -1034,6 +1037,7 @@ static void command_post_select(struct sched *s, struct task *t)
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        audiod_status_dump();
+       return 0;
 }
 
 static void init_command_task(struct command_task *ct)
@@ -1087,32 +1091,44 @@ static void set_stat_task_restart_barrier(unsigned seconds)
        tv_add(now, &delay, &stat_task->restart_barrier);
 }
 
-static void try_to_close_slot(int slot_num)
+static bool must_close_slot(int slot_num)
 {
        struct slot_info *s = &slot[slot_num];
        struct audio_format_info *a = afi + s->format;
        int i;
 
        if (s->format < 0)
-               return;
+               return false;
        if (s->receiver_node && s->receiver_node->task.error >= 0)
-               return;
+               return false;
        for (i = 0; i < a->num_filters; i++)
                if (s->fns && s->fns[i].task.error >= 0)
-                       return;
+                       return false;
        if (a->num_writers > 0) {
                for (i = 0; i < a->num_writers; i++)
                        if (s->wns && s->wns[i].task.error >= 0)
-                               return;
+                               return false;
        } else {
                if (s->wns && s->wns[0].task.error >= 0)
-                       return;
+                       return false;
+       }
+       return true;
+}
+
+static void close_unused_slots(void)
+{
+       int i;
+
+       FOR_EACH_SLOT(i) {
+               struct slot_info *s = slot + i;
+               if (!must_close_slot(i))
+                       continue;
+               PARA_INFO_LOG("closing slot %d\n", i);
+               close_writers(s);
+               close_filters(s);
+               close_receiver(i);
+               clear_slot(i);
        }
-       PARA_INFO_LOG("closing slot %d\n", slot_num);
-       close_writers(s);
-       close_filters(s);
-       close_receiver(slot_num);
-       clear_slot(slot_num);
 }
 
 /*
@@ -1121,12 +1137,11 @@ static void try_to_close_slot(int slot_num)
  */
 static void start_stop_decoders(void)
 {
-       int i, ret;
+       int ret;
        struct slot_info *sl;
        struct audio_format_info *a;
 
-       FOR_EACH_SLOT(i)
-               try_to_close_slot(i);
+       close_unused_slots();
        if (audiod_status != AUDIOD_ON ||
                        !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING))
                return notify_receivers(E_NOT_PLAYING);
@@ -1149,10 +1164,13 @@ static void start_stop_decoders(void)
 static void status_pre_select(struct sched *s, struct task *t)
 {
        struct status_task *st = container_of(t, struct status_task, task);
-       int ret, cafn = stat_task->current_audio_format_num;
+       int i, ret, cafn = stat_task->current_audio_format_num;
 
        if (must_start_decoder())
                goto min_delay;
+       FOR_EACH_SLOT(i)
+               if (must_close_slot(i))
+                       goto min_delay;
        ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
        if (ret > 0)
                goto min_delay;
@@ -1175,7 +1193,7 @@ min_delay:
 }
 
 /* restart the client task if necessary */
-static void status_post_select(struct sched *s, struct task *t)
+static int status_post_select(struct sched *s, struct task *t)
 {
        struct status_task *st = container_of(t, struct status_task, task);
 
@@ -1248,6 +1266,7 @@ static void status_post_select(struct sched *s, struct task *t)
        st->last_status_read = *now;
 out:
        start_stop_decoders();
+       return 0;
 }
 
 static void init_status_task(struct status_task *st)
@@ -1282,18 +1301,17 @@ static void set_initial_status(void)
 
 __noreturn static void print_help_and_die(void)
 {
-       int d = conf.detailed_help_given;
-       const char **p = d? audiod_args_info_detailed_help
-               : audiod_args_info_help;
-
-       printf_or_die("%s\n\n", AUDIOD_CMDLINE_PARSER_PACKAGE "-"
-               AUDIOD_CMDLINE_PARSER_VERSION);
-       printf_or_die("%s\n\n", audiod_args_info_usage);
-       for (; *p; p++)
-               printf_or_die("%s\n", *p);
-       print_receiver_helps(d);
-       print_filter_helps(d);
-       print_writer_helps(d);
+       struct ggo_help h = DEFINE_GGO_HELP(audiod);
+       bool d = conf.detailed_help_given;
+       unsigned flags;
+
+       flags = d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS;
+       ggo_print_help(&h, flags);
+
+       flags = d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS;
+       print_receiver_helps(flags);
+       print_filter_helps(flags);
+       print_writer_helps(flags);
        exit(0);
 }
 
@@ -1332,9 +1350,9 @@ int main(int argc, char *argv[])
        };
 
        valid_fd_012();
-       if (audiod_cmdline_parser_ext(argc, argv, &conf, &params))
-               exit(EXIT_FAILURE);
-       HANDLE_VERSION_FLAG("audiod", conf);
+       audiod_cmdline_parser_ext(argc, argv, &conf, &params);
+       daemon_set_loglevel(conf.loglevel_arg);
+       version_handle_flag("audiod", conf.version_given);
        /* init receivers/filters/writers early to make help work */
        recv_init();
        filter_init();