Enhance time tracking

Now with eliminated timer drift.
This commit is contained in:
Přemysl Eric Janouch 2016-10-04 18:33:14 +02:00
parent 87f5eddea0
commit 859c9d2737
Signed by: p
GPG Key ID: B715679E3A361BE6
1 changed files with 30 additions and 14 deletions

View File

@ -130,6 +130,14 @@ update_curses_terminal_size (void)
#endif // HAVE_RESIZETERM && TIOCGWINSZ
}
static int64_t
clock_msec (clockid_t clock)
{
struct timespec tp;
hard_assert (clock_gettime (clock, &tp) != -1);
return (int64_t) tp.tv_sec * 1000 + (int64_t) tp.tv_nsec / 1000000;
}
// --- Application -------------------------------------------------------------
// Function names are prefixed mostly because of curses which clutters the
@ -215,6 +223,8 @@ static struct app_context
struct str_map song_info; ///< Current song info
struct poller_timer elapsed_event; ///< Seconds elapsed event
int64_t elapsed_since; ///< Time of the next tick
// TODO: initialize these to -1
int song_elapsed; ///< Song elapsed in seconds
int song_duration; ///< Song duration in seconds
@ -1584,8 +1594,12 @@ mpd_on_info_response (const struct mpd_response *response,
// Note that we may receive a "time" field twice, however the right one
// wins here due to the order we send the commands in
// The contents of these values overlap and we try to get what we can
// FIXME: don't change the values, for fuck's sake
char *time = str_map_find (&map, "time");
char *duration = str_map_find (&map, "duration");
char *elapsed = str_map_find (&map, "elapsed");
if (time)
{
char *colon = strchr (time, ':');
@ -1602,8 +1616,10 @@ mpd_on_info_response (const struct mpd_response *response,
if (duration && xstrtoul (&tmp, duration, 10))
g_ctx.song_duration = tmp;
// TODO: use "time" as a fallback (no milliseconds there)
char *period, *elapsed = str_map_find (&map, "elapsed");
// We could also just poll the server each half a second but let's not
int msec_past_second = 0;
char *period;
if (elapsed && (period = strchr (elapsed, '.')))
{
// For some reason this is much more precise
@ -1613,12 +1629,12 @@ mpd_on_info_response (const struct mpd_response *response,
if (g_ctx.state == PLAYER_PLAYING
&& xstrtoul (&tmp, period, 10))
{
// TODO: initialize the timer and create a callback
poller_timer_set (&g_ctx.elapsed_event, 1000 - tmp);
}
msec_past_second = tmp;
}
poller_timer_set (&g_ctx.elapsed_event, 1000 - msec_past_second);
g_ctx.elapsed_since = clock_msec (CLOCK_BEST) - msec_past_second;
// The server sends -1 when nothing is being played right now
char *volume = str_map_find (&map, "volume");
if (volume && xstrtoul (&tmp, volume, 10))
g_ctx.volume = tmp;
@ -1631,10 +1647,14 @@ static void
mpd_on_tick (void *user_data)
{
(void) user_data;
// FIXME: this is doomed to drift unless we use POSIX CLOCK_MONOTONIC
poller_timer_set (&g_ctx.elapsed_event, 1000);
int64_t diff_msec = clock_msec (CLOCK_BEST) - g_ctx.elapsed_since;
int elapsed_sec = diff_msec / 1000;
int elapsed_msec = diff_msec % 1000;
g_ctx.song_elapsed += elapsed_sec;
g_ctx.elapsed_since += elapsed_sec * 1000;
poller_timer_set (&g_ctx.elapsed_event, 1000 - elapsed_msec);
g_ctx.song_elapsed++;
// TODO: try to be more efficient in the redrawing procedures
app_redraw ();
}
@ -1891,11 +1911,7 @@ debug_tab_push (const char *message, chtype attrs)
&g_debug_tab.items[g_debug_tab.super.item_count++];
item->text = xstrdup (message);
item->attrs = attrs;
struct timespec tp;
hard_assert (clock_gettime (CLOCK_REALTIME, &tp) != -1);
item->timestamp = (int64_t) tp.tv_sec * 1000
+ (int64_t) tp.tv_nsec / 1000000;
item->timestamp = clock_msec (CLOCK_REALTIME);
app_redraw_view ();
}