X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=a5a774376b37c50eba92a76a02b1389bd6df67f4;hp=254bcb8d8c4bac2947e52c3310fb7051fe5f1153;hb=HEAD;hpb=4d067435b1167dbf5217c875ac9fd7ac69ad91bd diff --git a/audiod.c b/audiod.c index 254bcb8d..7c223995 100644 --- a/audiod.c +++ b/audiod.c @@ -1,8 +1,4 @@ -/* - * Copyright (C) 2005 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ +/* Copyright (C) 2005 Andre Noll , see file COPYING. */ /** \file audiod.c The paraslash's audio daemon. */ @@ -15,19 +11,20 @@ #include #include #include +#include +#include "audiod.lsg.h" +#include "recv_cmd.lsg.h" #include "para.h" #include "error.h" +#include "lsu.h" #include "crypt.h" -#include "audiod.cmdline.h" #include "list.h" #include "sched.h" -#include "ggo.h" #include "buffer_tree.h" #include "recv.h" #include "filter.h" #include "grab_client.h" -#include "client.cmdline.h" #include "client.h" #include "audiod.h" #include "net.h" @@ -35,37 +32,43 @@ #include "string.h" #include "fd.h" #include "write.h" -#include "write_common.h" #include "signal.h" #include "version.h" /** Array of error strings. */ DEFINE_PARA_ERRLIST; +static struct lls_parse_result *lpr; +#define CMD_PTR (lls_cmd(0, audiod_suite)) +#define OPT_RESULT(_name) (lls_opt_result(LSG_AUDIOD_PARA_AUDIOD_OPT_ ## _name, lpr)) +#define OPT_GIVEN(_name) (lls_opt_given(OPT_RESULT(_name))) +#define OPT_STRING_VAL(_name) (lls_string_val(0, OPT_RESULT(_name))) +#define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name))) + __printf_2_3 void (*para_log)(int, const char*, ...) = daemon_log; /** 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 */ - struct receiver *receiver; - /** the receiver configuration */ - void *receiver_conf; + /** the receiver for this audio format */ + int receiver_num; + /** Parsed receiver command line. */ + struct lls_parse_result *receiver_lpr; /** the number of filters that should be activated for this audio format */ unsigned int num_filters; /** Array of filter numbers to be activated. */ unsigned *filter_nums; /** Pointer to the array of filter configurations. */ void **filter_conf; + /** Parsed filter command line, one parse result per filter. */ + struct lls_parse_result **filter_lpr; /** the number of filters that should be activated for this audio format */ unsigned int num_writers; - /** Array of writer numbers to be activated. */ - int *writer_nums; - /** pointer to the array of writer configurations */ - void **writer_conf; + /** Array of writer IDs to be activated. */ + int *wids; + /** Parsed writer command line(s) */ + struct lls_parse_result **writer_lpr; /** do not start receiver/filters/writer before this time */ struct timeval restart_barrier; }; @@ -88,6 +91,9 @@ struct slot_info { struct writer_node *wns; }; +#define RECEIVER_CMD(_a) lls_cmd((_a)->receiver_num, recv_cmd_suite) +#define RECEIVER(_a) ((const struct receiver *)lls_user_data(RECEIVER_CMD(_a))) + /** Maximal number of simultaneous instances. */ #define MAX_STREAM_SLOTS 5 @@ -98,9 +104,7 @@ struct slot_info { * para_audiod uses \p MAX_STREAM_SLOTS different slots, each of which may * be associated with a receiver/filter/writer triple. This array holds all * information on the status of these slots. - * - * \sa struct slot_info - * */ + */ struct slot_info slot[MAX_STREAM_SLOTS]; /** The vss status flags audiod is interested in. */ @@ -117,7 +121,7 @@ enum vss_status_flags { * This is needed also in audiod_command.c (for the tasks command), so it can * not be made static. */ -struct sched sched = {.max_fileno = 0}; +struct sched sched = {.timeout = 0}; /* The task for obtaining para_server's status (para_client stat). */ struct status_task { @@ -156,41 +160,32 @@ struct status_task { char *stat_item_values[NUM_STAT_ITEMS] = {NULL}; /** - * the current mode of operation of which can be changed by the on/off/cycle - * commands. It is either, AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY. + * The current mode of operation (AUDIOD_OFF, AUDIOD_ON or AUDIOD_STANDBY). + * Set by the on/off/cycle commands. */ int audiod_status = AUDIOD_ON; -/** - * the gengetopt args_info struct that holds information on all command line - * arguments - */ -static struct audiod_args_info conf; - static char *socket_name; static struct audio_format_info afi[NUM_AUDIO_FORMATS]; - static struct signal_task *signal_task; - static struct status_task status_task_struct; - static uid_t *uid_whitelist; /** - * the task that calls the status command of para_server + * The task that calls the status command of para_server. * - * \sa struct status_task + * \sa \ref struct status_task. */ static struct status_task *stat_task = &status_task_struct; struct command_task { /** The local listening socket. */ int fd; - /** the associated task structure */ + /** The associated task structure. */ struct task *task; }; -/** iterate over all supported audio formats */ +/** Iterate over all supported audio formats. */ #define FOR_EACH_AUDIO_FORMAT(af) for (af = 0; af < NUM_AUDIO_FORMATS; af++) /** @@ -295,7 +290,7 @@ static int get_play_time_slot_num(void) * * \return A string that must be freed by the caller. */ -char *get_time_string(void) +__malloc char *get_time_string(void) { int ret, seconds = 0, length = stat_task->length_seconds; struct timeval *tmp, sum, sss, /* server stream start */ @@ -305,6 +300,7 @@ char *get_time_string(void) rskip; /* receiver start - sss */ int slot_num = get_play_time_slot_num(); struct slot_info *s = slot_num < 0? NULL : &slot[slot_num]; + bool writer_active = s && s->wns && s->wns[0].btrn; char *msg; if (audiod_status == AUDIOD_OFF) @@ -318,11 +314,11 @@ char *get_time_string(void) } /* * Valid status items and playing, set length and tmp to the stream - * start. We use the slot info and fall back to the info from current - * status items if no slot info is available. + * start. We use the writer start time from the slot info and fall back + * to the info from current status items if no writer is active yet. */ tmp = &stat_task->server_stream_start; - if (s && s->wns && s->wns[0].btrn) { /* writer active in this slot */ + if (writer_active) { btr_get_node_start(s->wns[0].btrn, &wstime); if (wstime.tv_sec != 0) { /* writer wrote something */ if (s->server_stream_start.tv_sec == 0) { @@ -339,7 +335,7 @@ char *get_time_string(void) tv_diff(tmp, &stat_task->sa_time_diff, &sss); else tv_add(tmp, &stat_task->sa_time_diff, &sss); - if (!s || !s->wns || !s->wns[0].btrn || wstime.tv_sec == 0) { + if (!writer_active) { struct timeval diff; tv_diff(now, &sss, &diff); seconds = diff.tv_sec + stat_task->offset_seconds; @@ -381,58 +377,37 @@ empty: static void parse_config_or_die(void) { - int ret, i; - char *config_file; - struct audiod_cmdline_parser_params params = { - .override = 0, - .initialize = 0, - .check_required = 1, - .check_ambiguity = 0, - .print_errors = 1 - }; - - if (conf.config_file_given) - config_file = para_strdup(conf.config_file_arg); - else { - char *home = para_homedir(); - config_file = make_message("%s/.paraslash/audiod.conf", home); - free(home); - } - ret = file_exists(config_file); - if (conf.config_file_given && !ret) { - PARA_EMERG_LOG("can not read config file %s\n", config_file); - free(config_file); - goto err; - } - if (ret) { - audiod_cmdline_parser_config_file(config_file, &conf, ¶ms); - daemon_set_loglevel(conf.loglevel_arg); + int i, ret; + uint32_t n; + + ret = lsu_merge_config_file_options(OPT_STRING_VAL(CONFIG_FILE), + "audiod.conf", &lpr, CMD_PTR, audiod_suite, 0U /* flags */); + if (ret < 0) { + PARA_EMERG_LOG("failed to parse config file: %s\n", + para_strerror(-ret)); + exit(EXIT_FAILURE); } - free(config_file); - if (conf.user_allow_given > 0) { - uid_whitelist = para_malloc(conf.user_allow_given - * sizeof(uid_t)); - for (i = 0; i < conf.user_allow_given; i++) { - int32_t val; - struct passwd *pw; - ret = para_atoi32(conf.user_allow_arg[i], &val); - if (ret >= 0) { - uid_whitelist[i] = val; - continue; - } - errno = 0; /* see getpwnam(3) */ - pw = getpwnam(conf.user_allow_arg[i]); - if (!pw) { - PARA_EMERG_LOG("invalid username: %s\n", - conf.user_allow_arg[i]); - goto err; - } - uid_whitelist[i] = pw->pw_uid; + daemon_set_loglevel(OPT_UINT32_VAL(LOGLEVEL)); + n = OPT_GIVEN(USER_ALLOW); + if (n == 0) + return; + uid_whitelist = arr_alloc(n, sizeof(uid_t)); + for (i = 0; i < n; i++) { + const char *arg = lls_string_val(i, OPT_RESULT(USER_ALLOW)); + int32_t val; + struct passwd *pw; + ret = para_atoi32(arg, &val); + if (ret >= 0) { + uid_whitelist[i] = val; + continue; + } + pw = getpwnam(arg); + if (!pw) { + PARA_EMERG_LOG("invalid username: %s\n", arg); + exit(EXIT_FAILURE); } + uid_whitelist[i] = pw->pw_uid; } - return; -err: - exit(EXIT_FAILURE); } static void setup_signal_handling(void) @@ -463,25 +438,23 @@ static void close_receiver(int slot_num) a = &afi[s->format]; PARA_NOTICE_LOG("closing %s receiver in slot %d\n", audio_formats[s->format], slot_num); - a->receiver->close(s->receiver_node); + RECEIVER(a)->close(s->receiver_node); btr_remove_node(&s->receiver_node->btrn); task_reap(&s->receiver_node->task); free(s->receiver_node); s->receiver_node = NULL; - stat_task->current_audio_format_num = -1; + if (audiod_status == AUDIOD_ON) + stat_task->current_audio_format_num = -1; tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), &a->restart_barrier); } static void writer_cleanup(struct writer_node *wn) { - struct writer *w; - if (!wn) return; - w = writers + wn->writer_num; - PARA_INFO_LOG("closing %s\n", writer_names[wn->writer_num]); - w->close(wn); + PARA_INFO_LOG("closing %s\n", writer_name(wn->wid)); + writer_get(wn->wid)->close(wn); btr_remove_node(&wn->btrn); task_reap(&wn->task); } @@ -505,6 +478,23 @@ static void close_writers(struct slot_info *s) s->wns = NULL; } +static void notify_writers(int error) +{ + int i; + + FOR_EACH_SLOT(i) { + struct slot_info *s = slot + i; + struct audio_format_info *a; + int j; + + if (s->format < 0) + continue; + a = afi + s->format; + for (j = 0; j < a->num_writers; j++) + task_notify(s->wns[j].task, error); + } +} + static void close_filters(struct slot_info *s) { int i; @@ -572,30 +562,33 @@ static void open_filters(struct slot_info *s) return; PARA_INFO_LOG("opening %s filters\n", audio_formats[s->format]); assert(s->fns == NULL); - s->fns = para_calloc(nf * sizeof(struct filter_node)); + s->fns = zalloc(nf * sizeof(struct filter_node)); parent = s->receiver_node->btrn; for (i = 0; i < nf; i++) { char buf[20]; + const char *name; const struct filter *f = filter_get(a->filter_nums[i]); fn = s->fns + i; fn->filter_num = a->filter_nums[i]; fn->conf = a->filter_conf[i]; + fn->lpr = a->filter_lpr[i]; + name = filter_name(fn->filter_num); fn->btrn = btr_new_node(&(struct btr_node_description) - EMBRACE(.name = f->name, .parent = parent, + EMBRACE(.name = name, .parent = parent, .handler = f->execute, .context = fn)); if (f->open) f->open(fn); - sprintf(buf, "%s (slot %d)", f->name, (int)(s - slot)); + sprintf(buf, "%s (slot %d)", name, (int)(s - slot)); fn->task = task_register(&(struct task_info) { .name = buf, - .pre_select = f->pre_select, - .post_select = f->post_select, + .pre_monitor = f->pre_monitor, + .post_monitor = f->post_monitor, .context = fn, }, &sched); parent = fn->btrn; PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n", - audio_formats[s->format], i, nf, f->name, (int)(s - slot)); + audio_formats[s->format], i, nf, name, (int)(s - slot)); } } @@ -607,15 +600,15 @@ static void open_writers(struct slot_info *s) struct btr_node *parent = s->fns[a->num_filters - 1].btrn; assert(s->wns == NULL); - s->wns = para_calloc(PARA_MAX(1U, a->num_writers) + s->wns = zalloc(PARA_MAX(1U, a->num_writers) * sizeof(struct writer_node)); for (i = 0; i < a->num_writers; i++) { wn = s->wns + i; - wn->conf = a->writer_conf[i]; - wn->writer_num = a->writer_nums[i]; + wn->wid = a->wids[i]; + wn->lpr = a->writer_lpr[i]; register_writer_node(wn, parent, &sched); PARA_NOTICE_LOG("%s writer started in slot %d\n", - writer_names[a->writer_nums[i]], (int)(s - slot)); + writer_name(a->wids[i]), (int)(s - slot)); } } @@ -625,7 +618,8 @@ static int open_receiver(int format) struct audio_format_info *a = &afi[format]; struct slot_info *s; int ret, slot_num; - struct receiver *r = a->receiver; + const struct receiver *r = RECEIVER(a); + const char *name = lls_command_name(RECEIVER_CMD(a)); struct receiver_node *rn; tv_add(now, &(struct timeval)EMBRACE(2, 0), &a->restart_barrier); @@ -633,13 +627,14 @@ static int open_receiver(int format) if (ret < 0) return ret; slot_num = ret; - rn = para_calloc(sizeof(*rn)); + rn = zalloc(sizeof(*rn)); rn->receiver = r; - rn->conf = a->receiver_conf; + rn->lpr = a->receiver_lpr; rn->btrn = btr_new_node(&(struct btr_node_description) - EMBRACE(.name = r->name, .context = rn)); + EMBRACE(.name = name, .context = rn)); ret = r->open(rn); if (ret < 0) { + PARA_ERROR_LOG("could not open %s receiver\n", name); btr_remove_node(&rn->btrn); free(rn); return ret; @@ -648,11 +643,11 @@ static int open_receiver(int format) s->format = format; s->receiver_node = rn; PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n", - audio_formats[format], r->name, slot_num); + audio_formats[format], name, slot_num); rn->task = task_register(&(struct task_info) { - .name = r->name, - .pre_select = r->pre_select, - .post_select = r->post_select, + .name = name, + .pre_monitor = r->pre_monitor, + .post_monitor = r->post_monitor, .context = rn, }, &sched); return slot_num; @@ -752,8 +747,8 @@ static void compute_time_diff(const struct timeval *status_time) if (count > 5) { int s = tv_diff(&diff, &stat_task->sa_time_diff, &tmp); if (tv_diff(&max_deviation, &tmp, NULL) < 0) - PARA_WARNING_LOG("time diff jump: %lums\n", - s * tv2ms(&tmp)); + PARA_WARNING_LOG("time diff jump: %c%lums\n", + s < 0? '-' : '+', tv2ms(&tmp)); } count++; sa_time_diff_sign = tv_convex_combination( @@ -775,45 +770,45 @@ static int update_item(int itemnum, char *buf) { long unsigned sec, usec; - if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME) + if (stat_task->clock_diff_count && itemnum != SI_current_time) return 1; free(stat_item_values[itemnum]); stat_item_values[itemnum] = para_strdup(buf); stat_client_write_item(itemnum); switch (itemnum) { - case SI_STATUS_FLAGS: + case SI_status_flags: stat_task->vss_status = 0; if (strchr(buf, 'N')) stat_task->vss_status |= VSS_STATUS_FLAG_NEXT; if (strchr(buf, 'P')) stat_task->vss_status |= VSS_STATUS_FLAG_PLAYING; break; - case SI_OFFSET: + case SI_offset: stat_task->offset_seconds = atoi(buf); break; - case SI_SECONDS_TOTAL: + case SI_seconds_total: stat_task->length_seconds = atoi(buf); break; - case SI_STREAM_START: + case SI_stream_start: if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { stat_task->server_stream_start.tv_sec = sec; stat_task->server_stream_start.tv_usec = usec; } break; - case SI_CURRENT_TIME: + case SI_current_time: if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { struct timeval tv = {sec, usec}; compute_time_diff(&tv); } break; - case SI_FORMAT: + case SI_format: stat_task->current_audio_format_num = get_audio_format_num(buf); } return 1; } -static int parse_stream_command(const char *txt, char **cmd) +static int parse_stream_command(const char *txt, const char **cmd) { int ret, len; char *re, *p = strchr(txt, ':'); @@ -822,7 +817,7 @@ static int parse_stream_command(const char *txt, char **cmd) return -E_MISSING_COLON; *cmd = p + 1; len = p - txt; - re = malloc(len + 1); + re = alloc(len + 1); strncpy(re, txt, len); re[len] = '\0'; ret = get_matching_audio_format_nums(re); @@ -830,38 +825,38 @@ static int parse_stream_command(const char *txt, char **cmd) return ret; } -static int add_filter(int format, char *cmdline) +static int add_filter(int format, const char *cmdline) { struct audio_format_info *a = &afi[format]; int filter_num, nf = a->num_filters; void *cfg; + struct lls_parse_result *flpr; + + filter_num = filter_setup(cmdline, &cfg, &flpr); + a->filter_lpr = arr_realloc(a->filter_lpr, nf + 1, sizeof(flpr)); + a->filter_conf = arr_realloc(a->filter_conf, nf + 1, sizeof(void *)); + a->filter_nums = arr_realloc(a->filter_nums, nf + 1, sizeof(unsigned)); - filter_num = check_filter_arg(cmdline, &cfg); - if (filter_num < 0) - return filter_num; - a->filter_conf = para_realloc(a->filter_conf, - (nf + 1) * sizeof(void *)); - a->filter_nums = para_realloc(a->filter_nums, - (nf + 1) * sizeof(unsigned)); a->filter_nums[nf] = filter_num; a->filter_conf[nf] = cfg; + a->filter_lpr[nf] = flpr; a->num_filters++; PARA_INFO_LOG("%s filter %d: %s\n", audio_formats[format], nf, - filter_get(filter_num)->name); + filter_name(filter_num)); return filter_num; } static int parse_writer_args(void) { int i, ret; - char *cmd; + const char *cmd; struct audio_format_info *a; - for (i = 0; i < conf.writer_given; i++) { - void *wconf; - int j, nw, writer_num, af_mask; + for (i = 0; i < OPT_GIVEN(WRITER); i++) { + int j, nw, af_mask; - ret = parse_stream_command(conf.writer_arg[i], &cmd); + ret = parse_stream_command(lls_string_val(i, + OPT_RESULT(WRITER)), &cmd); if (ret < 0) return ret; af_mask = ret; @@ -869,47 +864,45 @@ static int parse_writer_args(void) a = afi + j; if ((af_mask & (1 << j)) == 0) /* no match */ continue; - wconf = check_writer_arg_or_die(cmd, &writer_num); nw = a->num_writers; - a->writer_nums = para_realloc(a->writer_nums, (nw + 1) * sizeof(int)); - a->writer_conf = para_realloc(a->writer_conf, (nw + 1) * sizeof(void *)); - a->writer_nums[nw] = writer_num; - a->writer_conf[nw] = wconf; + a->wids = para_realloc(a->wids, (nw + 1) * sizeof(int)); + a->writer_lpr = para_realloc(a->writer_lpr, + (nw + 1) * sizeof(struct lls_parse_result *)); + a->wids[nw] = check_writer_arg_or_die(cmd, + a->writer_lpr + nw); PARA_INFO_LOG("%s writer #%d: %s\n", audio_formats[j], - nw, writer_names[writer_num]); + nw, writer_name(a->wids[nw])); a->num_writers++; } } /* Use default writer for audio formats which are not yet set up. */ FOR_EACH_AUDIO_FORMAT(i) { - void *writer_conf; - int writer_num; a = afi + i; if (a->num_writers > 0) continue; /* already set up */ - writer_conf = check_writer_arg_or_die(NULL, &writer_num); - a->writer_nums = para_malloc(sizeof(int)); - a->writer_nums[0] = writer_num; - a->writer_conf = para_malloc(sizeof(void *)); - a->writer_conf[0] = writer_conf; a->num_writers = 1; + a->wids = alloc(sizeof(int)); + a->writer_lpr = alloc(sizeof(struct lls_parse_result *)); + a->wids[0] = check_writer_arg_or_die(NULL, a->writer_lpr); PARA_INFO_LOG("%s writer: %s (default)\n", audio_formats[i], - writer_names[writer_num]); + writer_name(a->wids[0])); } return 1; } static int parse_receiver_args(void) { - int i, ret, receiver_num; - char *cmd = NULL; + int i, ret; + const char *arg; struct audio_format_info *a; - for (i = conf.receiver_given - 1; i >= 0; i--) { - char *arg; + FOR_EACH_AUDIO_FORMAT(i) + afi[i].receiver_num = -1; + for (i = OPT_GIVEN(RECEIVER) - 1; i >= 0; i--) { int j, af_mask; - ret = parse_stream_command(conf.receiver_arg[i], &arg); + ret = parse_stream_command(lls_string_val(i, + OPT_RESULT(RECEIVER)), &arg); if (ret < 0) goto out; af_mask = ret; @@ -923,37 +916,27 @@ static int parse_receiver_args(void) * config here. Since we are iterating backwards, the winning * receiver arg is in fact the first one given. */ - if (a->receiver_conf) - a->receiver->free_config(a->receiver_conf); - a->receiver_conf = check_receiver_arg(arg, &receiver_num); - ret = -E_RECV_SYNTAX; - if (!a->receiver_conf) - goto out; - a->receiver = receivers + receiver_num; + lls_free_parse_result(a->receiver_lpr, RECEIVER_CMD(a)); + a->receiver_num = check_receiver_arg(arg, &a->receiver_lpr); } } /* - * Use the first available receiver with no arguments for those audio - * formats for which no receiver was specified. + * Use the default receiver for those audio formats for which no + * receiver was specified. */ - cmd = para_strdup(receivers[0].name); FOR_EACH_AUDIO_FORMAT(i) { - a = &afi[i]; - if (a->receiver_conf) + a = afi + i; + if (a->receiver_num >= 0) continue; - a->receiver_conf = check_receiver_arg(cmd, &receiver_num); - if (!a->receiver_conf) - return -E_RECV_SYNTAX; - a->receiver = &receivers[receiver_num]; + a->receiver_num = check_receiver_arg(NULL, &a->receiver_lpr); } FOR_EACH_AUDIO_FORMAT(i) { a = afi + i; PARA_INFO_LOG("receiving %s streams via %s receiver\n", - audio_formats[i], a->receiver->name); + audio_formats[i], lls_command_name(RECEIVER_CMD(a))); } ret = 1; out: - free(cmd); return ret; } @@ -963,6 +946,7 @@ static int init_default_filters(void) FOR_EACH_AUDIO_FORMAT(i) { struct audio_format_info *a = &afi[i]; + const char *name = lls_command_name(RECEIVER_CMD(a)); char *tmp; int j; @@ -972,30 +956,29 @@ static int init_default_filters(void) * udp and dccp streams are fec-encoded, so add fecdec as the * first filter. */ - if (strcmp(afi[i].receiver->name, "udp") == 0 || - strcmp(afi[i].receiver->name, "dccp") == 0) { + if (strcmp(name, "udp") == 0 || strcmp(name, "dccp") == 0) { tmp = para_strdup("fecdec"); - add_filter(i, tmp); + ret = add_filter(i, tmp); free(tmp); if (ret < 0) goto out; } /* add "dec" to audio format name */ tmp = make_message("%sdec", audio_formats[i]); - for (j = 0; filter_get(j); j++) - if (!strcmp(tmp, filter_get(j)->name)) + for (j = 1; filter_get(j); j++) + if (!strcmp(tmp, filter_name(j))) break; free(tmp); ret = -E_UNSUPPORTED_FILTER; if (!filter_get(j)) goto out; - tmp = para_strdup(filter_get(j)->name); + tmp = para_strdup(filter_name(j)); ret = add_filter(i, tmp); free(tmp); if (ret < 0) goto out; PARA_INFO_LOG("%s -> default filter: %s\n", audio_formats[i], - filter_get(j)->name); + filter_name(j)); } out: return ret; @@ -1005,9 +988,10 @@ static int parse_filter_args(void) { int i, j, ret, af_mask, num_matches; - for (i = 0; i < conf.filter_given; i++) { - char *arg; - ret = parse_stream_command(conf.filter_arg[i], &arg); + for (i = 0; i < OPT_GIVEN(FILTER); i++) { + const char *arg; + ret = parse_stream_command(lls_string_val(i, + OPT_RESULT(FILTER)), &arg); if (ret < 0) goto out; af_mask = ret; @@ -1022,7 +1006,7 @@ static int parse_filter_args(void) } if (num_matches == 0) PARA_WARNING_LOG("ignoring filter spec: %s\n", - conf.filter_arg[i]); + lls_string_val(i, OPT_RESULT(FILTER))); } ret = init_default_filters(); /* use default values for the rest */ out: @@ -1048,8 +1032,8 @@ static int parse_stream_args(void) /* does not unlink socket on errors */ static void init_local_socket(struct command_task *ct) { - if (conf.socket_given) - socket_name = para_strdup(conf.socket_arg); + if (OPT_GIVEN(SOCKET)) + socket_name = para_strdup(OPT_STRING_VAL(SOCKET)); else { char *hn = para_hostname(); socket_name = make_message("/var/paraslash/audiod_socket.%s", @@ -1057,7 +1041,7 @@ static void init_local_socket(struct command_task *ct) free(hn); } PARA_NOTICE_LOG("local socket: %s\n", socket_name); - if (conf.force_given) + if (OPT_GIVEN(FORCE)) unlink(socket_name); ct->fd = create_local_socket(socket_name); if (ct->fd >= 0) @@ -1066,7 +1050,7 @@ static void init_local_socket(struct command_task *ct) exit(EXIT_FAILURE); } -static int signal_post_select(struct sched *s, void *context) +static int signal_post_monitor(struct sched *s, void *context) { struct signal_task *st = context; int ret, signum; @@ -1074,25 +1058,25 @@ static int signal_post_select(struct sched *s, void *context) ret = task_get_notification(st->task); if (ret < 0) return ret; - signum = para_next_signal(&s->rfds); + signum = para_next_signal(); switch (signum) { case SIGINT: case SIGTERM: case SIGHUP: - PARA_NOTICE_LOG("received signal %d\n", signum); + PARA_WARNING_LOG("terminating on signal %d\n", signum); task_notify_all(s, E_AUDIOD_SIGNAL); return -E_AUDIOD_SIGNAL; } return 0; } -static void command_pre_select(struct sched *s, void *context) +static void command_pre_monitor(struct sched *s, void *context) { struct command_task *ct = context; - para_fd_set(ct->fd, &s->rfds, &s->max_fileno); + sched_monitor_readfd(ct->fd, s); } -static int command_post_select(struct sched *s, void *context) +static int command_post_monitor(struct sched *s, void *context) { int ret; struct command_task *ct = context; @@ -1103,9 +1087,9 @@ static int command_post_select(struct sched *s, void *context) ret = task_get_notification(ct->task); if (ret < 0) return ret; - ret = handle_connect(ct->fd, &s->rfds); + ret = dispatch_local_connection(ct->fd); if (ret < 0) { - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); if (ret == -E_AUDIOD_TERM) { task_notify_all(s, -ret); return ret; @@ -1143,8 +1127,8 @@ static void init_command_task(struct command_task *ct) ct->task = task_register(&(struct task_info) { .name = "command", - .pre_select = command_pre_select, - .post_select = command_post_select, + .pre_monitor = command_pre_monitor, + .post_monitor = command_post_monitor, .context = ct, }, &sched); } @@ -1232,7 +1216,6 @@ static void audiod_cleanup(void) unlink(socket_name); close_stat_pipe(); close_unused_slots(); - audiod_cmdline_parser_free(&conf); close_stat_clients(); free(uid_whitelist); } @@ -1247,8 +1230,9 @@ static void start_stop_decoders(void) struct slot_info *sl; close_unused_slots(); - if (audiod_status != AUDIOD_ON || - !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING)) + if (audiod_status != AUDIOD_ON) + return notify_writers(E_NOT_PLAYING); + if (!(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING)) return notify_receivers(E_NOT_PLAYING); if (!must_start_decoder()) return; @@ -1265,7 +1249,7 @@ static void start_stop_decoders(void) audiod_status_dump(true); } -static void status_pre_select(struct sched *s, void *context) +static void status_pre_monitor(struct sched *s, void *context) { struct status_task *st = context; int i, ret, cafn = stat_task->current_audio_format_num; @@ -1297,7 +1281,7 @@ min_delay: } /* restart the client task if necessary */ -static int status_post_select(struct sched *s, void *context) +static int status_post_monitor(struct sched *s, void *context) { struct status_task *st = context; int ret; @@ -1313,7 +1297,7 @@ static int status_post_select(struct sched *s, void *context) goto out; } close_stat_pipe(); - st->clock_diff_count = conf.clock_diff_count_arg; + st->clock_diff_count = OPT_UINT32_VAL(CLOCK_DIFF_COUNT); goto out; } if (st->ct) { @@ -1367,10 +1351,10 @@ static int status_post_select(struct sched *s, void *context) client_open(argc, argv, &st->ct, NULL, NULL, st->btrn, s); set_stat_task_restart_barrier(5); } - free(stat_item_values[SI_BASENAME]); - stat_item_values[SI_BASENAME] = para_strdup( + free(stat_item_values[SI_basename]); + stat_item_values[SI_basename] = para_strdup( "no connection to para_server"); - stat_client_write_item(SI_BASENAME); + stat_client_write_item(SI_basename); st->last_status_read = *now; out: start_stop_decoders(); @@ -1381,15 +1365,15 @@ static void init_status_task(struct status_task *st) { memset(st, 0, sizeof(struct status_task)); st->sa_time_diff_sign = 1; - st->clock_diff_count = conf.clock_diff_count_arg; + st->clock_diff_count = OPT_UINT32_VAL(CLOCK_DIFF_COUNT); st->current_audio_format_num = -1; st->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = "stat")); stat_task->task = task_register(&(struct task_info) { .name = "stat", - .pre_select = status_pre_select, - .post_select = status_post_select, + .pre_monitor = status_pre_monitor, + .post_monitor = status_post_monitor, .context = stat_task, }, &sched); } @@ -1397,36 +1381,20 @@ static void init_status_task(struct status_task *st) static void set_initial_status(void) { audiod_status = AUDIOD_ON; - if (!conf.mode_given) + if (!OPT_GIVEN(MODE)) return; - if (!strcmp(conf.mode_arg, "sb")) { + if (!strcmp(OPT_STRING_VAL(MODE), "sb")) { audiod_status = AUDIOD_STANDBY; return; } - if (!strcmp(conf.mode_arg, "off")) { + if (!strcmp(OPT_STRING_VAL(MODE), "off")) { audiod_status = AUDIOD_OFF; return; } - if (strcmp(conf.mode_arg, "on")) + if (strcmp(OPT_STRING_VAL(MODE), "on")) PARA_WARNING_LOG("invalid mode\n"); } -__noreturn static void print_help_and_die(void) -{ - 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); -} - /** * Lookup the given UID in the whitelist. * @@ -1442,14 +1410,33 @@ bool uid_is_whitelisted(uid_t uid) { int i; - if (!conf.user_allow_given) + if (!OPT_GIVEN(USER_ALLOW)) return true; - for (i = 0; i < conf.user_allow_given; i++) + for (i = 0; i < OPT_GIVEN(USER_ALLOW); i++) if (uid == uid_whitelist[i]) return true; return false; } +static void handle_help_flags(void) +{ + char *help; + bool d = OPT_GIVEN(DETAILED_HELP); + + if (d) + help = lls_long_help(CMD_PTR); + else if (OPT_GIVEN(HELP)) + help = lls_short_help(CMD_PTR); + else + return; + printf("%s\n", help); + free(help); + print_receiver_helps(d); + print_filter_helps(d); + print_writer_helps(d); + exit(EXIT_SUCCESS); +} + /** * the main function of para_audiod * @@ -1464,40 +1451,33 @@ int main(int argc, char *argv[]) { int ret, i; struct command_task command_task_struct, *cmd_task = &command_task_struct; - struct audiod_cmdline_parser_params params = { - .override = 0, - .initialize = 1, - .check_required = 0, - .check_ambiguity = 0, - .print_errors = 1 - }; + char *errctx; valid_fd_012(); - audiod_cmdline_parser_ext(argc, argv, &conf, ¶ms); - 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(); - writer_init(); - if (conf.help_given || conf.detailed_help_given) - print_help_and_die(); - daemon_set_priority(conf.priority_arg); - daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg); + ret = lls(lls_parse(argc, argv, CMD_PTR, &lpr, &errctx)); + if (ret < 0) + goto out; + daemon_set_loglevel(OPT_UINT32_VAL(LOGLEVEL)); + daemon_drop_privileges_or_die(OPT_STRING_VAL(USER), + OPT_STRING_VAL(GROUP)); + version_handle_flag("audiod", OPT_GIVEN(VERSION)); + handle_help_flags(); parse_config_or_die(); - if (daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no, - conf.logfile_given)) { - for (i = 0; i < conf.log_color_given; i++) - daemon_set_log_color_or_die(conf.log_color_arg[i]); + crypt_init(); + daemon_set_priority(OPT_UINT32_VAL(PRIORITY)); + if (daemon_init_colors_or_die(OPT_UINT32_VAL(COLOR), COLOR_AUTO, + COLOR_NO, OPT_GIVEN(LOGFILE))) { + for (i = 0; i < OPT_GIVEN(LOG_COLOR); i++) + daemon_set_log_color_or_die(lls_string_val(i, + OPT_RESULT(LOG_COLOR))); } - init_random_seed_or_die(); daemon_set_flag(DF_LOG_TIME); daemon_set_flag(DF_LOG_HOSTNAME); daemon_set_flag(DF_LOG_LL); - if (conf.log_timing_given) + if (OPT_GIVEN(LOG_TIMING)) daemon_set_flag(DF_LOG_TIMING); - if (conf.logfile_given) { - daemon_set_logfile(conf.logfile_arg); + if (OPT_GIVEN(LOGFILE)) { + daemon_set_logfile(OPT_STRING_VAL(LOGFILE)); daemon_open_log_or_die(); } ret = parse_stream_args(); @@ -1515,23 +1495,26 @@ int main(int argc, char *argv[]) init_status_task(stat_task); init_command_task(cmd_task); - if (conf.daemon_given) + if (OPT_GIVEN(DAEMON)) daemonize(false /* parent exits immediately */); signal_task->task = task_register(&(struct task_info) { .name = "signal", - .pre_select = signal_pre_select, - .post_select = signal_post_select, + .pre_monitor = signal_pre_monitor, + .post_monitor = signal_post_monitor, .context = signal_task, }, &sched); - sched.default_timeout.tv_sec = 2; - sched.default_timeout.tv_usec = 999 * 1000; + sched.default_timeout = 2999; ret = schedule(&sched); audiod_cleanup(); sched_shutdown(&sched); signal_shutdown(signal_task); - + crypt_shutdown(); +out: + lls_free_parse_result(lpr, CMD_PTR); + if (errctx) + PARA_ERROR_LOG("%s\n", errctx); if (ret < 0) PARA_EMERG_LOG("%s\n", para_strerror(-ret)); return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;