/** * This is the "PLAYLIST" event handler. It is invoked by the player * thread whenever it requests a new queued song, or when it exits. */ void playlist_sync(struct playlist *playlist, struct player_control *pc) { if (!playlist->playing) /* this event has reached us out of sync: we aren't playing anymore; ignore the event */ return; player_lock(pc); enum player_state pc_state = pc_get_state(pc); const struct song *pc_next_song = pc->next_song; player_unlock(pc); if (pc_state == PLAYER_STATE_STOP) /* the player thread has stopped: check if playback should be restarted with the next song. That can happen if the playlist isn't filling the queue fast enough */ playlist_resume_playback(playlist, pc); else { /* check if the player thread has already started playing the queued song */ if (pc_next_song == NULL && playlist->queued != -1) playlist_song_started(playlist, pc); player_lock(pc); pc_next_song = pc->next_song; player_unlock(pc); /* make sure the queued song is always set (if possible) */ if (pc_next_song == NULL && playlist->queued < 0) playlist_update_queued_song(playlist, pc, NULL); } }
static void playlist_delete_internal(struct playlist *playlist, unsigned song, const struct song **queued_p) { unsigned songOrder; assert(song < queue_length(&playlist->queue)); songOrder = queue_position_to_order(&playlist->queue, song); if (playlist->playing && playlist->current == (int)songOrder) { bool paused = pc_get_state() == PLAYER_STATE_PAUSE; /* the current song is going to be deleted: stop the player */ pc_stop(); playlist->playing = false; /* see which song is going to be played instead */ playlist->current = queue_next_order(&playlist->queue, playlist->current); if (playlist->current == (int)songOrder) playlist->current = -1; if (playlist->current >= 0 && !paused) /* play the song after the deleted one */ playlist_play_order(playlist, playlist->current); else /* no songs left to play, stop playback completely */ playlist_stop(playlist); *queued_p = NULL; } else if (playlist->current == (int)songOrder) /* there's a "current song" but we're not playing currently - clear "current" */ playlist->current = -1; /* now do it: remove the song */ if (!song_in_database(queue_get(&playlist->queue, song))) pc_song_deleted(queue_get(&playlist->queue, song)); queue_delete(&playlist->queue, song); /* update the "current" and "queued" variables */ if (playlist->current > (int)songOrder) { playlist->current--; } }
/** * The player has stopped for some reason. Check the error, and * decide whether to re-start playback */ static void playlist_resume_playback(struct playlist *playlist, struct player_control *pc) { enum player_error error; assert(playlist->playing); assert(pc_get_state(pc) == PLAYER_STATE_STOP); error = pc_get_error_type(pc); if (error == PLAYER_ERROR_NONE) playlist->error_count = 0; else ++playlist->error_count; if ((playlist->stop_on_error && error != PLAYER_ERROR_NONE) || error == PLAYER_ERROR_OUTPUT || playlist->error_count >= queue_length(&playlist->queue)) /* too many errors, or critical error: stop playback */ playlist_stop(playlist, pc); else /* continue playback at the next song */ playlist_next(playlist, pc); }