Rewrite mpd_update_playback_state()
- no longer make destructive changes to the state - use "duration" and support millisecond precision - clean up
This commit is contained in:
		
							
								
								
									
										82
									
								
								nncmpp.c
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								nncmpp.c
									
									
									
									
									
								
							@@ -2506,10 +2506,31 @@ debug_tab_init (void)
 | 
			
		||||
 | 
			
		||||
// --- MPD interface -----------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
mpd_read_time (const char *value, int *sec, int *optional_msec)
 | 
			
		||||
{
 | 
			
		||||
	if (!value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	char *end, *period = strchr (value, '.');
 | 
			
		||||
	if (optional_msec && period)
 | 
			
		||||
	{
 | 
			
		||||
		unsigned long n = strtoul (period + 1, &end, 10);
 | 
			
		||||
		if (*end)
 | 
			
		||||
			return;
 | 
			
		||||
		*optional_msec = MIN (INT_MAX, n);
 | 
			
		||||
	}
 | 
			
		||||
	unsigned long n = strtoul (value, &end, 10);
 | 
			
		||||
	if (end == period || !*end)
 | 
			
		||||
		*sec = MIN (INT_MAX, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
mpd_update_playback_state (void)
 | 
			
		||||
{
 | 
			
		||||
	struct str_map *map = &g_ctx.playback_info;
 | 
			
		||||
	g_ctx.song_elapsed = g_ctx.song_duration = g_ctx.volume = g_ctx.song = -1;
 | 
			
		||||
	g_ctx.playlist_version = 0;
 | 
			
		||||
 | 
			
		||||
	const char *state;
 | 
			
		||||
	g_ctx.state = PLAYER_PLAYING;
 | 
			
		||||
@@ -2521,39 +2542,29 @@ mpd_update_playback_state (void)
 | 
			
		||||
			g_ctx.state = PLAYER_PAUSED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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");
 | 
			
		||||
	// Values in "time" are always rounded.  "elapsed", introduced in MPD 0.16,
 | 
			
		||||
	// is in millisecond precision and "duration" as well, starting with 0.20.
 | 
			
		||||
	// Prefer the more precise values but use what we have.
 | 
			
		||||
	const char *time     = str_map_find (map, "time");
 | 
			
		||||
	const char *elapsed  = str_map_find (map, "elapsed");
 | 
			
		||||
	const char *duration = str_map_find (map, "duration");
 | 
			
		||||
 | 
			
		||||
	struct strv fields;
 | 
			
		||||
	strv_init (&fields);
 | 
			
		||||
	if (time)
 | 
			
		||||
	{
 | 
			
		||||
		char *colon = strchr (time, ':');
 | 
			
		||||
		if (colon)
 | 
			
		||||
		{
 | 
			
		||||
			*colon = '\0';
 | 
			
		||||
			duration = colon + 1;
 | 
			
		||||
		}
 | 
			
		||||
		cstr_split (time, ":", false, &fields);
 | 
			
		||||
		if (fields.len >= 1 && !elapsed)   elapsed  = fields.vector[0];
 | 
			
		||||
		if (fields.len >= 2 && !duration)  duration = fields.vector[1];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unsigned long n;
 | 
			
		||||
	if (time     && xstrtoul (&n, time,     10))  g_ctx.song_elapsed  = n;
 | 
			
		||||
	if (duration && xstrtoul (&n, duration, 10))  g_ctx.song_duration = n;
 | 
			
		||||
	int msec_past_second = 0;
 | 
			
		||||
	mpd_read_time (elapsed,  &g_ctx.song_elapsed,  &msec_past_second);
 | 
			
		||||
	mpd_read_time (duration, &g_ctx.song_duration, NULL);
 | 
			
		||||
	strv_free (&fields);
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
		*period++ = '\0';
 | 
			
		||||
		if (xstrtoul (&n, elapsed, 10))
 | 
			
		||||
			g_ctx.song_elapsed = n;
 | 
			
		||||
 | 
			
		||||
		if (xstrtoul (&n, period, 10))
 | 
			
		||||
			msec_past_second = n;
 | 
			
		||||
	}
 | 
			
		||||
	poller_timer_reset (&g_ctx.elapsed_event);
 | 
			
		||||
	if (g_ctx.state == PLAYER_PLAYING)
 | 
			
		||||
	{
 | 
			
		||||
		poller_timer_set (&g_ctx.elapsed_event, 1000 - msec_past_second);
 | 
			
		||||
@@ -2561,10 +2572,13 @@ mpd_update_playback_state (void)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The server sends -1 when nothing is being played right now
 | 
			
		||||
	unsigned long n;
 | 
			
		||||
	if (xstrtoul_map (map, "volume",   &n))  g_ctx.volume           = n;
 | 
			
		||||
 | 
			
		||||
	if (xstrtoul_map (map, "playlist", &n))  g_ctx.playlist_version = n;
 | 
			
		||||
	if (xstrtoul_map (map, "song",     &n))  g_ctx.song             = n;
 | 
			
		||||
 | 
			
		||||
	app_invalidate ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
			
		||||
@@ -2614,16 +2628,8 @@ mpd_on_info_response (const struct mpd_response *response,
 | 
			
		||||
{
 | 
			
		||||
	(void) user_data;
 | 
			
		||||
 | 
			
		||||
	// TODO: do this also on disconnect
 | 
			
		||||
	g_ctx.song = -1;
 | 
			
		||||
	g_ctx.song_elapsed = -1;
 | 
			
		||||
	g_ctx.song_duration = -1;
 | 
			
		||||
	g_ctx.volume = -1;
 | 
			
		||||
	str_map_free (&g_ctx.playback_info);
 | 
			
		||||
	poller_timer_reset (&g_ctx.elapsed_event);
 | 
			
		||||
	g_ctx.playlist_version = 0;
 | 
			
		||||
	// TODO: preset an error player state?
 | 
			
		||||
 | 
			
		||||
	str_map_free (&g_ctx.playback_info);
 | 
			
		||||
	if (!response->success)
 | 
			
		||||
		print_debug ("%s: %s",
 | 
			
		||||
			"retrieving MPD info failed", response->message_text);
 | 
			
		||||
@@ -2635,7 +2641,6 @@ mpd_on_info_response (const struct mpd_response *response,
 | 
			
		||||
	mpd_update_playback_state ();
 | 
			
		||||
	current_tab_update ();
 | 
			
		||||
	info_tab_update ();
 | 
			
		||||
	app_invalidate ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@@ -2740,6 +2745,9 @@ mpd_on_failure (void *user_data)
 | 
			
		||||
	// This is also triggered both by a failed connect and a clean disconnect
 | 
			
		||||
	print_error ("connection to MPD failed");
 | 
			
		||||
	mpd_queue_reconnect ();
 | 
			
		||||
 | 
			
		||||
	// TODO: reset all state related to the connection and update the UI:
 | 
			
		||||
	//   str_map_free(&g_ctx.playback_info), mpd_update_playback_state()?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user