]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - audiod.c
audiod: Move get_play_time_slot_num() to audiod.c.
[paraslash.git] / audiod.c
index 3f83b984a8215208e1247aade01e06c421e745a6..e73d14135b855b77f361a020d5c0484c4842b13f 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -155,14 +155,22 @@ static struct status_task status_task_struct;
  */
 static struct status_task *stat_task = &status_task_struct;
 
-/**
- * the task for handling audiod commands
+/*
+ * The task for handling audiod commands.
+ *
+ * We need two listening sockets for backward compability: on Linux systems
+ * fd[0] is an abstract socket (more precisely, a socket bound to an address in
+ * the abstract namespace), and fd[1] is the usual pathname socket. On other
+ * systems, fd[0] is negative, and only the pathname socket is used.
  *
- * \sa struct task, struct sched
+ * For 0.5.x we accept connections on both sockets to make sure that old
+ * para_audioc versions can still connect. New versions use only the abstract
+ * socket. Hence after v0.6.0 we can go back to a single socket, either an
+ * abstract one (Linux) or a pathname socket (all other systems).
  */
 struct command_task {
-       /** the local listening socket */
-       int fd;
+       /** The local listening sockets. */
+       int fd[2];
        /** the associated task structure */
        struct task *task;
 };
@@ -206,28 +214,44 @@ static int get_matching_audio_format_nums(const char *re)
        return ret;
 }
 
+static int get_play_time_slot_num(void)
+{
+       int i, oldest_slot = -1;
+       struct timeval oldest_wstime = {0, 0};
+
+       FOR_EACH_SLOT(i) {
+               struct slot_info *s = &slot[i];
+               struct timeval wstime;
+               if (!s->wns || !s->wns[0].btrn)
+                       continue;
+               btr_get_node_start(s->wns[0].btrn, &wstime);
+               if (oldest_slot >= 0 && tv_diff(&wstime, &oldest_wstime, NULL) > 0)
+                       continue;
+               oldest_wstime = wstime;
+               oldest_slot = i;
+       }
+       return oldest_slot;
+}
+
 /**
- * Compute the play time based on information of the given slot.
- *
- * \param slot_num The slot number (negative means: no slot).
+ * Compute the play time based on information of the current slot.
  *
  * This computes a string of the form "0:07 [3:33] (3%/3:40)" using information
  * from the status items received from para_server and the start time of the
- * (first) writer of the given slot.
+ * (first) writer of the current slot.
  *
  * It has to take into account that the stream was probably 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 configuration of the given slot.
+ * the prebuffer filter is used in the filter configuration.
  *
- * 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
- * only on the status items is computed and the returned string is prefixed
- * with "~".
+ * If no writer is active, for example because para_audiod runs in standby
+ * mode, an approximation based only on the status items is computed and the
+ * returned string is prefixed with "~".
  *
  * \return A string that must be freed by the caller.
  */
-char *get_time_string(int slot_num)
+char *get_time_string(void)
 {
        int ret, seconds = 0, length;
        struct timeval *tmp, sum, sss, /* server stream start */
@@ -235,6 +259,7 @@ char *get_time_string(int slot_num)
                wstime, /* writer start time */
                wtime, /* now - writer start */
                rskip; /* receiver start - sss */
+       int slot_num = get_play_time_slot_num();
        struct slot_info *s = slot_num < 0? NULL : &slot[slot_num];
        char *msg;
 
@@ -955,11 +980,8 @@ static int parse_stream_args(void)
 }
 
 /* does not unlink socket on errors */
-static int audiod_get_socket(void)
+static void init_local_sockets(struct command_task *ct)
 {
-       struct sockaddr_un unix_addr;
-       int ret, fd;
-
        if (conf.socket_given)
                socket_name = para_strdup(conf.socket_arg);
        else {
@@ -971,21 +993,12 @@ static int audiod_get_socket(void)
        PARA_NOTICE_LOG("local socket: %s\n", socket_name);
        if (conf.force_given)
                unlink(socket_name);
-       ret = create_local_socket(socket_name, &unix_addr,
+       ct->fd[0] = create_local_socket(socket_name, 0);
+       ct->fd[1] = create_local_socket(socket_name,
                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH);
-       if (ret < 0)
-               goto err;
-       fd = ret;
-       if (listen(fd , 5) < 0) {
-               ret = -ERRNO_TO_PARA_ERROR(errno);
-               goto err;
-       }
-       ret = mark_fd_nonblocking(fd);
-       if (ret < 0)
-               goto err;
-       return fd;
-err:
-       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+       if (ct->fd[0] >= 0 || ct->fd[1] >= 0)
+               return;
+       PARA_EMERG_LOG("%s\n", para_strerror(-ct->fd[1]));
        exit(EXIT_FAILURE);
 }
 
@@ -1012,28 +1025,38 @@ static int signal_post_select(struct sched *s, void *context)
 static void command_pre_select(struct sched *s, void *context)
 {
        struct command_task *ct = context;
-       para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
+       int i;
+
+       for (i = 0; i < 2; i++)
+               if (ct->fd[i] >= 0)
+                       para_fd_set(ct->fd[i], &s->rfds, &s->max_fileno);
 }
 
 static int command_post_select(struct sched *s, void *context)
 {
-       int ret;
+       int ret, i;
        struct command_task *ct = context;
        static struct timeval last_status_dump;
        struct timeval tmp, delay;
-       bool force = true;
+       bool force = false;
 
        ret = task_get_notification(ct->task);
        if (ret < 0)
                return ret;
-       ret = handle_connect(ct->fd, &s->rfds);
-       if (ret < 0) {
-               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
-               if (ret == -E_AUDIOD_TERM) {
-                       task_notify_all(s, -ret);
-                       return ret;
-               }
-       } else if (ret > 0)
+       for (i = 0; i < 2; i++) {
+               if (ct->fd[i] < 0)
+                       continue;
+               ret = handle_connect(ct->fd[i], &s->rfds);
+               if (ret < 0) {
+                       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+                       if (ret == -E_AUDIOD_TERM) {
+                               task_notify_all(s, -ret);
+                               return ret;
+                       }
+               } else if (ret > 0)
+                       force = true;
+       }
+       if (force == true)
                goto dump;
 
        /* if last status dump was less than 500ms ago, do nothing */
@@ -1050,8 +1073,8 @@ static int command_post_select(struct sched *s, void *context)
        delay.tv_sec = 5;
        delay.tv_usec = 0;
        tv_add(&last_status_dump, &delay, &tmp);
-       if (tv_diff(now, &tmp, NULL) < 0)
-               force = false;
+       if (tv_diff(now, &tmp, NULL) > 0)
+               force = true;
 dump:
        audiod_status_dump(force);
        last_status_dump = *now;
@@ -1060,7 +1083,7 @@ dump:
 
 static void init_command_task(struct command_task *ct)
 {
-       ct->fd = audiod_get_socket(); /* doesn't return on errors */
+       init_local_sockets(ct); /* doesn't return on errors */
 
        ct->task = task_register(&(struct task_info) {
                .name = "command",