audiod: Improve display of play time.
authorAndre Noll <maan@systemlinux.org>
Thu, 19 Mar 2009 21:51:17 +0000 (22:51 +0100)
committerAndre Noll <maan@systemlinux.org>
Thu, 19 Mar 2009 21:51:17 +0000 (22:51 +0100)
Keeping track of the offset, server stream start and the duration
of the audio file length at the time the receiver/writer was started
allows to compute the play time more accurately.

audiod.c
audiod.h
audiod_command.c

index 3f46acb..3a2607d 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -172,53 +172,66 @@ 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 */
+               wtime, /* now - writer start */
+               rskip; /* receiver start - sss */
+       struct slot_info *s = slot_num < 0? NULL : &slot[slot_num];
 
+       if (audiod_status == AUDIOD_OFF)
+               goto empty;
        if (!(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING)) {
-               if (length_seconds)
+               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 */
+       if (s) { /* writer active in this slot */
+               length = s->seconds_total;
+               tmp = &s->server_stream_start;
+       } else { /* standby mode, rely on status items */
+               length = stat_task->length_seconds;
+               tmp = &stat_task->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) {
+               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, &s->wstime, &wtime);
+       seconds = s->offset_seconds;
+       ret = tv_diff(&s->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:
+       seconds = PARA_MIN(seconds, length);
+       seconds = PARA_MAX(seconds, 0);
        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
+               s? "" : "~",
+               seconds / 60,
+               seconds % 60,
+               (length - seconds) / 60,
+               (length - seconds) % 60,
+               length? (seconds * 100 + length / 2) / length : 0,
+               length / 60,
+               length % 60
        );
+empty:
+       return make_message("%s:\n", status_item_list[SI_PLAY_TIME]);
 }
 
 static int want_colors(void)
@@ -429,6 +442,10 @@ static void open_writers(int slot_num)
                return;
        }
        s->wstime = *now;
+       s->server_stream_start = stat_task->server_stream_start.tv_sec?
+               stat_task->server_stream_start : *now;
+       s->offset_seconds = stat_task->offset_seconds;
+       s->seconds_total = stat_task->length_seconds;
        activate_inactive_grab_clients(slot_num, s->format, s->fc);
 }
 
@@ -460,6 +477,7 @@ static int open_receiver(int format)
                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;
+       s->rstime = *now;
        sprintf(rn->task.status, "%s receiver node", rn->receiver->name);
        register_task(&rn->task);
        ret = 1;
index 74d598c..8b416ce 100644 (file)
--- a/audiod.h
+++ b/audiod.h
@@ -49,21 +49,29 @@ struct audiod_command {
 };
 
 /**
- * describes one instance of a receiver-filter-writer chain
+ * Describes one instance of a receiver-filter-writer chain.
  *
  * \sa receiver_node, receiver, filter, filter_node, filter_chain, writer,
  * writer_node, writer_node_group.
  */
 struct slot_info {
-       /** number of the audio format in this slot */
+       /** Number of the audio format in this slot. */
        int format;
-       /** writer start time */
+       /** Receiver start time. */
+       struct timeval rstime;
+       /** Writer start time. */
        struct timeval wstime;
-       /** the receiver info associated with this slot */
+       /** The stream_start status item announced by para_server.  */
+       struct timeval server_stream_start;
+       /** The offset status item announced by para_server. */
+       unsigned offset_seconds;
+       /** The seconds_total status item announced by para_server. */
+       unsigned seconds_total;
+       /** The receiver info associated with this slot. */
        struct receiver_node *receiver_node;
-       /** the active filter chain */
+       /** The active filter chain. */
        struct filter_chain *fc;
-       /** the active writer node group */
+       /** The active writer node group. */
        struct writer_node_group *wng;
 };
 
@@ -75,7 +83,7 @@ void __noreturn clean_exit(int status, const char *msg);
 int handle_connect(int accept_fd);
 void audiod_status_dump(void);
 void dump_empty_status(void);
-char *get_time_string(struct timeval *newest_stime);
+char *get_time_string(int slot_num);
 
 /** iterate over all slots */
 #define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++)
index 3b41376..3467dbe 100644 (file)
@@ -46,20 +46,22 @@ __malloc static char *audiod_status_string(void)
        return make_message("%s: %s\n", status_item_list[SI_AUDIOD_STATUS], status);
 }
 
-static struct timeval *wstime(void)
+static int get_play_time_slot_num(void)
 {
-       int i;
-       struct timeval *max = NULL;
+       int i, oldest = -1;
+
        FOR_EACH_SLOT(i) {
                struct slot_info *s = &slot[i];
                if (!s->wng)
                        continue;
-               if (max && tv_diff(&s->wstime, max, NULL) <= 0)
+               if (oldest >= 0 && tv_diff(&s->wstime, &slot[oldest].wstime,
+                               NULL) > 0)
                        continue;
-               max = &s->wstime;
+               oldest = i;
        }
-       return max;
+       return oldest;
 }
+
 __malloc static char *decoder_flags(void)
 {
        int i;
@@ -181,8 +183,8 @@ int com_stat(int fd, __a_unused int argc, __a_unused char **argv)
        }
        PARA_INFO_LOG("mask: 0x%lx\n", mask);
        if (mask & (1 << SI_PLAY_TIME)) {
-               struct timeval *t = wstime();
-               char *ts = get_time_string(t);
+               int slot_num = get_play_time_slot_num();
+               char *ts = get_time_string(slot_num);
                if (ts) {
                        ret = client_write(fd, ts);
                        if (ret < 0)
@@ -422,11 +424,11 @@ out:
  */
 void audiod_status_dump(void)
 {
-       struct timeval *t = wstime();
+       int slot_num = get_play_time_slot_num();
        char *old, *new, *tmp;
 
        old = stat_item_values[SI_PLAY_TIME];
-       new = get_time_string(t);
+       new = get_time_string(slot_num);
        if (new) {
                if (!old || strcmp(old, new)) {
                        free(old);