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)
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);
}
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;
};
/**
- * 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;
};
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++)
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;
}
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)
*/
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);