void
playlist_stop(struct playlist *playlist, struct player_control *pc)
{
	if (!playlist->playing)
		return;

	assert(playlist->current >= 0);

	g_debug("stop");
	pc_stop(pc);
	playlist->queued = -1;
	playlist->playing = false;

	if (playlist->queue.random) {
		/* shuffle the playlist, so the next playback will
		   result in a new random order */

		unsigned current_position =
			queue_order_to_position(&playlist->queue,
						playlist->current);

		queue_shuffle_order(&playlist->queue);

		/* make sure that "current" stays valid, and the next
		   "play" command plays the same song again */
		playlist->current =
			queue_position_to_order(&playlist->queue,
						current_position);
	}
}
Exemple #2
0
void
playlist_update_queued_song(struct playlist *playlist,
			    struct player_control *pc,
			    const struct song *prev)
{
	int next_order;
	const struct song *next_song;

	if (!playlist->playing)
		return;

	assert(!queue_is_empty(&playlist->queue));
	assert((playlist->queued < 0) == (prev == NULL));

	next_order = playlist->current >= 0
		? queue_next_order(&playlist->queue, playlist->current)
		: 0;

	if (next_order == 0 && playlist->queue.random &&
	    !playlist->queue.single) {
		/* shuffle the song order again, so we get a different
		   order each time the playlist is played
		   completely */
		unsigned current_position =
			queue_order_to_position(&playlist->queue,
						playlist->current);

		queue_shuffle_order(&playlist->queue);

		/* make sure that the playlist->current still points to
		   the current song, after the song order has been
		   shuffled */
		playlist->current =
			queue_position_to_order(&playlist->queue,
						current_position);
	}

	if (next_order >= 0)
		next_song = queue_get_order(&playlist->queue, next_order);
	else
		next_song = NULL;

	if (prev != NULL && next_song != prev) {
		/* clear the currently queued song */
		pc_cancel(pc);
		playlist->queued = -1;
	}

	if (next_order >= 0) {
		if (next_song != prev)
			playlist_queue_song_order(playlist, pc, next_order);
		else
			playlist->queued = next_order;
	}
}
void
playlist_next(struct playlist *playlist, struct player_control *pc)
{
	int next_order;
	int current;

	if (!playlist->playing)
		return;

	assert(!queue_is_empty(&playlist->queue));
	assert(queue_valid_order(&playlist->queue, playlist->current));

	current = playlist->current;
	playlist->stop_on_error = false;

	/* determine the next song from the queue's order list */

	next_order = queue_next_order(&playlist->queue, playlist->current);
	if (next_order < 0) {
		/* no song after this one: stop playback */
		playlist_stop(playlist, pc);

		/* reset "current song" */
		playlist->current = -1;
	}
	else
	{
		if (next_order == 0 && playlist->queue.random) {
			/* The queue told us that the next song is the first
			   song.  This means we are in repeat mode.  Shuffle
			   the queue order, so this time, the user hears the
			   songs in a different than before */
			assert(playlist->queue.repeat);

			queue_shuffle_order(&playlist->queue);

			/* note that playlist->current and playlist->queued are
			   now invalid, but playlist_play_order() will
			   discard them anyway */
		}

		playlist_play_order(playlist, pc, next_order);
	}

	/* Consume mode removes each played songs. */
	if(playlist->queue.consume)
		playlist_delete(playlist, pc,
				queue_order_to_position(&playlist->queue,
							current));
}
Exemple #4
0
void
playlist_set_random(struct playlist *playlist, struct player_control *pc,
		    bool status)
{
	const struct song *queued;

	if (status == playlist->queue.random)
		return;

	queued = playlist_get_queued_song(playlist);

	playlist->queue.random = status;

	if (playlist->queue.random) {
		/* shuffle the queue order, but preserve
		   playlist->current */

		int current_position =
			playlist->playing && playlist->current >= 0
			? (int)queue_order_to_position(&playlist->queue,
						       playlist->current)
			: -1;

		queue_shuffle_order(&playlist->queue);

		if (current_position >= 0) {
			/* make sure the current song is the first in
			   the order list, so the whole rest of the
			   playlist is played after that */
			unsigned current_order =
				queue_position_to_order(&playlist->queue,
							current_position);
			queue_swap_order(&playlist->queue, 0, current_order);
			playlist->current = 0;
		} else
			playlist->current = -1;
	} else
		playlist_order(playlist);

	playlist_update_queued_song(playlist, pc, queued);

	idle_add(IDLE_OPTIONS);
}
int
main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
{
	struct song songs[16];

	struct queue queue;
	queue_init(&queue, 32);

	for (unsigned i = 0; i < G_N_ELEMENTS(songs); ++i)
		queue_append(&queue, &songs[i]);

	assert(queue_length(&queue) == G_N_ELEMENTS(songs));

	/* priority=10 for 4 items */

	queue_set_priority_range(&queue, 4, 8, 10, -1);

	queue.random = true;
	queue_shuffle_order(&queue);
	check_descending_priority(&queue, 0);

	for (unsigned i = 0; i < 4; ++i) {
		assert(queue_position_to_order(&queue, i) >= 4);
	}

	for (unsigned i = 4; i < 8; ++i) {
		assert(queue_position_to_order(&queue, i) < 4);
	}

	for (unsigned i = 8; i < G_N_ELEMENTS(songs); ++i) {
		assert(queue_position_to_order(&queue, i) >= 4);
	}

	/* priority=50 one more item */

	queue_set_priority_range(&queue, 15, 16, 50, -1);
	check_descending_priority(&queue, 0);

	assert(queue_position_to_order(&queue, 15) == 0);

	for (unsigned i = 0; i < 4; ++i) {
		assert(queue_position_to_order(&queue, i) >= 4);
	}

	for (unsigned i = 4; i < 8; ++i) {
		assert(queue_position_to_order(&queue, i) >= 1 &&
		       queue_position_to_order(&queue, i) < 5);
	}

	for (unsigned i = 8; i < 15; ++i) {
		assert(queue_position_to_order(&queue, i) >= 5);
	}

	/* priority=20 for one of the 4 priority=10 items */

	queue_set_priority_range(&queue, 3, 4, 20, -1);
	check_descending_priority(&queue, 0);

	assert(queue_position_to_order(&queue, 3) == 1);
	assert(queue_position_to_order(&queue, 15) == 0);

	for (unsigned i = 0; i < 3; ++i) {
		assert(queue_position_to_order(&queue, i) >= 5);
	}

	for (unsigned i = 4; i < 8; ++i) {
		assert(queue_position_to_order(&queue, i) >= 2 &&
		       queue_position_to_order(&queue, i) < 6);
	}

	for (unsigned i = 8; i < 15; ++i) {
		assert(queue_position_to_order(&queue, i) >= 6);
	}

	/* priority=20 for another one of the 4 priority=10 items;
	   pass "after_order" (with priority=10) and see if it's moved
	   after that one */

	unsigned current_order = 4;
	unsigned current_position =
		queue_order_to_position(&queue, current_order);

	unsigned a_order = 3;
	unsigned a_position = queue_order_to_position(&queue, a_order);
	assert(queue.items[a_position].priority == 10);
	queue_set_priority(&queue, a_position, 20, current_order);

	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	a_order = queue_position_to_order(&queue, a_position);
	assert(a_order == 4);

	check_descending_priority(&queue, current_order + 1);

	/* priority=70 for one of the last items; must be inserted
	   right after the current song, before the priority=20 one we
	   just created */

	unsigned b_order = 10;
	unsigned b_position = queue_order_to_position(&queue, b_order);
	assert(queue.items[b_position].priority == 0);
	queue_set_priority(&queue, b_position, 70, current_order);

	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	b_order = queue_position_to_order(&queue, b_position);
	assert(b_order == 4);

	check_descending_priority(&queue, current_order + 1);

	/* priority=60 for the old prio50 item; must not be moved,
	   because it's before the current song, and it's status
	   hasn't changed (it was already higher before) */

	unsigned c_order = 0;
	unsigned c_position = queue_order_to_position(&queue, c_order);
	assert(queue.items[c_position].priority == 50);
	queue_set_priority(&queue, c_position, 60, current_order);

	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	c_order = queue_position_to_order(&queue, c_position);
	assert(c_order == 0);

	/* move the prio=20 item back */

	a_order = queue_position_to_order(&queue, a_position);
	assert(a_order == 5);
	assert(queue.items[a_position].priority == 20);
	queue_set_priority(&queue, a_position, 5, current_order);


	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	a_order = queue_position_to_order(&queue, a_position);
	assert(a_order == 6);
}