]> git.sesse.net Git - vlc/blob - src/playlist/thread.c
5efe4231ea7f2c85c15bba53a04288777b51cc64
[vlc] / src / playlist / thread.c
1 /*****************************************************************************
2  * playlist.c : Playlist management functions
3  *****************************************************************************
4  * Copyright (C) 1999-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          ClĂ©ment Stenac <zorglub@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 #include <vlc/vlc.h>
25 #include <vlc_es.h>
26 #include <vlc_input.h>
27 #include "vlc_playlist.h"
28 #include "vlc_interaction.h"
29 #include "playlist_internal.h"
30
31 /*****************************************************************************
32  * Local prototypes
33  *****************************************************************************/
34 static void RunControlThread ( playlist_t * );
35 static void RunPreparse( playlist_preparse_t * );
36 static void RunSecondaryPreparse( playlist_secondary_preparse_t * );
37
38 static playlist_t * CreatePlaylist( vlc_object_t *p_parent );
39 static void HandlePlaylist( playlist_t * );
40 static void EndPlaylist( playlist_t * );
41 static void DestroyPlaylist( playlist_t * );
42
43 static void HandleStats( playlist_t *, int );
44
45 static void HandleInteraction( playlist_t * );
46 static void DestroyInteraction( playlist_t * );
47
48 /*****************************************************************************
49  * Main functions for the global thread
50  *****************************************************************************/
51
52 /**
53  * Create the main playlist thread
54  * Additionally to the playlist, this thread controls :
55  *    - Interaction
56  *    - Statistics
57  *    - VLM
58  * \param p_parent
59  * \return an object with a started thread
60  */
61 void __playlist_ThreadCreate( vlc_object_t *p_parent )
62 {
63     playlist_t *p_playlist;
64     p_playlist = CreatePlaylist( p_parent );
65
66     if( !p_playlist ) return;
67
68     // Stats
69     p_playlist->p_stats = (global_stats_t *)malloc( sizeof( global_stats_t ) );
70     vlc_mutex_init( p_playlist, &p_playlist->p_stats->lock );
71
72     // Interaction
73     p_playlist->p_interaction = NULL;
74
75     // Preparse
76     p_playlist->p_preparse = vlc_object_create( p_playlist,
77                                   sizeof( playlist_preparse_t ) );
78     if( !p_playlist->p_preparse )
79     {
80         msg_Err( p_playlist, "unable to create preparser" );
81         vlc_object_destroy( p_playlist );
82         return;
83     }
84     p_playlist->p_preparse->i_waiting = 0;
85     p_playlist->p_preparse->pp_waiting = NULL;
86
87     vlc_object_attach( p_playlist->p_preparse, p_playlist );
88     if( vlc_thread_create( p_playlist->p_preparse, "preparser",
89                            RunPreparse, VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
90     {
91         msg_Err( p_playlist, "cannot spawn preparse thread" );
92         vlc_object_detach( p_playlist->p_preparse );
93         vlc_object_destroy( p_playlist->p_preparse );
94         return;
95     }
96
97     // Secondary Preparse
98     p_playlist->p_secondary_preparse = vlc_object_create( p_playlist,
99                               sizeof( playlist_secondary_preparse_t ) );
100     if( !p_playlist->p_secondary_preparse )
101     {
102         msg_Err( p_playlist, "unable to create secondary preparser" );
103         vlc_object_destroy( p_playlist );
104         return;
105     }
106     p_playlist->p_secondary_preparse->i_waiting = 0;
107     p_playlist->p_secondary_preparse->p_waiting = NULL;
108
109     vlc_object_attach( p_playlist->p_secondary_preparse, p_playlist );
110     if( vlc_thread_create( p_playlist->p_secondary_preparse,
111                            "secondary preparser",
112                            RunSecondaryPreparse,
113                            VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
114     {
115         msg_Err( p_playlist, "cannot spawn secondary preparse thread" );
116         vlc_object_detach( p_playlist->p_secondary_preparse );
117         vlc_object_destroy( p_playlist->p_secondary_preparse );
118         return;
119     }
120
121     // Start the thread
122     if( vlc_thread_create( p_playlist, "playlist", RunControlThread,
123                            VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
124     {
125         msg_Err( p_playlist, "cannot spawn playlist thread" );
126         vlc_object_destroy( p_playlist );
127         return;
128     }
129
130     /* The object has been initialized, now attach it */
131     vlc_object_attach( p_playlist, p_parent );
132
133     return;
134 }
135
136 /**
137  * Destroy the playlist global thread.
138  *
139  * Deinits all things controlled by the playlist global thread
140  * \param p_playlist the playlist thread to destroy
141  * \return VLC_SUCCESS or an error
142  */
143 int playlist_ThreadDestroy( playlist_t * p_playlist )
144 {
145     p_playlist->b_die = 1;
146
147     DestroyInteraction( p_playlist );
148     DestroyPlaylist( p_playlist );
149
150     return VLC_SUCCESS;
151 }
152
153 /**
154  * Run the main control thread itself
155  */
156 static void RunControlThread ( playlist_t *p_playlist )
157 {
158    int i_loops = 0;
159
160    /* Tell above that we're ready */
161    vlc_thread_ready( p_playlist );
162
163     while( !p_playlist->b_die )
164     {
165         i_loops++;
166
167         HandleInteraction( p_playlist );
168         HandleStats( p_playlist, i_loops );
169         HandlePlaylist( p_playlist );
170
171         /* 100 ms is an acceptable delay for playlist operations */
172         msleep( INTF_IDLE_SLEEP*2 );
173     }
174
175     EndPlaylist( p_playlist );
176 }
177
178
179 /*****************************************************************************
180  * Playlist-specific functions
181  *****************************************************************************/
182 static playlist_t * CreatePlaylist( vlc_object_t *p_parent )
183 {
184     return playlist_Create( p_parent );
185 }
186
187 static void DestroyPlaylist( playlist_t *p_playlist )
188 {
189     playlist_Destroy( p_playlist );
190 }
191
192 static void HandlePlaylist( playlist_t *p_playlist )
193 {
194     playlist_MainLoop( p_playlist );
195 }
196
197 static void EndPlaylist( playlist_t *p_playlist )
198 {
199     playlist_LastLoop( p_playlist );
200 }
201
202 /*****************************************************************************
203  * Preparse-specific functions
204  *****************************************************************************/
205 static void RunPreparse ( playlist_preparse_t *p_obj )
206 {
207     playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
208     /* Tell above that we're ready */
209     vlc_thread_ready( p_obj );
210
211     while( !p_playlist->b_die )
212     {
213         playlist_PreparseLoop( p_obj );
214         if( p_obj->i_waiting == 0 )
215         {
216             msleep( INTF_IDLE_SLEEP );
217         }
218     }
219 }
220
221 static void RunSecondaryPreparse( playlist_secondary_preparse_t *p_obj )
222 {
223     playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
224     /* Tell above that we're ready */
225     vlc_thread_ready( p_obj );
226
227     while( !p_playlist->b_die )
228     {
229         playlist_SecondaryPreparseLoop( p_obj );
230         if( p_obj->i_waiting == 0 )
231         {
232             msleep( INTF_IDLE_SLEEP );
233         }
234     }
235 }
236
237 /*****************************************************************************
238  * Interaction functions
239  *****************************************************************************/
240 static void DestroyInteraction( playlist_t *p_playlist )
241 {
242     if( p_playlist->p_interaction )
243     {
244         intf_InteractionDestroy( p_playlist->p_interaction );
245         fprintf( stderr, "NOW NULL ****\n" );
246         p_playlist->p_interaction = NULL;
247     }
248 }
249
250 static void HandleInteraction( playlist_t *p_playlist )
251 {
252     if( p_playlist->p_interaction )
253     {
254         stats_TimerStart( p_playlist, "Interaction thread",
255                           STATS_TIMER_INTERACTION );
256         intf_InteractionManage( p_playlist );
257         stats_TimerStop( p_playlist, STATS_TIMER_INTERACTION );
258     }
259 }
260
261
262 /*****************************************************************************
263  * Stats functions
264  *****************************************************************************/
265 static void HandleStats( playlist_t *p_playlist, int i_loops )
266 {
267     if( i_loops % 5 == 0 && p_playlist->p_stats )
268     {
269         stats_ComputeGlobalStats( p_playlist, p_playlist->p_stats );
270         if( p_playlist->p_input )
271         {
272             stats_ComputeInputStats( p_playlist->p_input,
273                                 p_playlist->p_input->input.p_item->p_stats );
274         }
275     }
276 }