private void OnNowPlayingResponse(IAsyncResult ar)
        {
            try {
                current_now_playing_request.EndSend(ar);
            } catch (Exception e) {
                Log.Exception("Failed to complete the NowPlaying request", e);
                state = State.Idle;
                current_now_playing_request = null;
                return;
            }

            StationError error = current_now_playing_request.GetError();

            // API docs say "Now Playing requests that fail should not be retried".
            if (error == StationError.InvalidSessionKey)
            {
                Log.Warning("Audioscrobbler NowPlaying failed", "Session ID sent was invalid", false);
                // TODO: Suggest to the user to (re)do the Last.fm authentication ?
            }
            else if (error != StationError.None)
            {
                Log.WarningFormat("Audioscrobbler NowPlaying failed: {0}", error.ToString());
            }
            else
            {
                Log.Debug("Submitted NowPlaying track to Audioscrobbler");
                now_playing_started = false;
            }
            current_now_playing_request = null;
        }
        private void OnScrobbleResponse(IAsyncResult ar)
        {
            int nb_tracks_scrobbled = 0;

            try {
                current_scrobble_request.EndSend(ar);
                nb_tracks_scrobbled = (int)ar.AsyncState;
            } catch (Exception e) {
                Log.Exception("Failed to complete the scrobble request", e);
                state = State.Idle;
                return;
            }

            JsonObject response = null;

            try {
                response = current_scrobble_request.GetResponseObject();
            } catch (Exception e) {
                Log.Exception("Failed to process the scrobble response", e);
                state = State.Idle;
                return;
            }

            var error = current_scrobble_request.GetError();

            if (error == StationError.ServiceOffline || error == StationError.TemporarilyUnavailable)
            {
                Log.WarningFormat("Lastfm is temporarily unavailable: {0}", (string)response ["message"]);
                next_interval = DateTime.Now + new TimeSpan(0, 0, RETRY_SECONDS);
                hard_failures++;
                state = State.Idle;
            }
            else if (error != StationError.None)
            {
                // TODO: If error == StationError.InvalidSessionKey,
                // suggest to the user to (re)do the Last.fm authentication.
                hard_failures++;

                queue.RemoveInvalidTracks();

                // if there are still valid tracks in the queue then retransmit on the next interval
                if (queue.Count > 0)
                {
                    state = State.NeedTransmit;
                }
                else
                {
                    state = State.Idle;
                }
            }
            else
            {
                try {
                    var scrobbles      = (JsonObject)response["scrobbles"];
                    var scrobbles_attr = (JsonObject)scrobbles["@attr"];
                    Log.InformationFormat("Audioscrobbler upload succeeded: {0} accepted, {1} ignored",
                                          scrobbles_attr["accepted"], scrobbles_attr["ignored"]);

                    if (nb_tracks_scrobbled > 1)
                    {
                        var scrobble_array = (JsonArray)scrobbles["scrobble"];
                        foreach (JsonObject scrobbled_track in scrobble_array)
                        {
                            LogIfIgnored(scrobbled_track);
                        }
                    }
                    else
                    {
                        var scrobbled_track = (JsonObject)scrobbles["scrobble"];
                        LogIfIgnored(scrobbled_track);
                    }
                } catch (Exception) {
                    Log.Information("Audioscrobbler upload succeeded but unknown response received");
                    Log.Debug("Response received", response.ToString());
                }

                hard_failures = 0;

                // we succeeded, pop the elements off our queue
                queue.RemoveRange(0, nb_tracks_scrobbled);
                queue.Save();

                state = State.Idle;
            }
        }