media_list_player.c: Fix previous commit.
[vlc.git] / src / control / media_list_player.c
1 /*****************************************************************************
2  * media_list_player.c: libvlc new API media_list player functions
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 #include "libvlc_internal.h"
24 #include <vlc/libvlc.h>
25
26 /*
27  * Private functions
28  */
29
30 /**************************************************************************
31  *       get_next_index (private)
32  *
33  * Simple next item fetcher.
34  **************************************************************************/
35 static int get_next_index( libvlc_media_list_player_t * p_mlp )
36 {
37         /* We are entered with libvlc_media_list_lock( p_mlp->p_list ) */
38         
39         int next = p_mlp->i_current_playing_index + 1;
40
41         if( next >= libvlc_media_list_count( p_mlp->p_mlist, NULL ) )
42                 return -1; /* no more to play */
43
44         return next;
45 }
46
47 /**************************************************************************
48  *       media_instance_reached_end (private) (Event Callback)
49  **************************************************************************/
50 static void 
51 media_instance_reached_end( const libvlc_event_t * p_event,
52                             void * p_user_data )
53 {
54         libvlc_media_list_player_t * p_mlp = p_user_data;
55         libvlc_media_instance_t * p_mi = p_event->p_obj;
56     libvlc_media_descriptor_t *p_md, * p_current_md;
57     p_md = libvlc_media_instance_get_media_descriptor( p_mi, NULL );
58     /* XXX: need if p_mlp->p_current_playing_index is beyond */
59     p_current_md = libvlc_media_list_item_at_index(
60                         p_mlp->p_mlist,
61                         p_mlp->i_current_playing_index,
62                         NULL );
63         if( p_md != p_current_md )
64         {
65                 msg_Warn( p_mlp->p_libvlc_instance->p_libvlc_int,
66                                   "We are not sync-ed with the media instance" );
67         libvlc_media_descriptor_release( p_md );
68         libvlc_media_descriptor_release( p_current_md );
69                 return;
70         }
71     libvlc_media_descriptor_release( p_md );
72     libvlc_media_descriptor_release( p_current_md );
73         libvlc_media_list_player_next( p_mlp, NULL );
74 }
75
76 /**************************************************************************
77  *       playlist_item_deleted (private) (Event Callback)
78  **************************************************************************/
79 static void 
80 mlist_item_deleted( const libvlc_event_t * p_event, void * p_user_data )
81 {
82     libvlc_media_descriptor_t * p_current_md;    
83         libvlc_media_list_player_t * p_mlp = p_user_data;
84         libvlc_media_list_t * p_emitting_mlist = p_event->p_obj;
85     /* XXX: need if p_mlp->p_current_playing_index is beyond */
86     p_current_md = libvlc_media_list_item_at_index(
87                         p_mlp->p_mlist,
88                         p_mlp->i_current_playing_index,
89                         NULL );
90
91         if( p_event->u.media_list_item_deleted.item == p_current_md &&
92             p_emitting_mlist == p_mlp->p_mlist )
93         {
94                 /* We are playing this item, we choose to stop */
95                 libvlc_media_list_player_stop( p_mlp, NULL );
96         }
97 }
98
99 /**************************************************************************
100  *       install_playlist_observer (private)
101  **************************************************************************/
102 static void
103 install_playlist_observer( libvlc_media_list_player_t * p_mlp )
104 {
105         libvlc_event_attach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
106             libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
107 }
108
109 /**************************************************************************
110  *       uninstall_playlist_observer (private)
111  **************************************************************************/
112 static void
113 uninstall_playlist_observer( libvlc_media_list_player_t * p_mlp )
114 {
115     libvlc_event_detach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
116             libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
117 }
118
119 /**************************************************************************
120  *       install_media_instance_observer (private)
121  **************************************************************************/
122 static void
123 install_media_instance_observer( libvlc_media_list_player_t * p_mlp )
124 {
125         libvlc_event_attach( libvlc_media_instance_event_manager( p_mlp->p_mi, NULL ),
126                          libvlc_MediaInstanceReachedEnd,
127                                               media_instance_reached_end, p_mlp, NULL );
128 }
129
130
131 /**************************************************************************
132  *       uninstall_media_instance_observer (private)
133  **************************************************************************/
134 static void
135 uninstall_media_instance_observer( libvlc_media_list_player_t * p_mlp )
136 {
137         libvlc_event_detach( libvlc_media_instance_event_manager( p_mlp->p_mi, NULL ),
138                          libvlc_MediaInstanceReachedEnd,
139                                              media_instance_reached_end, p_mlp, NULL );
140 }
141
142 /**************************************************************************
143  *       Stop (Public)
144  **************************************************************************/
145 static vlc_bool_t
146 libvlc_media_list_player_is_playing( libvlc_media_list_player_t * p_mlp,
147                                     libvlc_exception_t * p_e )
148 {
149     libvlc_exception_raise( p_e, "Unimplemented" );
150     return 0;
151 }
152
153 /**************************************************************************
154  *       Next (private)
155  *
156  * Playlist lock should be held
157  **************************************************************************/
158 static void
159 media_list_player_set_next( libvlc_media_list_player_t * p_mlp, int index,
160                             libvlc_exception_t * p_e )
161 {
162         libvlc_media_descriptor_t * p_md;
163         
164         p_md = libvlc_media_list_item_at_index( p_mlp->p_mlist, index, p_e );
165         if( !p_md )
166         {
167                 libvlc_media_list_unlock( p_mlp->p_mlist );             
168                 if( !libvlc_exception_raised( p_e ) )
169                         libvlc_exception_raise( p_e, "Can't obtain a media" );
170                 return;
171         }
172
173     vlc_mutex_lock( &p_mlp->object_lock );
174         
175     p_mlp->i_current_playing_index = index;
176
177         /* We are not interested in getting media_descriptor stop event now */
178         uninstall_media_instance_observer( p_mlp );
179     libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_md, NULL );
180 //      wait_playing_state(); /* If we want to be synchronous */
181         install_media_instance_observer( p_mlp );
182
183     vlc_mutex_unlock( &p_mlp->object_lock );
184
185         libvlc_media_list_unlock( p_mlp->p_mlist );             
186         
187         libvlc_media_descriptor_release( p_md ); /* for libvlc_media_list_item_at_index */
188 }
189
190 /*
191  * Public libvlc functions
192  */
193
194 /**************************************************************************
195  *         new (Public)
196  **************************************************************************/
197 libvlc_media_list_player_t *
198 libvlc_media_list_player_new( libvlc_instance_t * p_instance,
199                               libvlc_exception_t * p_e )
200 {
201     (void)p_e;
202     libvlc_media_list_player_t * p_mlp;
203     p_mlp = malloc(sizeof(libvlc_media_list_player_t));
204         p_mlp->i_current_playing_index = -1;
205     p_mlp->p_mi = NULL;
206     p_mlp->p_mlist = NULL;
207     vlc_mutex_init( p_instance->p_libvlc_int, &p_mlp->object_lock );
208     p_mlp->p_event_manager = libvlc_event_manager_new( p_mlp,
209                                                        p_instance,
210                                                        p_e );
211     libvlc_event_manager_register_event_type( p_mlp->p_event_manager,
212             libvlc_MediaListPlayerNextItemSet, p_e );
213     libvlc_event_manager_register_event_type( p_mlp->p_event_manager,
214             libvlc_MediaListPlayerNextItemSet, p_e );
215
216         return p_mlp;
217 }
218
219 /**************************************************************************
220  *         release (Public)
221  **************************************************************************/
222 void libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp )
223 {
224     libvlc_event_manager_release( p_mlp->p_event_manager );
225     free(p_mlp);
226 }
227
228 /**************************************************************************
229  *        set_media_instance (Public)
230  **************************************************************************/
231 void libvlc_media_list_player_set_media_instance(
232                                      libvlc_media_list_player_t * p_mlp,
233                                      libvlc_media_instance_t * p_mi,
234                                      libvlc_exception_t * p_e )
235 {
236     vlc_mutex_lock( &p_mlp->object_lock );
237
238         if( p_mlp->p_mi )
239         {
240                 uninstall_media_instance_observer( p_mlp );
241                 libvlc_media_instance_release( p_mlp->p_mi );
242         }
243         libvlc_media_instance_retain( p_mi );
244         p_mlp->p_mi = p_mi;
245
246     install_media_instance_observer( p_mlp );
247
248     vlc_mutex_unlock( &p_mlp->object_lock );
249 }
250
251 /**************************************************************************
252  *       set_media_list (Public)
253  **************************************************************************/
254 void libvlc_media_list_player_set_media_list(
255                                      libvlc_media_list_player_t * p_mlp,
256                                      libvlc_media_list_t * p_mlist,
257                                      libvlc_exception_t * p_e )
258 {
259     vlc_mutex_lock( &p_mlp->object_lock );
260     
261         if( libvlc_media_list_player_is_playing( p_mlp, p_e ) )
262                 libvlc_media_list_player_stop( p_mlp, p_e );
263
264         if( p_mlp->p_mlist )
265         {
266                 uninstall_playlist_observer( p_mlp );
267                 libvlc_media_list_release( p_mlp->p_mlist );
268         }
269         libvlc_media_list_retain( p_mlist );
270         p_mlp->p_mlist = p_mlist;
271     
272         install_playlist_observer( p_mlp );
273
274     vlc_mutex_unlock( &p_mlp->object_lock );
275 }
276
277 /**************************************************************************
278  *        Play (Public)
279  **************************************************************************/
280 void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp,
281                                   libvlc_exception_t * p_e )
282 {
283     if( p_mlp->i_current_playing_index < 0 )
284     {
285         libvlc_media_list_player_next( p_mlp, p_e );
286         return; /* Will set to play */
287     }
288
289         libvlc_media_instance_play( p_mlp->p_mi, p_e );
290 }
291
292 /**************************************************************************
293  *        Play item at index (Public)
294  *
295  * Playlist lock should be help
296  **************************************************************************/
297 void libvlc_media_list_player_play_item_at_index(
298                         libvlc_media_list_player_t * p_mlp,
299                         int i_index,
300                         libvlc_exception_t * p_e )
301 {
302         media_list_player_set_next( p_mlp, i_index, p_e );
303
304         if( libvlc_exception_raised( p_e ) )
305                 return;
306
307     /* Send the next item event */
308     libvlc_event_t event;
309     event.type = libvlc_MediaListPlayerNextItemSet;
310     libvlc_event_send( p_mlp->p_event_manager, &event );
311
312         libvlc_media_instance_play( p_mlp->p_mi, p_e );
313 }
314
315
316 /**************************************************************************
317  *       Stop (Public)
318  **************************************************************************/
319 void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
320                                     libvlc_exception_t * p_e )
321 {
322         libvlc_media_instance_stop( p_mlp->p_mi, p_e );
323
324     vlc_mutex_lock( &p_mlp->object_lock );
325         p_mlp->i_current_playing_index = -1;
326     vlc_mutex_unlock( &p_mlp->object_lock );
327 }
328
329 /**************************************************************************
330  *       Next (Public)
331  **************************************************************************/
332 void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
333                                     libvlc_exception_t * p_e )
334 {       
335         int index;
336         
337         libvlc_media_list_lock( p_mlp->p_mlist );
338
339         index = get_next_index( p_mlp );
340
341         if( index < 0 )
342         {
343                 libvlc_media_list_unlock( p_mlp->p_mlist );
344                 libvlc_exception_raise( p_e, "No more element to play" );
345                 libvlc_media_list_player_stop( p_mlp, p_e );
346                 return;
347         }
348
349         media_list_player_set_next( p_mlp, index, p_e );
350         
351     libvlc_media_instance_play( p_mlp->p_mi, p_e );
352
353     libvlc_media_list_unlock( p_mlp->p_mlist );
354
355     /* Send the next item event */
356     libvlc_event_t event;
357     event.type = libvlc_MediaListPlayerNextItemSet;
358     libvlc_event_send( p_mlp->p_event_manager, &event);
359 }
360