libOggFLAC.m4: Remove libOggFLAC.m4 as it's buggy.
[mpd-mk.git] / src / playlist.c
blobe708ce00f88ab1bc5b98c655dfa59078f9f47378
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "playlist_internal.h"
22 #include "playlist_save.h"
23 #include "player_control.h"
24 #include "command.h"
25 #include "tag.h"
26 #include "song.h"
27 #include "conf.h"
28 #include "stored_playlist.h"
29 #include "idle.h"
31 #include <glib.h>
33 #include <assert.h>
35 #undef G_LOG_DOMAIN
36 #define G_LOG_DOMAIN "playlist"
38 void
39 playlist_increment_version_all(struct playlist *playlist)
41 queue_modify_all(&playlist->queue);
42 idle_add(IDLE_PLAYLIST);
45 void
46 playlist_tag_changed(struct playlist *playlist)
48 if (!playlist->playing)
49 return;
51 assert(playlist->current >= 0);
53 queue_modify(&playlist->queue, playlist->current);
54 idle_add(IDLE_PLAYLIST);
57 void
58 playlist_init(struct playlist *playlist)
60 queue_init(&playlist->queue,
61 config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
62 DEFAULT_PLAYLIST_MAX_LENGTH));
64 playlist->queued = -1;
65 playlist->current = -1;
68 void
69 playlist_finish(struct playlist *playlist)
71 queue_finish(&playlist->queue);
74 /**
75 * Queue a song, addressed by its order number.
77 static void
78 playlist_queue_song_order(struct playlist *playlist, unsigned order)
80 struct song *song;
81 char *uri;
83 assert(queue_valid_order(&playlist->queue, order));
85 playlist->queued = order;
87 song = queue_get_order(&playlist->queue, order);
88 uri = song_get_uri(song);
89 g_debug("queue song %i:\"%s\"", playlist->queued, uri);
90 g_free(uri);
92 pc_enqueue_song(song);
95 /**
96 * Check if the player thread has already started playing the "queued"
97 * song.
99 static void
100 playlist_sync_with_queue(struct playlist *playlist)
102 if (pc.next_song == NULL && playlist->queued != -1) {
103 /* queued song has started: copy queued to current,
104 and notify the clients */
106 int current = playlist->current;
107 playlist->current = playlist->queued;
108 playlist->queued = -1;
110 if(playlist->queue.consume)
111 playlist_delete(playlist, queue_order_to_position(&playlist->queue, current));
113 idle_add(IDLE_PLAYER);
117 const struct song *
118 playlist_get_queued_song(struct playlist *playlist)
120 if (!playlist->playing || playlist->queued < 0)
121 return NULL;
123 return queue_get_order(&playlist->queue, playlist->queued);
126 void
127 playlist_update_queued_song(struct playlist *playlist, const struct song *prev)
129 int next_order;
130 const struct song *next_song;
132 if (!playlist->playing)
133 return;
135 assert(!queue_is_empty(&playlist->queue));
136 assert((playlist->queued < 0) == (prev == NULL));
138 next_order = playlist->current >= 0
139 ? queue_next_order(&playlist->queue, playlist->current)
140 : 0;
142 if (next_order == 0 && playlist->queue.random &&
143 !playlist->queue.single) {
144 /* shuffle the song order again, so we get a different
145 order each time the playlist is played
146 completely */
147 unsigned current_position =
148 queue_order_to_position(&playlist->queue,
149 playlist->current);
151 queue_shuffle_order(&playlist->queue);
153 /* make sure that the playlist->current still points to
154 the current song, after the song order has been
155 shuffled */
156 playlist->current =
157 queue_position_to_order(&playlist->queue,
158 current_position);
161 if (next_order >= 0)
162 next_song = queue_get_order(&playlist->queue, next_order);
163 else
164 next_song = NULL;
166 if (prev != NULL && next_song != prev) {
167 /* clear the currently queued song */
168 pc_cancel();
169 playlist->queued = -1;
172 if (next_order >= 0) {
173 if (next_song != prev)
174 playlist_queue_song_order(playlist, next_order);
175 else
176 playlist->queued = next_order;
180 void
181 playlist_play_order(struct playlist *playlist, int orderNum)
183 struct song *song;
184 char *uri;
186 playlist->playing = true;
187 playlist->queued = -1;
189 song = queue_get_order(&playlist->queue, orderNum);
191 uri = song_get_uri(song);
192 g_debug("play %i:\"%s\"", orderNum, uri);
193 g_free(uri);
195 pc_play(song);
196 playlist->current = orderNum;
199 static void
200 playlist_resume_playback(struct playlist *playlist);
203 * This is the "PLAYLIST" event handler. It is invoked by the player
204 * thread whenever it requests a new queued song, or when it exits.
206 void
207 playlist_sync(struct playlist *playlist)
209 if (!playlist->playing)
210 /* this event has reached us out of sync: we aren't
211 playing anymore; ignore the event */
212 return;
214 if (pc_get_state() == PLAYER_STATE_STOP)
215 /* the player thread has stopped: check if playback
216 should be restarted with the next song. That can
217 happen if the playlist isn't filling the queue fast
218 enough */
219 playlist_resume_playback(playlist);
220 else {
221 /* check if the player thread has already started
222 playing the queued song */
223 playlist_sync_with_queue(playlist);
225 /* make sure the queued song is always set (if
226 possible) */
227 if (pc.next_song == NULL)
228 playlist_update_queued_song(playlist, NULL);
233 * The player has stopped for some reason. Check the error, and
234 * decide whether to re-start playback
236 static void
237 playlist_resume_playback(struct playlist *playlist)
239 enum player_error error;
241 assert(playlist->playing);
242 assert(pc_get_state() == PLAYER_STATE_STOP);
244 error = pc_get_error();
245 if (error == PLAYER_ERROR_NOERROR)
246 playlist->error_count = 0;
247 else
248 ++playlist->error_count;
250 if ((playlist->stop_on_error && error != PLAYER_ERROR_NOERROR) ||
251 error == PLAYER_ERROR_AUDIO || error == PLAYER_ERROR_SYSTEM ||
252 playlist->error_count >= queue_length(&playlist->queue))
253 /* too many errors, or critical error: stop
254 playback */
255 playlist_stop(playlist);
256 else
257 /* continue playback at the next song */
258 playlist_next(playlist);
261 bool
262 playlist_get_repeat(const struct playlist *playlist)
264 return playlist->queue.repeat;
267 bool
268 playlist_get_random(const struct playlist *playlist)
270 return playlist->queue.random;
273 bool
274 playlist_get_single(const struct playlist *playlist)
276 return playlist->queue.single;
279 bool
280 playlist_get_consume(const struct playlist *playlist)
282 return playlist->queue.consume;
285 void
286 playlist_set_repeat(struct playlist *playlist, bool status)
288 if (status == playlist->queue.repeat)
289 return;
291 playlist->queue.repeat = status;
293 /* if the last song is currently being played, the "next song"
294 might change when repeat mode is toggled */
295 playlist_update_queued_song(playlist,
296 playlist_get_queued_song(playlist));
298 idle_add(IDLE_OPTIONS);
301 static void
302 playlist_order(struct playlist *playlist)
304 if (playlist->current >= 0)
305 /* update playlist.current, order==position now */
306 playlist->current = queue_order_to_position(&playlist->queue,
307 playlist->current);
309 queue_restore_order(&playlist->queue);
312 void
313 playlist_set_single(struct playlist *playlist, bool status)
315 if (status == playlist->queue.single)
316 return;
318 playlist->queue.single = status;
320 /* if the last song is currently being played, the "next song"
321 might change when single mode is toggled */
322 playlist_update_queued_song(playlist,
323 playlist_get_queued_song(playlist));
325 idle_add(IDLE_OPTIONS);
328 void
329 playlist_set_consume(struct playlist *playlist, bool status)
331 if (status == playlist->queue.consume)
332 return;
334 playlist->queue.consume = status;
335 idle_add(IDLE_OPTIONS);
338 void
339 playlist_set_random(struct playlist *playlist, bool status)
341 const struct song *queued;
343 if (status == playlist->queue.random)
344 return;
346 queued = playlist_get_queued_song(playlist);
348 playlist->queue.random = status;
350 if (playlist->queue.random) {
351 /* shuffle the queue order, but preserve
352 playlist->current */
354 int current_position =
355 playlist->playing && playlist->current >= 0
356 ? (int)queue_order_to_position(&playlist->queue,
357 playlist->current)
358 : -1;
360 queue_shuffle_order(&playlist->queue);
362 if (current_position >= 0) {
363 /* make sure the current song is the first in
364 the order list, so the whole rest of the
365 playlist is played after that */
366 unsigned current_order =
367 queue_position_to_order(&playlist->queue,
368 current_position);
369 queue_swap_order(&playlist->queue, 0, current_order);
370 playlist->current = 0;
371 } else
372 playlist->current = -1;
373 } else
374 playlist_order(playlist);
376 playlist_update_queued_song(playlist, queued);
378 idle_add(IDLE_OPTIONS);
382 playlist_get_current_song(const struct playlist *playlist)
384 if (playlist->current >= 0)
385 return queue_order_to_position(&playlist->queue,
386 playlist->current);
388 return -1;
392 playlist_get_next_song(const struct playlist *playlist)
394 if (playlist->current >= 0)
396 if (playlist->queue.single == 1)
398 if (playlist->queue.repeat == 1)
399 return queue_order_to_position(&playlist->queue,
400 playlist->current);
401 else
402 return -1;
404 if (playlist->current + 1 < (int)queue_length(&playlist->queue))
405 return queue_order_to_position(&playlist->queue,
406 playlist->current + 1);
407 else if (playlist->queue.repeat == 1)
408 return queue_order_to_position(&playlist->queue, 0);
411 return -1;
414 unsigned long
415 playlist_get_version(const struct playlist *playlist)
417 return playlist->queue.version;
421 playlist_get_length(const struct playlist *playlist)
423 return queue_length(&playlist->queue);
426 unsigned
427 playlist_get_song_id(const struct playlist *playlist, unsigned song)
429 return queue_position_to_id(&playlist->queue, song);