X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod.c;h=40a35c6a601cf5839b044e44be35992b6e8036d3;hp=2c27648b816ae135ec3823ad1b4dc01695f569a4;hb=c387b216b5fd3c944053e1bba024815719e9a0d9;hpb=39f0303d96983d62b6f5dcdd453ff05f7874a49d diff --git a/audiod.c b/audiod.c index 2c27648b..40a35c6a 100644 --- a/audiod.c +++ b/audiod.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2009 Andre Noll + * Copyright (C) 2005-2011 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "para.h" @@ -92,6 +91,7 @@ struct status_task { struct timeval restart_barrier; /** Last time we received status data from para_server. */ struct timeval last_status_read; + size_t min_iqs; /** The offset value announced by para_server. */ int offset_seconds; /** The length of the current audio file as announced by para_server. */ @@ -166,7 +166,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(const char *name) +static int get_audio_format_num(const char *name) { int i; @@ -190,7 +190,7 @@ int get_audio_format_num(const char *name) * It has to to take into account that probably the stream was not started at * the beginning of the file, that the clock between the server and the client * host may differ and that playback of the stream was delayed, e.g. because - * the prebuffer filter is used in the filter chain of the given slot. + * the prebuffer filter is used in the filter configuration of the given slot. * * If no writer is active in the given slot, or \a slot_num is negative * (indicating that para_audiod runs in standby mode), an approximation based @@ -357,6 +357,8 @@ static void close_receiver(int slot_num) btr_free_node(s->receiver_node->btrn); free(s->receiver_node); s->receiver_node = NULL; + tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), + &a->restart_barrier); } static void writer_cleanup(struct writer_node *wn) @@ -466,20 +468,6 @@ static int get_empty_slot(void) return -E_NO_MORE_SLOTS; } -/** - * get the number of filters - * - * \param audio_format_num the number identifying the audio format - * - * \return the number of filters for the given audio format - * - * \sa struct filter; - */ -int num_filters(int audio_format_num) -{ - return afi[audio_format_num].num_filters; -} - static void open_filters(struct slot_info *s) { struct audio_format_info *a = afi + s->format; @@ -632,6 +620,8 @@ static bool must_start_decoder(void) int cafn = stat_task->current_audio_format_num; unsigned vs = stat_task->vss_status; + if (audiod_status != AUDIOD_ON) + return false; if (cafn < 0) return false; if (!stat_task->ct) @@ -818,6 +808,14 @@ static int parse_receiver_args(void) ret = get_audio_format_num(arg); if (ret < 0) goto out; + /* + * If multiple receivers are given for this audio format, the + * last one wins and we have to free the previous receiver + * config here. Since we are iterating backwards, the winning + * receiver arg is in fact the first one given. + */ + if (afi[ret].receiver_conf) + afi[ret].receiver->free_config(afi[ret].receiver_conf); afi[ret].receiver_conf = check_receiver_arg(recv_arg, &receiver_num); if (!afi[ret].receiver_conf) { ret = -E_RECV_SYNTAX; @@ -825,9 +823,9 @@ static int parse_receiver_args(void) } afi[ret].receiver = &receivers[receiver_num]; } - /* use the first available receiver with no arguments - * for those audio formats for which no receiver - * was specified + /* + * Use the first available receiver with no arguments for those audio + * formats for which no receiver was specified. */ cmd = para_strdup(receivers[0].name); FOR_EACH_AUDIO_FORMAT(i) { @@ -860,7 +858,8 @@ static int init_default_filters(void) * If udp is used to receive this audiod format, add fecdec as * the first filter. */ - if (strcmp(afi[i].receiver->name, "udp") == 0) { + if (strcmp(afi[i].receiver->name, "udp") == 0 || + strcmp(afi[i].receiver->name, "dccp") == 0) { tmp = para_strdup("fecdec"); add_filter(i, tmp); free(tmp); @@ -977,19 +976,16 @@ 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, struct task *t) +static void signal_post_select(struct sched *s, __a_unused struct task *t) { - struct signal_task *st = container_of(t, struct signal_task, task); - - if (!FD_ISSET(st->fd, &s->rfds)) - return; + int signum; - st->signum = para_next_signal(); - switch (st->signum) { + signum = para_next_signal(&s->rfds); + switch (signum) { case SIGINT: case SIGTERM: case SIGHUP: - PARA_EMERG_LOG("terminating on signal %d\n", st->signum); + PARA_EMERG_LOG("terminating on signal %d\n", signum); clean_exit(EXIT_FAILURE, "caught deadly signal"); } } @@ -1020,11 +1016,10 @@ static void command_post_select(struct sched *s, struct task *t) last_status_dump = *now; } - if (!FD_ISSET(ct->fd, &s->rfds)) - return; - ret = handle_connect(ct->fd); + ret = handle_connect(ct->fd, &s->rfds); if (ret < 0) PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + audiod_status_dump(); } static void init_command_task(struct command_task *ct) @@ -1087,17 +1082,17 @@ static void try_to_close_slot(int slot_num) if (s->format < 0) return; - if (s->receiver_node && s->receiver_node->task.error != -E_TASK_UNREGISTERED) + if (s->receiver_node && s->receiver_node->task.error >= 0) return; for (i = 0; i < a->num_filters; i++) - if (s->fns && s->fns[i].task.error != -E_TASK_UNREGISTERED) + if (s->fns && s->fns[i].task.error >= 0) return; if (a->num_writers > 0) { for (i = 0; i < a->num_writers; i++) - if (s->wns && s->wns[i].task.error != -E_TASK_UNREGISTERED) + if (s->wns && s->wns[i].task.error >= 0) return; } else { - if (s->wns && s->wns[0].task.error != -E_TASK_UNREGISTERED) + if (s->wns && s->wns[0].task.error >= 0) return; } PARA_INFO_LOG("closing slot %d\n", slot_num); @@ -1148,10 +1143,19 @@ static void status_pre_select(struct sched *s, struct task *t) ret = btr_node_status(st->btrn, 0, BTR_NT_LEAF); if (ret > 0) goto min_delay; - if (!st->ct) + if (st->ct && audiod_status == AUDIOD_OFF) + goto min_delay; + if (!st->ct && audiod_status != AUDIOD_OFF) sched_request_barrier_or_min_delay(&st->restart_barrier, s); if (cafn >= 0) sched_request_barrier(&afi[cafn].restart_barrier, s); + /* + * If para_server is playing we'd like to have a smooth time display + * even if we are running in standby mode. So we request a timeout that + * expires at the next full second. + */ + if (stat_task->vss_status & VSS_STATUS_FLAG_PLAYING) + sched_request_timeout_ms(1000 - now->tv_usec / 1000, s); return; min_delay: sched_min_delay(s); @@ -1169,7 +1173,7 @@ static void status_post_select(__a_unused struct sched *s, struct task *t) kill_btrn(st->ct->btrn, &st->ct->task, -E_AUDIOD_OFF); goto out; } - if (st->ct->task.error != -E_TASK_UNREGISTERED) + if (st->ct->task.error >= 0) goto out; close_stat_pipe(); st->clock_diff_count = conf.clock_diff_count_arg; @@ -1180,34 +1184,39 @@ static void status_post_select(__a_unused struct sched *s, struct task *t) size_t sz; int ret; if (st->ct->task.error < 0) { - if (st->ct->task.error != -E_TASK_UNREGISTERED) + if (st->ct->task.error >= 0) goto out; close_stat_pipe(); goto out; } if (st->ct->status != CL_RECEIVING) goto out; - ret = btr_node_status(st->btrn, 0, BTR_NT_LEAF); - if (ret <= 0) + ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF); + if (ret <= 0) { + struct timeval diff; + tv_diff(now, &st->last_status_read, &diff); + if (diff.tv_sec > 61) + kill_btrn(st->ct->btrn, &st->ct->task, + -E_STATUS_TIMEOUT); goto out; + } + btr_merge(st->btrn, st->min_iqs); sz = btr_next_buffer(st->btrn, &buf); ret = for_each_stat_item(buf, sz, update_item); if (ret < 0) { kill_btrn(st->ct->btrn, &st->ct->task, ret); goto out; } - if (sz != ret) + if (sz != ret) { + btr_consume(st->btrn, sz - ret); st->last_status_read = *now; - else { - struct timeval diff; - tv_diff(now, &st->last_status_read, &diff); - if (diff.tv_sec > 61) - kill_btrn(st->ct->btrn, &st->ct->task, - -E_STATUS_TIMEOUT); - } - btr_consume(st->btrn, sz - ret); + st->min_iqs = 0; + } else /* current status item crosses buffers */ + st->min_iqs = sz + 1; goto out; } + btr_drain(st->btrn); + st->current_audio_format_num = -1; if (tv_diff(now, &st->restart_barrier, NULL) < 0) goto out; if (st->clock_diff_count) { /* get status only one time */ @@ -1282,17 +1291,14 @@ __noreturn static void print_help_and_die(void) static void init_colors_or_die(void) { - int ret, i; + int i; if (!want_colors()) return; daemon_set_default_log_colors(); daemon_set_flag(DF_COLOR_LOG); - for (i = 0; i < conf.log_color_given; i++) { - ret = daemon_set_log_color(conf.log_color_arg[i]); - if (ret < 0) - exit(EXIT_FAILURE); - } + for (i = 0; i < conf.log_color_given; i++) + daemon_set_log_color_or_die(conf.log_color_arg[i]); } /**