]> git.sesse.net Git - vlc/blob - src/playlist/thread.c
5bf33e45bd98feb9684cf6754690f7857ba8c283
[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
37 static playlist_t * CreatePlaylist( vlc_object_t *p_parent );
38 static void HandlePlaylist( playlist_t * );
39 static void EndPlaylist( playlist_t * );
40 static void DestroyPlaylist( playlist_t * );
41
42 static void HandleStats( playlist_t *, int );
43
44 static void HandleInteraction( playlist_t * );
45 static void DestroyInteraction( playlist_t * );
46
47 /*****************************************************************************
48  * Main functions for the global thread
49  *****************************************************************************/
50
51 /**
52  * Create the main playlist thread
53  * Additionally to the playlist, this thread controls :
54  *    - Interaction
55  *    - Statistics
56  *    - VLM
57  * \param p_parent
58  * \return an object with a started thread
59  */
60 playlist_t * __playlist_ThreadCreate( vlc_object_t *p_parent )
61 {
62     playlist_t *p_playlist;
63     p_playlist = CreatePlaylist( p_parent );
64
65     if( !p_playlist ) return NULL;
66
67     // Stats
68     p_playlist->p_stats = (global_stats_t *)malloc( sizeof( global_stats_t ) );
69     vlc_mutex_init( p_playlist, &p_playlist->p_stats->lock );
70
71     // Interaction
72     p_playlist->p_interaction = NULL;
73
74     // Preparse
75     p_playlist->p_preparse = vlc_object_create( p_playlist,
76                                   sizeof( playlist_preparse_t ) );
77     if( !p_playlist->p_preparse )
78     {
79         msg_Err( p_playlist, "unable to create preparser" );
80         vlc_object_destroy( p_playlist );
81         return NULL;
82     }
83     p_playlist->p_preparse->i_waiting = 0;
84     p_playlist->p_preparse->pp_waiting = NULL;
85
86     vlc_object_attach( p_playlist->p_preparse, p_playlist );
87     if( vlc_thread_create( p_playlist->p_preparse, "preparser",
88                            RunPreparse, VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
89     {
90         msg_Err( p_playlist, "cannot spawn preparse thread" );
91         vlc_object_detach( p_playlist->p_preparse );
92         vlc_object_destroy( p_playlist->p_preparse );
93         return NULL;
94     }
95
96     // Start the thread
97     if( vlc_thread_create( p_playlist, "playlist", RunControlThread,
98                            VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
99     {
100         msg_Err( p_playlist, "cannot spawn playlist thread" );
101         vlc_object_destroy( p_playlist );
102         return NULL;
103     }
104
105     /* The object has been initialized, now attach it */
106     vlc_object_attach( p_playlist, p_parent );
107
108     return p_playlist;
109 }
110
111 /**
112  * Destroy the playlist global thread.
113  *
114  * Deinits all things controlled by the playlist global thread
115  * \param p_playlist the playlist thread to destroy
116  * \return VLC_SUCCESS or an error
117  */
118 int playlist_ThreadDestroy( playlist_t * p_playlist )
119 {
120     p_playlist->b_die = 1;
121
122     DestroyInteraction( p_playlist );
123     DestroyPlaylist( p_playlist );
124
125     return VLC_SUCCESS;
126 }
127
128 /**
129  * Run the main control thread itself
130  */
131 static void RunControlThread ( playlist_t *p_playlist )
132 {
133    int i_loops = 0;
134
135    /* Tell above that we're ready */
136    vlc_thread_ready( p_playlist );
137
138     while( !p_playlist->b_die )
139     {
140         i_loops++;
141
142         HandleInteraction( p_playlist );
143         HandleStats( p_playlist, i_loops );
144
145         HandlePlaylist( p_playlist );
146
147         msleep( INTF_IDLE_SLEEP / 2 );
148
149         /* Stop sleeping earlier if we have work */
150         /* TODO : statistics about this */
151         if ( p_playlist->request.b_request &&
152                         p_playlist->status.i_status == PLAYLIST_RUNNING )
153         {
154             continue;
155         }
156
157         msleep( INTF_IDLE_SLEEP / 2 );
158     }
159
160     EndPlaylist( p_playlist );
161 }
162
163
164 /*****************************************************************************
165  * Playlist-specific functions
166  *****************************************************************************/
167 static playlist_t * CreatePlaylist( vlc_object_t *p_parent )
168 {
169     return playlist_Create( p_parent );
170 }
171
172 static void DestroyPlaylist( playlist_t *p_playlist )
173 {
174     playlist_Destroy( p_playlist );
175 }
176
177 static void HandlePlaylist( playlist_t *p_playlist )
178 {
179     playlist_MainLoop( p_playlist );
180 }
181
182 static void EndPlaylist( playlist_t *p_playlist )
183 {
184     playlist_LastLoop( p_playlist );
185 }
186
187 /*****************************************************************************
188  * Preparse-specific functions
189  *****************************************************************************/
190 static void RunPreparse ( playlist_preparse_t *p_obj )
191 {
192     playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
193     /* Tell above that we're ready */
194     vlc_thread_ready( p_obj );
195
196     while( !p_playlist->b_die )
197     {
198         playlist_PreparseLoop(  p_obj );
199         if( p_obj->i_waiting == 0 )
200         {
201             msleep( INTF_IDLE_SLEEP );
202         }
203     }
204 }
205
206 /*****************************************************************************
207  * Interaction functions
208  *****************************************************************************/
209 static void DestroyInteraction( playlist_t *p_playlist )
210 {
211     if( p_playlist->p_interaction )
212     {
213         intf_InteractionDestroy( p_playlist->p_interaction );
214     }
215 }
216
217 static void HandleInteraction( playlist_t *p_playlist )
218 {
219     if( p_playlist->p_interaction )
220     {
221         stats_TimerStart( p_playlist, "Interaction thread",
222                           STATS_TIMER_INTERACTION );
223         intf_InteractionManage( p_playlist );
224         stats_TimerStop( p_playlist, STATS_TIMER_INTERACTION );
225     }
226 }
227
228
229 /*****************************************************************************
230  * Stats functions
231  *****************************************************************************/
232 static void HandleStats( playlist_t *p_playlist, int i_loops )
233 {
234     if( i_loops %5 == 0 && p_playlist->p_stats )
235     {
236         stats_ComputeGlobalStats( p_playlist, p_playlist->p_stats );
237         if( p_playlist->p_input )
238         {
239             stats_ComputeInputStats( p_playlist->p_input,
240                                 p_playlist->p_input->input.p_item->p_stats );
241         }
242     }
243 }