Compare commits

...

2 Commits

Author SHA1 Message Date
6c2ae2f6bb
Give up and implement elapsed time polling
Playback may sometimes stall but it won't produce any events.

This popular workaround likes to jump around, though.
It might be a good idea to use some kind of hybrid approach.

Therefore this is disabled by default so far.

Updates #1
2020-10-18 07:28:14 +02:00
b3579d1128
Explain the ticking mechanism
Took time to read.  Also fix an invalid comment.
2020-10-18 05:57:44 +02:00

View File

@ -609,7 +609,8 @@ static struct app_context
struct str_map playback_info; ///< Current song info struct str_map playback_info; ///< Current song info
struct poller_timer elapsed_event; ///< Seconds elapsed event struct poller_timer elapsed_event; ///< Seconds elapsed event
int64_t elapsed_since; ///< Time of the next tick int64_t elapsed_since; ///< Time of the last tick
bool elapsed_poll; ///< Poll MPD for the elapsed time?
// TODO: initialize these to -1 // TODO: initialize these to -1
int song; ///< Current song index int song; ///< Current song index
@ -692,6 +693,13 @@ tab_selection_range (struct tab *self)
// --- Configuration ----------------------------------------------------------- // --- Configuration -----------------------------------------------------------
static void
on_poll_elapsed_time_changed (struct config_item *item)
{
// This is only set once, on application startup
g.elapsed_poll = item->value.boolean;
}
static struct config_schema g_config_settings[] = static struct config_schema g_config_settings[] =
{ {
{ .name = "address", { .name = "address",
@ -704,6 +712,11 @@ static struct config_schema g_config_settings[] =
{ .name = "root", { .name = "root",
.comment = "Where all the files MPD is playing are located", .comment = "Where all the files MPD is playing are located",
.type = CONFIG_ITEM_STRING }, .type = CONFIG_ITEM_STRING },
{ .name = "poll_elapsed_time",
.comment = "Whether to actively poll MPD for the elapsed time",
.type = CONFIG_ITEM_BOOLEAN,
.on_change = on_poll_elapsed_time_changed,
.default_ = "off" },
{} {}
}; };
@ -3406,11 +3419,20 @@ mpd_update_playback_state (void)
mpd_read_time (duration, &g.song_duration, NULL); mpd_read_time (duration, &g.song_duration, NULL);
strv_free (&fields); strv_free (&fields);
// We could also just poll the server each half a second but let's not
poller_timer_reset (&g.elapsed_event); poller_timer_reset (&g.elapsed_event);
if (g.state == PLAYER_PLAYING) if (g.state == PLAYER_PLAYING)
{ {
poller_timer_set (&g.elapsed_event, 1000 - msec_past_second); int until_next = 1000 - msec_past_second;
// We could make use of "until_next", however this might create
// an intensive busy loop when playback stalls (typically because of
// some network issues). Half a second will work reasonably well.
if (g.elapsed_poll)
until_next = 500;
// Set a timer for when the next round second of playback happens
poller_timer_set (&g.elapsed_event, until_next);
// Remember when the last round second was, relative to monotonic time
g.elapsed_since = clock_msec (CLOCK_BEST) - msec_past_second; g.elapsed_since = clock_msec (CLOCK_BEST) - msec_past_second;
} }
@ -3537,15 +3559,19 @@ mpd_on_info_response (const struct mpd_response *response,
} }
static void static void
mpd_on_tick (void *user_data) mpd_on_elapsed_time_tick (void *user_data)
{ {
(void) user_data; (void) user_data;
// Compute how much time has elapsed since the last round second
int64_t diff_msec = clock_msec (CLOCK_BEST) - g.elapsed_since; int64_t diff_msec = clock_msec (CLOCK_BEST) - g.elapsed_since;
int elapsed_sec = diff_msec / 1000; int elapsed_sec = diff_msec / 1000;
int elapsed_msec = diff_msec % 1000; int elapsed_msec = diff_msec % 1000;
g.song_elapsed += elapsed_sec; g.song_elapsed += elapsed_sec;
g.elapsed_since += elapsed_sec * 1000; g.elapsed_since += elapsed_sec * 1000;
// Try to get called on the next round second of playback
poller_timer_set (&g.elapsed_event, 1000 - elapsed_msec); poller_timer_set (&g.elapsed_event, 1000 - elapsed_msec);
app_invalidate (); app_invalidate ();
@ -3566,6 +3592,15 @@ mpd_request_info (void)
mpd_client_idle (c, 0); mpd_client_idle (c, 0);
} }
static void
mpd_on_elapsed_time_tick_poll (void *user_data)
{
(void) user_data;
// As soon as the reply arrives, we (may) set the timer again
mpd_request_info ();
}
static void static void
mpd_on_events (unsigned subsystems, void *user_data) mpd_on_events (unsigned subsystems, void *user_data)
{ {
@ -3917,7 +3952,9 @@ app_init_poller_events (void)
poller_timer_set (&g.connect_event, 0); poller_timer_set (&g.connect_event, 0);
g.elapsed_event = poller_timer_make (&g.poller); g.elapsed_event = poller_timer_make (&g.poller);
g.elapsed_event.dispatcher = mpd_on_tick; g.elapsed_event.dispatcher = g.elapsed_poll
? mpd_on_elapsed_time_tick_poll
: mpd_on_elapsed_time_tick;
g.refresh_event = poller_idle_make (&g.poller); g.refresh_event = poller_idle_make (&g.poller);
g.refresh_event.dispatcher = app_on_refresh; g.refresh_event.dispatcher = app_on_refresh;