1 /*****************************************************************************
2 * engine.c : Run the playlist and handle its control
3 *****************************************************************************
4 * Copyright (C) 1999-2008 the VideoLAN team
6 * Authors: Samuel Hocevar <sam@zoy.org>
7 * Clément Stenac <zorglub@videolan.org>
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.
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.
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 *****************************************************************************/
30 #include <vlc_common.h>
32 #include <vlc_playlist.h>
33 #include <vlc_interface.h>
34 #include "playlist_internal.h"
35 #include "stream_output/stream_output.h" /* sout_DeleteInstance */
37 /*****************************************************************************
39 *****************************************************************************/
40 static void VariablesInit( playlist_t
*p_playlist
);
41 static void playlist_Destructor( vlc_object_t
* p_this
);
43 static int RandomCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
44 vlc_value_t oldval
, vlc_value_t newval
, void *a
)
46 (void)psz_cmd
; (void)oldval
; (void)newval
; (void)a
;
47 playlist_t
*p_playlist
= (playlist_t
*)p_this
;
51 pl_priv(p_playlist
)->b_reset_currently_playing
= true;
52 vlc_cond_signal( &pl_priv(p_playlist
)->signal
);
61 * Create a playlist structure.
62 * \param p_parent the vlc object that is to be the parent of this playlist
63 * \return a pointer to the created playlist, or NULL on error
65 playlist_t
* playlist_Create( vlc_object_t
*p_parent
)
67 static const char playlist_name
[] = "playlist";
68 playlist_t
*p_playlist
;
69 playlist_private_t
*p
;
71 /* Allocate structure */
72 p
= vlc_custom_create( p_parent
, sizeof( *p
),
73 VLC_OBJECT_GENERIC
, playlist_name
);
77 assert( offsetof( playlist_private_t
, public_data
) == 0 );
78 p_playlist
= &p
->public_data
;
79 TAB_INIT( pl_priv(p_playlist
)->i_sds
, pl_priv(p_playlist
)->pp_sds
);
81 libvlc_priv(p_parent
->p_libvlc
)->p_playlist
= p_playlist
;
83 VariablesInit( p_playlist
);
84 vlc_mutex_init( &p
->lock
);
85 vlc_cond_init( &p
->signal
);
87 /* Initialise data structures */
88 pl_priv(p_playlist
)->i_last_playlist_id
= 0;
89 pl_priv(p_playlist
)->p_input
= NULL
;
91 ARRAY_INIT( p_playlist
->items
);
92 ARRAY_INIT( p_playlist
->all_items
);
93 ARRAY_INIT( pl_priv(p_playlist
)->items_to_delete
);
94 ARRAY_INIT( p_playlist
->current
);
96 p_playlist
->i_current_index
= 0;
97 pl_priv(p_playlist
)->b_reset_currently_playing
= true;
98 pl_priv(p_playlist
)->last_rebuild_date
= 0;
100 pl_priv(p_playlist
)->b_tree
= var_CreateGetBool( p_playlist
, "playlist-tree" );
102 pl_priv(p_playlist
)->b_doing_ml
= false;
104 const bool b_auto_preparse
= var_CreateGetBool( p_playlist
, "auto-preparse" );
105 pl_priv(p_playlist
)->b_auto_preparse
= b_auto_preparse
;
107 PL_LOCK
; /* playlist_NodeCreate will check for it */
108 p_playlist
->p_root_category
= playlist_NodeCreate( p_playlist
, NULL
, NULL
,
110 p_playlist
->p_root_onelevel
= playlist_NodeCreate( p_playlist
, NULL
, NULL
,
111 0, p_playlist
->p_root_category
->p_input
);
114 if( !p_playlist
->p_root_category
|| !p_playlist
->p_root_onelevel
)
117 /* Create playlist and media library */
118 PL_LOCK
; /* playlist_NodesPairCreate will check for it */
119 playlist_NodesPairCreate( p_playlist
, _( "Playlist" ),
120 &p_playlist
->p_local_category
,
121 &p_playlist
->p_local_onelevel
, false );
124 p_playlist
->p_local_category
->i_flags
|= PLAYLIST_RO_FLAG
;
125 p_playlist
->p_local_onelevel
->i_flags
|= PLAYLIST_RO_FLAG
;
127 if( !p_playlist
->p_local_category
|| !p_playlist
->p_local_onelevel
||
128 !p_playlist
->p_local_category
->p_input
||
129 !p_playlist
->p_local_onelevel
->p_input
)
132 if( config_GetInt( p_playlist
, "media-library") )
134 PL_LOCK
; /* playlist_NodesPairCreate will check for it */
135 playlist_NodesPairCreate( p_playlist
, _( "Media Library" ),
136 &p_playlist
->p_ml_category
,
137 &p_playlist
->p_ml_onelevel
, false );
140 if(!p_playlist
->p_ml_category
|| !p_playlist
->p_ml_onelevel
)
143 p_playlist
->p_ml_category
->i_flags
|= PLAYLIST_RO_FLAG
;
144 p_playlist
->p_ml_onelevel
->i_flags
|= PLAYLIST_RO_FLAG
;
148 p_playlist
->p_ml_category
= p_playlist
->p_ml_onelevel
= NULL
;
152 pl_priv(p_playlist
)->status
.p_item
= NULL
;
153 pl_priv(p_playlist
)->status
.p_node
= p_playlist
->p_local_onelevel
;
154 pl_priv(p_playlist
)->request
.b_request
= false;
155 pl_priv(p_playlist
)->status
.i_status
= PLAYLIST_STOPPED
;
157 pl_priv(p_playlist
)->b_auto_preparse
= false;
158 playlist_MLLoad( p_playlist
);
159 pl_priv(p_playlist
)->b_auto_preparse
= b_auto_preparse
;
161 vlc_object_set_destructor( p_playlist
, playlist_Destructor
);
169 * Destroy a playlist structure.
170 * \param p_playlist the playlist object
174 static void playlist_Destructor( vlc_object_t
* p_this
)
176 playlist_t
*p_playlist
= (playlist_t
*)p_this
;
177 playlist_private_t
*p_sys
= pl_priv(p_playlist
);
179 assert( !p_sys
->p_input
);
180 assert( !p_sys
->p_input_resource
);
181 assert( !p_sys
->p_preparser
);
182 assert( !p_sys
->p_fetcher
);
184 vlc_cond_destroy( &p_sys
->signal
);
185 vlc_mutex_destroy( &p_sys
->lock
);
187 /* Remove all remaining items */
188 FOREACH_ARRAY( playlist_item_t
*p_del
, p_playlist
->all_items
)
189 free( p_del
->pp_children
);
190 vlc_gc_decref( p_del
->p_input
);
193 ARRAY_RESET( p_playlist
->all_items
);
194 FOREACH_ARRAY( playlist_item_t
*p_del
, p_sys
->items_to_delete
)
195 free( p_del
->pp_children
);
196 vlc_gc_decref( p_del
->p_input
);
199 ARRAY_RESET( p_sys
->items_to_delete
);
201 ARRAY_RESET( p_playlist
->items
);
202 ARRAY_RESET( p_playlist
->current
);
204 msg_Dbg( p_this
, "Destroyed" );
207 /** Get current playing input.
209 input_thread_t
* playlist_CurrentInput( playlist_t
* p_playlist
)
211 input_thread_t
* p_input
;
213 p_input
= pl_priv(p_playlist
)->p_input
;
214 if( p_input
) vlc_object_hold( p_input
);
223 /** Accessor for status item and status nodes.
225 playlist_item_t
* get_current_status_item( playlist_t
* p_playlist
)
229 return pl_priv(p_playlist
)->status
.p_item
;
232 playlist_item_t
* get_current_status_node( playlist_t
* p_playlist
)
236 return pl_priv(p_playlist
)->status
.p_node
;
239 void set_current_status_item( playlist_t
* p_playlist
,
240 playlist_item_t
* p_item
)
244 if( pl_priv(p_playlist
)->status
.p_item
&&
245 pl_priv(p_playlist
)->status
.p_item
->i_flags
& PLAYLIST_REMOVE_FLAG
&&
246 pl_priv(p_playlist
)->status
.p_item
!= p_item
)
248 /* It's unsafe given current design to delete a playlist item :(
249 playlist_ItemDelete( pl_priv(p_playlist)->status.p_item ); */
251 pl_priv(p_playlist
)->status
.p_item
= p_item
;
254 void set_current_status_node( playlist_t
* p_playlist
,
255 playlist_item_t
* p_node
)
259 if( pl_priv(p_playlist
)->status
.p_node
&&
260 pl_priv(p_playlist
)->status
.p_node
->i_flags
& PLAYLIST_REMOVE_FLAG
&&
261 pl_priv(p_playlist
)->status
.p_node
!= p_node
)
263 /* It's unsafe given current design to delete a playlist item :(
264 playlist_ItemDelete( pl_priv(p_playlist)->status.p_node ); */
266 pl_priv(p_playlist
)->status
.p_node
= p_node
;
269 static void VariablesInit( playlist_t
*p_playlist
)
271 /* These variables control updates */
272 var_Create( p_playlist
, "intf-change", VLC_VAR_BOOL
);
273 var_SetBool( p_playlist
, "intf-change", true );
275 var_Create( p_playlist
, "item-change", VLC_VAR_ADDRESS
);
277 var_Create( p_playlist
, "playlist-item-deleted", VLC_VAR_INTEGER
);
278 var_SetInteger( p_playlist
, "playlist-item-deleted", -1 );
280 var_Create( p_playlist
, "playlist-item-append", VLC_VAR_ADDRESS
);
282 var_Create( p_playlist
, "item-current", VLC_VAR_ADDRESS
);
283 var_Create( p_playlist
, "input-current", VLC_VAR_ADDRESS
);
285 var_Create( p_playlist
, "activity", VLC_VAR_INTEGER
);
286 var_SetInteger( p_playlist
, "activity", 0 );
288 /* Variables to control playback */
289 var_Create( p_playlist
, "play-and-stop", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
290 var_Create( p_playlist
, "play-and-exit", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
291 var_Create( p_playlist
, "random", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
292 var_Create( p_playlist
, "repeat", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
293 var_Create( p_playlist
, "loop", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
295 var_AddCallback( p_playlist
, "random", RandomCallback
, NULL
);
298 var_Create( p_playlist
, "album-art", VLC_VAR_INTEGER
| VLC_VAR_DOINHERIT
);
301 playlist_item_t
* playlist_CurrentPlayingItem( playlist_t
* p_playlist
)
305 return pl_priv(p_playlist
)->status
.p_item
;
308 int playlist_Status( playlist_t
* p_playlist
)
312 return pl_priv(p_playlist
)->status
.i_status
;