contrib: Do not pass debug/optim flags to meson
[vlc.git] / src / playlist / control.c
1 /*****************************************************************************
2  * playlist/control.c
3  *****************************************************************************
4  * Copyright (C) 2018 VLC authors and VideoLAN
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include "control.h"
26
27 #include "item.h"
28 #include "notify.h"
29 #include "playlist.h"
30 #include "player.h"
31
32 static void
33 vlc_playlist_PlaybackOrderChanged(vlc_playlist_t *playlist)
34 {
35     if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
36     {
37         /* randomizer is expected to be empty at this point */
38         assert(randomizer_Count(&playlist->randomizer) == 0);
39         randomizer_Add(&playlist->randomizer, playlist->items.data,
40                        playlist->items.size);
41
42         bool loop = playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL;
43         randomizer_SetLoop(&playlist->randomizer, loop);
44     }
45     else
46         /* we don't use the randomizer anymore */
47         randomizer_Clear(&playlist->randomizer);
48
49     struct vlc_playlist_state state;
50     vlc_playlist_state_Save(playlist, &state);
51
52     playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
53     playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
54
55     vlc_playlist_Notify(playlist, on_playback_order_changed, playlist->order);
56     vlc_playlist_state_NotifyChanges(playlist, &state);
57
58     char const *state_text = NULL;
59     switch (playlist->order)
60     {
61         case VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL:
62             state_text = N_("Off");
63             break;
64         case VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM:
65             state_text = N_("On");
66             break;
67     }
68     vlc_player_vout_OSDMessage(playlist->player,
69                                _("Random: %s"), vlc_gettext(state_text));
70     /* vlc_player_vout_OSDMessage() does nothing in tests */
71     VLC_UNUSED(state_text);
72 }
73
74 static void
75 vlc_playlist_PlaybackRepeatChanged(vlc_playlist_t *playlist)
76 {
77     if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
78     {
79         bool loop = playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL;
80         randomizer_SetLoop(&playlist->randomizer, loop);
81     }
82
83     struct vlc_playlist_state state;
84     vlc_playlist_state_Save(playlist, &state);
85
86     playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
87     playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
88
89     vlc_playlist_Notify(playlist, on_playback_repeat_changed, playlist->repeat);
90     vlc_playlist_state_NotifyChanges(playlist, &state);
91
92     char const *state_text = NULL;
93     switch (playlist->repeat)
94     {
95         case VLC_PLAYLIST_PLAYBACK_REPEAT_NONE:
96             state_text = N_("Off");
97             break;
98         case VLC_PLAYLIST_PLAYBACK_REPEAT_ALL:
99             state_text = N_("All");
100             break;
101         case VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT:
102             state_text = N_("One");
103             break;
104     }
105     vlc_player_vout_OSDMessage(playlist->player,
106                                _("Loop: %s"), vlc_gettext(state_text));
107     /* vlc_player_vout_OSDMessage() does nothing in tests */
108     VLC_UNUSED(state_text);
109 }
110
111 enum vlc_playlist_playback_repeat
112 vlc_playlist_GetPlaybackRepeat(vlc_playlist_t *playlist)
113 {
114     vlc_playlist_AssertLocked(playlist);
115     return playlist->repeat;
116 }
117
118 enum vlc_playlist_playback_order
119 vlc_playlist_GetPlaybackOrder(vlc_playlist_t *playlist)
120 {
121     vlc_playlist_AssertLocked(playlist);
122     return playlist->order;
123 }
124
125 void
126 vlc_playlist_SetPlaybackRepeat(vlc_playlist_t *playlist,
127                                enum vlc_playlist_playback_repeat repeat)
128 {
129     vlc_playlist_AssertLocked(playlist);
130
131     if (playlist->repeat == repeat)
132         return;
133
134     playlist->repeat = repeat;
135     vlc_playlist_PlaybackRepeatChanged(playlist);
136 }
137
138 void
139 vlc_playlist_SetPlaybackOrder(vlc_playlist_t *playlist,
140                               enum vlc_playlist_playback_order order)
141 {
142     vlc_playlist_AssertLocked(playlist);
143
144     if (playlist->order == order)
145         return;
146
147     playlist->order = order;
148     vlc_playlist_PlaybackOrderChanged(playlist);
149 }
150
151 int
152 vlc_playlist_SetCurrentMedia(vlc_playlist_t *playlist, ssize_t index)
153 {
154     vlc_playlist_AssertLocked(playlist);
155
156     input_item_t *media = index != -1
157                         ? playlist->items.data[index]->media
158                         : NULL;
159     return vlc_player_SetCurrentMedia(playlist->player, media);
160 }
161
162 static inline bool
163 vlc_playlist_NormalOrderHasPrev(vlc_playlist_t *playlist)
164 {
165     if (playlist->current == -1)
166         return false;
167
168     if (playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL)
169         return playlist->items.size > 0;
170
171     return playlist->current > 0;
172 }
173
174 static inline size_t
175 vlc_playlist_NormalOrderGetPrevIndex(vlc_playlist_t *playlist)
176 {
177     switch (playlist->repeat)
178     {
179         case VLC_PLAYLIST_PLAYBACK_REPEAT_NONE:
180         case VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT:
181             return playlist->current - 1;
182         case VLC_PLAYLIST_PLAYBACK_REPEAT_ALL:
183             if (playlist->current == 0)
184                 return playlist->items.size - 1;
185             return playlist->current - 1;
186         default:
187             vlc_assert_unreachable();
188     }
189 }
190
191 static inline bool
192 vlc_playlist_NormalOrderHasNext(vlc_playlist_t *playlist)
193 {
194     if (playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL)
195         return playlist->items.size > 0;
196
197     /* also works if current == -1 or playlist->items.size == 0 */
198     return playlist->current < (ssize_t) playlist->items.size - 1;
199 }
200
201 static inline size_t
202 vlc_playlist_NormalOrderGetNextIndex(vlc_playlist_t *playlist)
203 {
204     switch (playlist->repeat)
205     {
206         case VLC_PLAYLIST_PLAYBACK_REPEAT_NONE:
207         case VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT:
208             if (playlist->current >= (ssize_t) playlist->items.size - 1)
209                 return -1;
210             return playlist->current + 1;
211         case VLC_PLAYLIST_PLAYBACK_REPEAT_ALL:
212                 if (playlist->items.size == 0)
213                     return -1;
214             return (playlist->current + 1) % playlist->items.size;
215         default:
216             vlc_assert_unreachable();
217     }
218 }
219
220 static inline bool
221 vlc_playlist_RandomOrderHasPrev(vlc_playlist_t *playlist)
222 {
223     return randomizer_HasPrev(&playlist->randomizer);
224 }
225
226 static inline size_t
227 vlc_playlist_RandomOrderGetPrevIndex(vlc_playlist_t *playlist)
228 {
229     vlc_playlist_item_t *prev = randomizer_PeekPrev(&playlist->randomizer);
230     assert(prev);
231     ssize_t index = vlc_playlist_IndexOf(playlist, prev);
232     assert(index != -1);
233     return (size_t) index;
234 }
235
236 static inline bool
237 vlc_playlist_RandomOrderHasNext(vlc_playlist_t *playlist)
238 {
239     if (playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL)
240         return playlist->items.size > 0;
241     return randomizer_HasNext(&playlist->randomizer);
242 }
243
244 static inline size_t
245 vlc_playlist_RandomOrderGetNextIndex(vlc_playlist_t *playlist)
246 {
247     vlc_playlist_item_t *next = randomizer_PeekNext(&playlist->randomizer);
248     assert(next);
249     ssize_t index = vlc_playlist_IndexOf(playlist, next);
250     assert(index != -1);
251     return (size_t) index;
252 }
253
254 static size_t
255 vlc_playlist_GetPrevIndex(vlc_playlist_t *playlist)
256 {
257     vlc_playlist_AssertLocked(playlist);
258     switch (playlist->order)
259     {
260         case VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL:
261             return vlc_playlist_NormalOrderGetPrevIndex(playlist);
262         case VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM:
263             return vlc_playlist_RandomOrderGetPrevIndex(playlist);
264         default:
265             vlc_assert_unreachable();
266     }
267 }
268
269 static size_t
270 vlc_playlist_GetNextIndex(vlc_playlist_t *playlist)
271 {
272     vlc_playlist_AssertLocked(playlist);
273     switch (playlist->order)
274     {
275         case VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL:
276             return vlc_playlist_NormalOrderGetNextIndex(playlist);
277         case VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM:
278             return vlc_playlist_RandomOrderGetNextIndex(playlist);
279         default:
280             vlc_assert_unreachable();
281     }
282 }
283
284 bool
285 vlc_playlist_ComputeHasPrev(vlc_playlist_t *playlist)
286 {
287     vlc_playlist_AssertLocked(playlist);
288     switch (playlist->order)
289     {
290         case VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL:
291             return vlc_playlist_NormalOrderHasPrev(playlist);
292         case VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM:
293             return vlc_playlist_RandomOrderHasPrev(playlist);
294         default:
295             vlc_assert_unreachable();
296     }
297 }
298
299 bool
300 vlc_playlist_ComputeHasNext(vlc_playlist_t *playlist)
301 {
302     vlc_playlist_AssertLocked(playlist);
303     switch (playlist->order)
304     {
305         case VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL:
306             return vlc_playlist_NormalOrderHasNext(playlist);
307         case VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM:
308             return vlc_playlist_RandomOrderHasNext(playlist);
309         default:
310             vlc_assert_unreachable();
311     }
312 }
313
314 ssize_t
315 vlc_playlist_GetCurrentIndex(vlc_playlist_t *playlist)
316 {
317     vlc_playlist_AssertLocked(playlist);
318     return playlist->current;
319 }
320
321 static void
322 vlc_playlist_SetCurrentIndex(vlc_playlist_t *playlist, ssize_t index)
323 {
324     struct vlc_playlist_state state;
325     vlc_playlist_state_Save(playlist, &state);
326
327     playlist->current = index;
328     playlist->has_prev = vlc_playlist_ComputeHasPrev(playlist);
329     playlist->has_next = vlc_playlist_ComputeHasNext(playlist);
330
331     vlc_playlist_state_NotifyChanges(playlist, &state);
332 }
333
334 bool
335 vlc_playlist_HasPrev(vlc_playlist_t *playlist)
336 {
337     vlc_playlist_AssertLocked(playlist);
338     return playlist->has_prev;
339 }
340
341 bool
342 vlc_playlist_HasNext(vlc_playlist_t *playlist)
343 {
344     vlc_playlist_AssertLocked(playlist);
345     return playlist->has_next;
346 }
347
348 int
349 vlc_playlist_Prev(vlc_playlist_t *playlist)
350 {
351     vlc_playlist_AssertLocked(playlist);
352
353     if (!vlc_playlist_ComputeHasPrev(playlist))
354         return VLC_EGENERIC;
355
356     ssize_t index = vlc_playlist_GetPrevIndex(playlist);
357     assert(index != -1);
358
359     int ret = vlc_playlist_SetCurrentMedia(playlist, index);
360     if (ret != VLC_SUCCESS)
361         return ret;
362
363     if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
364     {
365         /* mark the item as selected in the randomizer */
366         vlc_playlist_item_t *selected = randomizer_Prev(&playlist->randomizer);
367         assert(selected == playlist->items.data[index]);
368         VLC_UNUSED(selected);
369     }
370
371     vlc_playlist_SetCurrentIndex(playlist, index);
372     vlc_player_vout_OSDMessage(playlist->player, _("Previous"));
373     return VLC_SUCCESS;
374 }
375
376 int
377 vlc_playlist_Next(vlc_playlist_t *playlist)
378 {
379     vlc_playlist_AssertLocked(playlist);
380
381     if (!vlc_playlist_ComputeHasNext(playlist))
382         return VLC_EGENERIC;
383
384     ssize_t index = vlc_playlist_GetNextIndex(playlist);
385     assert(index != -1);
386
387     int ret = vlc_playlist_SetCurrentMedia(playlist, index);
388     if (ret != VLC_SUCCESS)
389         return ret;
390
391     if (playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
392     {
393         /* mark the item as selected in the randomizer */
394         vlc_playlist_item_t *selected = randomizer_Next(&playlist->randomizer);
395         assert(selected == playlist->items.data[index]);
396         VLC_UNUSED(selected);
397     }
398
399     vlc_playlist_SetCurrentIndex(playlist, index);
400     vlc_player_vout_OSDMessage(playlist->player, _("Next"));
401     return VLC_SUCCESS;
402 }
403
404 int
405 vlc_playlist_GoTo(vlc_playlist_t *playlist, ssize_t index)
406 {
407     vlc_playlist_AssertLocked(playlist);
408     assert(index == -1 || (size_t) index < playlist->items.size);
409
410     int ret = vlc_playlist_SetCurrentMedia(playlist, index);
411     if (ret != VLC_SUCCESS)
412         return ret;
413
414     if (index != -1 && playlist->order == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM)
415     {
416         vlc_playlist_item_t *item = playlist->items.data[index];
417         randomizer_Select(&playlist->randomizer, item);
418     }
419
420     vlc_playlist_SetCurrentIndex(playlist, index);
421     return VLC_SUCCESS;
422 }
423
424 static ssize_t
425 vlc_playlist_GetNextMediaIndex(vlc_playlist_t *playlist)
426 {
427     vlc_playlist_AssertLocked(playlist);
428     if (playlist->repeat == VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT)
429         return playlist->current;
430     if (!vlc_playlist_ComputeHasNext(playlist))
431         return -1;
432     return vlc_playlist_GetNextIndex(playlist);
433 }
434
435 input_item_t *
436 vlc_playlist_GetNextMedia(vlc_playlist_t *playlist)
437 {
438     /* the playlist and the player share the lock */
439     vlc_playlist_AssertLocked(playlist);
440
441     ssize_t index = vlc_playlist_GetNextMediaIndex(playlist);
442     if (index == -1)
443         return NULL;
444
445     input_item_t *media = playlist->items.data[index]->media;
446     input_item_Hold(media);
447     return media;
448 }