X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=d12b65e5a49193346adc798be3b28293e16bb99c;hp=d771fa68b719edd33b228f94eec0d6b542bbb7be;hb=a94872914afe2e9cc96bb9f8f931a34fb471bb11;hpb=70812d3cc48848784ea4c051fb47cdba965d2c9b diff --git a/audiod.c b/audiod.c index d771fa68..d12b65e5 100644 --- a/audiod.c +++ b/audiod.c @@ -5,19 +5,23 @@ */ /** \file audiod.c the paraslash's audio daemon */ +#include #include #include #include +#include +#include #include "para.h" #include "error.h" +#include "crypt.h" #include "audiod.cmdline.h" #include "list.h" #include "sched.h" #include "ggo.h" #include "recv.h" +#include "buffer_tree.h" #include "filter.h" -#include "grab_client.cmdline.h" #include "grab_client.h" #include "client.cmdline.h" #include "client.h" @@ -49,8 +53,8 @@ struct audio_format_info { void **filter_conf; /** the number of filters that should be activated for this audio format */ unsigned int num_writers; - /** pointer to the array of writers to be activated */ - struct writer **writers; + /** Array of writer numbers to be activated. */ + int *writer_nums; /** pointer to the array of writer configurations */ void **writer_conf; /** do not start receiver/filters/writer before this time */ @@ -66,6 +70,14 @@ struct audio_format_info { * */ struct slot_info slot[MAX_STREAM_SLOTS]; +/** The vss status flags audiod is interested in. */ +enum vss_status_flags { + /** Whether the 'N' flag is set. */ + VSS_STATUS_FLAG_NEXT = 1, + /** The 'P' flag is set. */ + VSS_STATUS_FLAG_PLAYING = 2, +}; + /** * The task for obtaining para_server's status (para_client stat). * @@ -90,8 +102,8 @@ struct status_task { struct timeval sa_time_diff; /** Whether client time is ahead of server time. */ int sa_time_diff_sign; - /** Non-zero if para_server's status is "playing". */ - int playing; + /** The 'P' and the 'N' flags as announced by para_server. */ + enum vss_status_flags vss_status; /** Number of times the clock difference is to be checked. */ unsigned clock_diff_count; /** When to start the next check for clock difference. */ @@ -152,7 +164,7 @@ struct command_task { * \return The audio format number on success, -E_UNSUPPORTED_AUDIO_FORMAT if * \a name is not a supported audio format. */ -int get_audio_format_num(char *name) +int get_audio_format_num(const char *name) { int i; @@ -164,53 +176,84 @@ int get_audio_format_num(char *name) return -E_UNSUPPORTED_AUDIO_FORMAT; } -char *get_time_string(struct timeval *newest_stime) +char *get_time_string(int slot_num) { - struct timeval diff, adj_stream_start, tmp; - int total = 0, use_server_time = 1, - length_seconds = stat_task->length_seconds; + int ret, seconds = 0, length; + struct timeval *tmp, sum, sss, /* server stream start */ + rstime, /* receiver start time */ + wstime, /* writer start time */ + wtime, /* now - writer start */ + rskip; /* receiver start - sss */ + struct slot_info *s = slot_num < 0? NULL : &slot[slot_num]; + char *msg; - if (!stat_task->playing) { - if (length_seconds) + if (audiod_status == AUDIOD_OFF) + goto empty; + if (!(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING)) { + if (stat_task->length_seconds) /* paused */ return NULL; - return make_message("%s:\n", status_item_list[SI_PLAY_TIME]); + goto empty; /* stopped */ + } + if (audiod_status == AUDIOD_ON && !s) + goto empty; + /* + * 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. + */ + length = stat_task->length_seconds; + tmp = &stat_task->server_stream_start; + if (s && s->wns) { /* writer active in this slot */ + 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) { + /* copy status info to slot */ + s->server_stream_start = stat_task->server_stream_start; + s->offset_seconds = stat_task->offset_seconds; + s->seconds_total = stat_task->length_seconds; + } + length = s->seconds_total; + tmp = &s->server_stream_start; + } } - if (audiod_status == AUDIOD_OFF) - goto out; if (stat_task->sa_time_diff_sign > 0) - tv_diff(&stat_task->server_stream_start, &stat_task->sa_time_diff, - &adj_stream_start); + tv_diff(tmp, &stat_task->sa_time_diff, &sss); else - tv_add(&stat_task->server_stream_start, &stat_task->sa_time_diff, - &adj_stream_start); - tmp = adj_stream_start; - if (newest_stime && audiod_status == AUDIOD_ON) { - tv_diff(newest_stime, &adj_stream_start, &diff); - if (tv2ms(&diff) < 5000) { - tmp = *newest_stime; - use_server_time = 0; - } + tv_add(tmp, &stat_task->sa_time_diff, &sss); + if (!s || !s->wns) { + struct timeval diff; + tv_diff(now, &sss, &diff); + seconds = diff.tv_sec + stat_task->offset_seconds; + goto out; } - tv_diff(now, &tmp, &diff); - total = diff.tv_sec + stat_task->offset_seconds; - if (total > length_seconds) - total = length_seconds; - if (total < 0) - total = 0; + tv_diff(now, &wstime, &wtime); + //PARA_CRIT_LOG("offset %d\n", s->offset_seconds); + seconds = s->offset_seconds; + btr_get_node_start(s->receiver_node->btrn, &rstime); + ret = tv_diff(&rstime, &sss, &rskip); + if (ret > 0) { /* audiod was started in the middle of the stream */ + tv_add(&wtime, &rskip, &sum); + seconds += sum.tv_sec; + } else + seconds += wtime.tv_sec; out: - return make_message( - "%s: %s%d:%02d [%d:%02d] (%d%%/%d:%02d)\n", - status_item_list[SI_PLAY_TIME], - use_server_time? "~" : "", - total / 60, - total % 60, - (length_seconds - total) / 60, - (length_seconds - total) % 60, - length_seconds? (total * 100 + length_seconds / 2) / - length_seconds : 0, - length_seconds / 60, - length_seconds % 60 + seconds = PARA_MIN(seconds, length); + seconds = PARA_MAX(seconds, 0); + msg = make_message( + "%s%d:%02d [%d:%02d] (%d%%/%d:%02d)", + s? "" : "~", + seconds / 60, + seconds % 60, + (length - seconds) / 60, + (length - seconds) % 60, + length? (seconds * 100 + length / 2) / length : 0, + length / 60, + length % 60 ); + PARA_DEBUG_LOG("slot %d: %s\n", slot_num, msg); + return msg; +empty: + return para_strdup(NULL); } static int want_colors(void) @@ -265,7 +308,7 @@ static void setup_signal_handling(void) para_install_sighandler(SIGINT); para_install_sighandler(SIGTERM); para_install_sighandler(SIGHUP); - signal(SIGPIPE, SIG_IGN); + para_sigaction(SIGPIPE, SIG_IGN); } static void clear_slot(int slot_num) @@ -281,6 +324,7 @@ static void close_receiver(int slot_num) { struct slot_info *s = &slot[slot_num]; struct audio_format_info *a; + struct timeval restart_delay = {0, 200 * 1000}; if (s->format < 0 || !s->receiver_node) return; @@ -288,29 +332,80 @@ static void close_receiver(int slot_num) PARA_NOTICE_LOG("closing %s receiver in slot %d\n", audio_formats[s->format], slot_num); a->receiver->close(s->receiver_node); + btr_free_node(s->receiver_node->btrn); free(s->receiver_node); s->receiver_node = NULL; + tv_add(now, &restart_delay, &afi[s->format].restart_barrier); } -static void kill_all_decoders(int error) +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); + btr_free_node(wn->btrn); +} + +static void close_writers(struct slot_info *s) +{ + struct audio_format_info *a; + int i; + + if (s->format < 0) + return; + a = afi + s->format; + if (a->num_writers == 0) + writer_cleanup(s->wns); + else { + for (i = 0; i < a->num_writers; i++) + writer_cleanup(s->wns + i); + } + free(s->wns); + s->wns = NULL; +} + +static void _close_filters(struct slot_info *s) { int i; + struct audio_format_info *a = afi + s->format; + if (a->num_filters == 0) + return; + for (i = 0; i < a->num_filters; i++) { + struct filter_node *fn = s->fns + i; + struct filter *f; + + if (!fn) + continue; + f = filters + fn->filter_num; + f->close(fn); + btr_free_node(fn->btrn); + } + free(s->fns); + s->fns = NULL; +} + +static void kill_all_decoders(int error) +{ + int i, j; FOR_EACH_SLOT(i) { struct slot_info *s = &slot[i]; - if (s->wng && s->wng->task.error >= 0) { - PARA_INFO_LOG("deactivating wng in slot %d\n", - i); - s->wng->task.error = error; - } - if (s->fc && s->fc->task.error >= 0) { - PARA_INFO_LOG("deactivatimg filter chain in slot %d\n", i); - s->fc->task.error = error; - } - if (s->receiver_node && s->receiver_node->task.error >= 0) { - PARA_INFO_LOG("deactivating receiver_node in slot %d\n", i); + struct audio_format_info *a; + if (s->format < 0) + continue; + a = afi + s->format; + if (s->wns) + for (j = 0; j < a->num_writers; j++) + s->wns[j].task.error = error; + if (s->fns) + for (j = 0; j < a->num_writers; j++) + s->fns[j].task.error = error; + if (s->receiver_node) s->receiver_node->task.error = error; - } } } @@ -325,7 +420,7 @@ static int get_empty_slot(void) clear_slot(i); return i; } - if (s->wng || s->receiver_node || s->fc) + if (s->wns || s->receiver_node || s->fns) continue; clear_slot(i); return i; @@ -347,88 +442,67 @@ int num_filters(int audio_format_num) return afi[audio_format_num].num_filters; } -static void open_filters(int slot_num) +static void open_filters(struct slot_info *s) { - struct slot_info *s = &slot[slot_num]; - struct audio_format_info *a = &afi[s->format]; + struct audio_format_info *a = afi + s->format; struct filter_node *fn; int nf = a->num_filters; + struct btr_node *parent; int i; - s->fc = NULL; - if (!nf) + if (nf == 0) return; PARA_INFO_LOG("opening %s filters\n", audio_formats[s->format]); - s->fc = para_calloc(sizeof(struct filter_chain)); - s->fc->filter_nodes = para_malloc(nf * sizeof(struct filter_node)); - s->fc->inbuf = s->receiver_node->buf; - s->fc->in_loaded = &s->receiver_node->loaded; - s->fc->input_error = &s->receiver_node->task.error; - s->fc->task.pre_select = filter_pre_select; - s->fc->task.post_select = NULL; - s->fc->task.error = 0; - s->fc->num_filters = nf; - - s->receiver_node->output_error = &s->fc->task.error; - sprintf(s->fc->task.status, "filter chain"); - FOR_EACH_FILTER_NODE(fn, s->fc, i) { + assert(s->fns == NULL); + s->fns = para_calloc(nf * sizeof(struct filter_node)); + parent = s->receiver_node->btrn; + for (i = 0; i < nf; i++) { struct filter *f = filters + a->filter_nums[i]; + fn = s->fns + i; fn->filter_num = a->filter_nums[i]; fn->conf = a->filter_conf[i]; - fn->fc = s->fc; - fn->loaded = 0; - INIT_LIST_HEAD(&fn->callbacks); + fn->task.pre_select = f->pre_select; + fn->task.post_select = f->post_select; + fn->btrn = btr_new_node(f->name, parent, f->execute, fn); f->open(fn); + register_task(&fn->task); + parent = fn->btrn; PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n", - audio_formats[s->format], i, nf, f->name, slot_num); - s->fc->outbuf = fn->buf; - s->fc->out_loaded = &fn->loaded; + audio_formats[s->format], i, nf, f->name, s - slot); + sprintf(fn->task.status, "%s (slot %d)", f->name, s - slot); } - register_task(&s->fc->task); } -static void open_writers(int slot_num) +static void open_writers(struct slot_info *s) { - int ret, i; - struct slot_info *s = &slot[slot_num]; - struct audio_format_info *a = &afi[s->format]; - - PARA_INFO_LOG("opening %s writers\n", audio_formats[s->format]); - if (!a->num_writers) - s->wng = setup_default_wng(); - else - s->wng = wng_new(a->num_writers); - if (s->fc) { - s->wng->buf = s->fc->outbuf; - s->wng->loaded = s->fc->out_loaded; - s->wng->input_error = &s->fc->task.error; - s->wng->channels = &s->fc->channels; - s->wng->samplerate = &s->fc->samplerate; - s->fc->output_error = &s->wng->task.error; - PARA_INFO_LOG("samplerate: %d\n", *s->wng->samplerate); - } else { - s->wng->buf = s->receiver_node->buf; - s->wng->loaded = &s->receiver_node->loaded; - s->wng->input_error = &s->receiver_node->task.error; - } - for (i = 0; i < a->num_writers; i++) { - s->wng->writer_nodes[i].conf = a->writer_conf[i]; - s->wng->writer_nodes[i].writer = a->writers[i]; - } - ret = wng_open(s->wng); - if (ret < 0) { - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - return; + int i; + struct audio_format_info *a = afi + s->format; + struct writer_node *wn; + 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) + * sizeof(struct writer_node)); + if (a->num_writers == 0) + setup_writer_node(NULL, parent, s->wns); + else { + PARA_INFO_LOG("opening %s writers\n", audio_formats[s->format]); + 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]; + register_writer_node(wn, parent); + } } - s->wstime = *now; - activate_inactive_grab_clients(slot_num, s->format, s->fc); } +/* returns slot num on success */ 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; struct receiver_node *rn; const struct timeval restart_delay = {2, 0}; @@ -440,21 +514,23 @@ static int open_receiver(int format) s->format = format; s->receiver_node = para_calloc(sizeof(struct receiver_node)); rn = s->receiver_node; - rn->receiver = a->receiver; + rn->receiver = r; rn->conf = a->receiver_conf; - ret = a->receiver->open(s->receiver_node); + rn->btrn = btr_new_node(r->name, NULL, NULL, rn); + ret = r->open(rn); if (ret < 0) { - free(s->receiver_node); + btr_free_node(rn->btrn); + free(rn); s->receiver_node = NULL; goto err; } PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n", - audio_formats[s->format], a->receiver->name, slot_num); - rn->task.pre_select = a->receiver->pre_select; - rn->task.post_select = a->receiver->post_select; - sprintf(rn->task.status, "%s receiver node", rn->receiver->name); + audio_formats[s->format], r->name, slot_num); + rn->task.pre_select = r->pre_select; + rn->task.post_select = r->post_select; + sprintf(rn->task.status, "%s receiver node", r->name); register_task(&rn->task); - ret = 1; + ret = slot_num; err: if (ret < 0) PARA_ERROR_LOG("%s\n", para_strerror(-ret)); @@ -462,32 +538,82 @@ err: return ret; } +/* return: 0: Not running, 1: Running, -1: Running but eof (or error) */ static int receiver_running(int format) { - int i; + int i, ret = 0; FOR_EACH_SLOT(i) { struct slot_info *s = &slot[i]; - if (s->format == format && s->receiver_node) + if (s->format != format) + continue; + if (!s->receiver_node) + continue; + if (s->receiver_node->task.error >= 0) return 1; + ret = -1; + } + return ret; +} + +struct btr_node *audiod_get_btr_root(void) +{ + int i, newest_slot = -1; + struct timeval newest_rstime = {0, 0}; + + FOR_EACH_SLOT(i) { + struct slot_info *s = &slot[i]; + struct timeval rstime; + if (!s->receiver_node) + continue; + if (s->receiver_node->task.error < 0) + continue; + btr_get_node_start(s->receiver_node->btrn, &rstime); + if (newest_slot >= 0 && tv_diff(&rstime, &newest_rstime, NULL) < 0) + continue; + newest_rstime = rstime; + newest_slot = i; } - return 0; + if (newest_slot == -1) + return NULL; + return slot[newest_slot].receiver_node->btrn; } -static void open_current_receiver(struct sched *s) +/* returns slot num on success. */ +static int open_current_receiver(struct sched *s) { struct timeval diff; - int cafn = stat_task->current_audio_format_num; + int ret, cafn = stat_task->current_audio_format_num; if (cafn < 0 || !stat_task->ct) - return; - if (receiver_running(cafn)) - return; + return -1; + /* Do nothing if the 'N' flag is set or the 'P' flag is unset */ + if (stat_task->vss_status != VSS_STATUS_FLAG_PLAYING) + return -1; + ret = receiver_running(cafn); + if (ret > 0) /* already running and not eof */ + return -1; + if (ret < 0) { /* eof */ + /* + * para_server uses a zero start time during the announcement + * period, i.e. before it sends the first chunk. Wait until + * this period begins to avoid restarting the receiver that + * belongs to the file just completed. + */ + if (stat_task->server_stream_start.tv_sec != 0) { + sched_request_timeout_ms(100, s); + return -1; + } + } if (tv_diff(now, &afi[cafn].restart_barrier, &diff) < 0) { - s->timeout = diff; - return; + if (tv_diff(&s->timeout, &diff, NULL) > 0) + sched_request_timeout(&diff, s); + else + sched_min_delay(s); + return -1; } - open_receiver(cafn); + /* start a new receiver */ + return open_receiver(cafn); } static unsigned compute_time_diff(const struct timeval *status_time) @@ -532,42 +658,31 @@ out: return count; } -static int check_stat_line(char *line, __a_unused void *data) +static int update_item(int itemnum, char *buf) { - int itemnum; - size_t ilen = 0; long unsigned sec, usec; - char *tmp; - //PARA_INFO_LOG("line: %s\n", line); - if (!line) - return 1; - itemnum = stat_line_valid(line); - if (itemnum < 0) { - PARA_WARNING_LOG("invalid status line: %s\n", line); - return 1; - } if (stat_task->clock_diff_count && itemnum != SI_CURRENT_TIME) return 1; - tmp = make_message("%s\n", line); - stat_client_write(tmp, itemnum); - free(tmp); free(stat_item_values[itemnum]); - stat_item_values[itemnum] = para_strdup(line); - ilen = strlen(status_item_list[itemnum]); + stat_item_values[itemnum] = para_strdup(buf); + stat_client_write_item(itemnum); switch (itemnum) { - case SI_STATUS: - stat_task->playing = strstr(line, "playing")? 1 : 0; - PARA_INFO_LOG("stat task playing: %d\n", stat_task->playing); + 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: - stat_task->offset_seconds = atoi(line + ilen + 1); + stat_task->offset_seconds = atoi(buf); break; case SI_SECONDS_TOTAL: - stat_task->length_seconds = atoi(line + ilen + 1); + stat_task->length_seconds = atoi(buf); break; case SI_STREAM_START: - if (sscanf(line + ilen + 1, "%lu.%lu", &sec, &usec) == 2) { + if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { struct timeval a_start, delay; delay.tv_sec = conf.stream_delay_arg / 1000; delay.tv_usec = (conf.stream_delay_arg % 1000) * 1000; @@ -585,14 +700,14 @@ static int check_stat_line(char *line, __a_unused void *data) } break; case SI_CURRENT_TIME: - if (sscanf(line + ilen + 1, "%lu.%lu", &sec, &usec) == 2) { + if (sscanf(buf, "%lu.%lu", &sec, &usec) == 2) { struct timeval tv = {sec, usec}; compute_time_diff(&tv); } break; case SI_FORMAT: - stat_task->current_audio_format_num = get_audio_format_num( - line + ilen + 1); + stat_task->current_audio_format_num + = get_audio_format_num(buf); } return 1; } @@ -640,7 +755,7 @@ static int parse_writer_args(void) FOR_EACH_AUDIO_FORMAT(i) { a = &afi[i]; a->writer_conf = para_malloc(nw * sizeof(void *)); - a->writers = para_malloc(nw * sizeof(struct writer *)); + a->writer_nums = para_malloc(nw * sizeof(int)); a->num_writers = 0; } for (i = 0; i < conf.writer_given; i++) { @@ -656,7 +771,7 @@ static int parse_writer_args(void) ret = writer_num; goto out; } - a->writers[nw] = &writers[writer_num]; + a->writer_nums[nw] = writer_num; a->writer_conf[nw] = wconf; PARA_INFO_LOG("%s writer #%d: %s\n", audio_formats[ret], nw, writer_names[writer_num]); @@ -866,8 +981,15 @@ static void command_post_select(struct sched *s, struct task *t) { int ret; struct command_task *ct = container_of(t, struct command_task, task); + static struct timeval last_status_dump; + struct timeval tmp, delay = {0, 500 * 1000}; + + tv_add(&last_status_dump, &delay, &tmp); + if (tv_diff(&tmp, now, NULL) < 0) { + audiod_status_dump(); + last_status_dump = *now; + } - audiod_status_dump(); if (!FD_ISSET(ct->fd, &s->rfds)) return; ret = handle_connect(ct->fd); @@ -886,21 +1008,16 @@ static void init_command_task(struct command_task *ct) static void close_stat_pipe(void) { - int i; - if (!stat_task->ct) return; client_close(stat_task->ct); stat_task->ct = NULL; - FOR_EACH_STATUS_ITEM(i) { - free(stat_item_values[i]); - stat_item_values[i] = NULL; - } - dump_empty_status(); + clear_and_dump_items(); stat_task->length_seconds = 0; stat_task->offset_seconds = 0; + stat_task->vss_status = 0; + stat_task->current_audio_format_num = -1; audiod_status_dump(); - stat_task->playing = 0; } /** @@ -931,24 +1048,28 @@ 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 try_to_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 != -E_TASK_UNREGISTERED) - return; - if (s->fc && s->fc->task.error != -E_TASK_UNREGISTERED) - return; - if (s->wng && s->wng->task.error != -E_TASK_UNREGISTERED) - return; + return false; + for (i = 0; i < a->num_filters; i++) + if (s->fns && s->fns[i].task.error != -E_TASK_UNREGISTERED) + return false; + for (i = 0; i < a->num_writers; i++) + if (s->wns && s->wns[i].task.error != -E_TASK_UNREGISTERED) + return false; PARA_INFO_LOG("closing slot %d\n", slot_num); - wng_close(s->wng); - close_filters(s->fc); - free(s->fc); + close_writers(s); + _close_filters(s); close_receiver(slot_num); clear_slot(slot_num); + return true; } /* @@ -957,49 +1078,29 @@ static void try_to_close_slot(int slot_num) */ static void start_stop_decoders(struct sched *s) { - int i; + int i, ret; + struct slot_info *sl; + struct audio_format_info *a; FOR_EACH_SLOT(i) - try_to_close_slot(i); - if (audiod_status != AUDIOD_ON || !stat_task->playing) - return kill_all_decoders(-E_NOT_PLAYING); - open_current_receiver(s); - FOR_EACH_SLOT(i) { - struct slot_info *sl = &slot[i]; - struct audio_format_info *a; - struct timeval diff; - - if (sl->format < 0) - continue; - a = &afi[sl->format]; - if (!sl->receiver_node) - continue; - if ((!a->num_filters || sl->fc) && sl->wng) - continue; /* everything already started */ - if (!a->num_filters) { - if (sl->receiver_node->loaded && !sl->wng) { - open_writers(i); - } - continue; - } - if (sl->receiver_node->loaded && !sl->fc) { - open_filters(i); - continue; - } - if (sl->wng || !sl->fc || !*sl->fc->out_loaded) - continue; - if (tv_diff(now, &initial_delay_barrier, &diff) > 0) { - open_writers(i); - continue; - } - PARA_INFO_LOG("initial delay: %lu ms left\n", tv2ms(&diff)); - if (tv_diff(&s->timeout, &diff, NULL) > 0) { - s->timeout = diff; - } - } + if (try_to_close_slot(i)) + sched_min_delay(s); +// if (audiod_status != AUDIOD_ON || +// !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING)) +// return kill_all_decoders(-E_NOT_PLAYING); + ret = open_current_receiver(s); + if (ret < 0) + return; + sl = slot + ret; + a = afi + sl->format; + if (a->num_filters) + open_filters(sl); + open_writers(sl); + activate_grab_clients(); + btr_log_tree(sl->receiver_node->btrn, LL_NOTICE); + sched_min_delay(s); } - /* restart the client task if necessary */ static void status_pre_select(struct sched *s, struct task *t) { @@ -1019,7 +1120,7 @@ static void status_pre_select(struct sched *s, struct task *t) goto out; } if (st->ct) { - unsigned bytes_left; + int ret; if (st->ct->task.error < 0) { if (st->ct->task.error != -E_TASK_UNREGISTERED) goto out; @@ -1028,11 +1129,15 @@ static void status_pre_select(struct sched *s, struct task *t) } if (st->ct->status != CL_RECEIVING) goto out; - bytes_left = for_each_line(st->ct->buf, st->ct->loaded, - &check_stat_line, NULL); - if (st->ct->loaded != bytes_left) { + ret = for_each_stat_item(st->ct->buf, st->ct->loaded, + update_item); + if (ret < 0) { + st->ct->task.error = ret; + goto out; + } + if (st->ct->loaded != ret) { st->last_status_read = *now; - st->ct->loaded = bytes_left; + st->ct->loaded = ret; } else { struct timeval diff; tv_diff(now, &st->last_status_read, &diff); @@ -1044,25 +1149,25 @@ static void status_pre_select(struct sched *s, struct task *t) if (tv_diff(now, &st->restart_barrier, NULL) < 0) goto out; if (st->clock_diff_count) { /* get status only one time */ - char *argv[] = {"audiod", "stat", "1", NULL}; - int argc = 3; + char *argv[] = {"audiod", "--", "stat", "-p", "-n=1", NULL}; + int argc = 5; PARA_INFO_LOG("clock diff count: %d\n", st->clock_diff_count); st->clock_diff_count--; client_open(argc, argv, &st->ct, NULL); set_stat_task_restart_barrier(2); + sched_min_delay(s); } else { - char *argv[] = {"audiod", "stat", NULL}; - int argc = 2; + char *argv[] = {"audiod", "--", "stat", "-p", NULL}; + int argc = 4; client_open(argc, argv, &st->ct, NULL); set_stat_task_restart_barrier(5); + sched_min_delay(s); } free(stat_item_values[SI_BASENAME]); - stat_item_values[SI_BASENAME] = make_message( - "%s: no connection to para_server\n", - status_item_list[SI_BASENAME]); - stat_client_write(stat_item_values[SI_BASENAME], - SI_BASENAME); + stat_item_values[SI_BASENAME] = para_strdup( + "no connection to para_server"); + stat_client_write_item(SI_BASENAME); st->last_status_read = *now; out: start_stop_decoders(s); @@ -1163,9 +1268,12 @@ int main(int argc, char *argv[]) drop_privileges_or_die(conf.user_arg, conf.group_arg); parse_config_or_die(); init_colors_or_die(); + 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) + daemon_set_flag(DF_LOG_TIMING); if (conf.logfile_given) { daemon_set_logfile(conf.logfile_arg); daemon_open_log_or_die(); @@ -1180,7 +1288,6 @@ int main(int argc, char *argv[]) set_initial_status(); FOR_EACH_SLOT(i) clear_slot(i); - init_grabbing(); setup_signal_handling(); signal_setup_default(sig_task); @@ -1193,8 +1300,8 @@ int main(int argc, char *argv[]) register_task(&sig_task->task); register_task(&cmd_task->task); register_task(&stat_task->task); - s.default_timeout.tv_sec = 0; - s.default_timeout.tv_usec = 99 * 1000; + s.default_timeout.tv_sec = 2; + s.default_timeout.tv_usec = 999 * 1000; ret = schedule(&s); PARA_EMERG_LOG("%s\n", para_strerror(-ret));