]> git.sesse.net Git - vlc/blobdiff - src/playlist/control.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / src / playlist / control.c
index 82e62e322a65af57407fa13b7e60e0dfc6672fd2..38ddf485646668a97440732351a857bd6b2a64f0 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- * control.c : Hanle control of the playlist & running through it
+ * control.c : Handle control of the playlist & running through it
  *****************************************************************************
  * Copyright (C) 1999-2004 the VideoLAN team
- * $Id: /local/vlc/0.8.6-playlist-vlm/src/playlist/playlist.c 13741 2006-03-21T19:29:39.792444Z zorglub  $
+ * $Id$
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *          ClĂ©ment Stenac <zorglub@videolan.org>
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc/input.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
 #include "vlc_playlist.h"
+#include "playlist_internal.h"
 #include <assert.h>
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args );
-
-void PreparseEnqueueItemSub( playlist_t *, playlist_item_t * );
-
-playlist_item_t *playlist_RecursiveFindLast(playlist_t *p_playlist,
-                                            playlist_item_t *p_node );
+static int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args );
 
 /*****************************************************************************
  * Playlist control
  *****************************************************************************/
 
-/**
- * Do a playlist action. Should be entered without playlist lock
- * \see playlist_Control
- */
-int playlist_LockControl( playlist_t * p_playlist, int i_query, ... )
+static vlc_mutex_t global_lock = VLC_STATIC_MUTEX;
+
+#undef pl_Get
+playlist_t *pl_Get (vlc_object_t *obj)
 {
-    va_list args;
-    int i_result;
-    va_start( args, i_query );
-    vlc_mutex_lock( &p_playlist->object_lock );
-    i_result = PlaylistVAControl( p_playlist, i_query, args );
-    va_end( args );
-    vlc_mutex_unlock( &p_playlist->object_lock );
-    return i_result;
+    playlist_t *pl;
+    libvlc_int_t *p_libvlc = obj->p_libvlc;
+
+    vlc_mutex_lock (&global_lock);
+    pl = libvlc_priv (p_libvlc)->p_playlist;
+    assert (pl != NULL);
+
+    if (!libvlc_priv (p_libvlc)->playlist_active)
+    {
+         playlist_Activate (pl);
+         libvlc_priv (p_libvlc)->playlist_active = true;
+    }
+    vlc_mutex_unlock (&global_lock);
+    return pl;
 }
 
-/**
- * Do a playlist action.
- * If there is something in the playlist then you can do playlist actions.
- * Should be entered with playlist lock. See include/vlc_playlist.h for
- * possible queries
- *
- * \param p_playlist the playlist to do the command on
- * \param i_query the command to do
- * \param variable number of arguments
- * \return VLC_SUCCESS or an error
- */
-int playlist_Control( playlist_t * p_playlist, int i_query, ... )
+void pl_Deactivate (libvlc_int_t *p_libvlc)
+{
+    bool deactivate;
+
+    vlc_mutex_lock (&global_lock);
+    deactivate = libvlc_priv (p_libvlc)->playlist_active;
+    vlc_mutex_unlock (&global_lock);
+
+    if (deactivate)
+        playlist_Deactivate (libvlc_priv (p_libvlc)->p_playlist);
+}
+
+void playlist_Lock( playlist_t *pl )
+{
+    vlc_mutex_lock( &pl_priv(pl)->lock );
+}
+
+void playlist_Unlock( playlist_t *pl )
+{
+    vlc_mutex_unlock( &pl_priv(pl)->lock );
+}
+
+void playlist_AssertLocked( playlist_t *pl )
+{
+    vlc_assert_locked( &pl_priv(pl)->lock );
+}
+
+int playlist_Control( playlist_t * p_playlist, int i_query,
+                      bool b_locked, ... )
 {
     va_list args;
     int i_result;
-    va_start( args, i_query );
+    PL_LOCK_IF( !b_locked );
+    va_start( args, b_locked );
     i_result = PlaylistVAControl( p_playlist, i_query, args );
     va_end( args );
+    PL_UNLOCK_IF( !b_locked );
 
     return i_result;
 }
 
-int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args )
+static int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args )
 {
-    int i_view;
     playlist_item_t *p_item, *p_node;
-    vlc_value_t val;
 
-    if( p_playlist->i_size <= 0 )
-    {
+    PL_ASSERT_LOCKED;
+
+    if( !vlc_object_alive( p_playlist ) )
+        return VLC_EGENERIC;
+
+    if( playlist_IsEmpty( p_playlist ) && i_query != PLAYLIST_STOP )
         return VLC_EGENERIC;
-    }
 
     switch( i_query )
     {
     case PLAYLIST_STOP:
-        p_playlist->request.i_status = PLAYLIST_STOPPED;
-        p_playlist->request.b_request = VLC_TRUE;
-        p_playlist->request.p_item = NULL;
+        pl_priv(p_playlist)->request.i_status = PLAYLIST_STOPPED;
+        pl_priv(p_playlist)->request.b_request = true;
+        pl_priv(p_playlist)->request.p_item = NULL;
         break;
 
     // Node can be null, it will keep the same. Use with care ...
@@ -104,78 +128,68 @@ int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args )
         p_item = (playlist_item_t *)va_arg( args, playlist_item_t * );
         if ( p_node == NULL )
         {
-            p_node = p_playlist->status.p_node;
+            p_node = get_current_status_node( p_playlist );
             assert( p_node );
         }
-        p_playlist->request.i_status = PLAYLIST_RUNNING;
-        p_playlist->request.i_skip = 0;
-        p_playlist->request.b_request = VLC_TRUE;
-        p_playlist->request.p_node = p_node;
-        p_playlist->request.p_item = p_item;
+        pl_priv(p_playlist)->request.i_status = PLAYLIST_RUNNING;
+        pl_priv(p_playlist)->request.i_skip = 0;
+        pl_priv(p_playlist)->request.b_request = true;
+        pl_priv(p_playlist)->request.p_node = p_node;
+        pl_priv(p_playlist)->request.p_item = p_item;
+        if( p_item && var_GetBool( p_playlist, "random" ) )
+            pl_priv(p_playlist)->b_reset_currently_playing = true;
         break;
 
     case PLAYLIST_PLAY:
-        if( p_playlist->p_input )
+        if( pl_priv(p_playlist)->p_input )
         {
-            val.i_int = PLAYING_S;
-            var_Set( p_playlist->p_input, "state", val );
+            var_SetInteger( pl_priv(p_playlist)->p_input, "state", PLAYING_S );
             break;
         }
         else
         {
-            p_playlist->request.i_status = PLAYLIST_RUNNING;
-            p_playlist->request.b_request = VLC_TRUE;
-            p_playlist->request.p_node = p_playlist->status.p_node;
-            p_playlist->request.p_item = p_playlist->status.p_item;
-            p_playlist->request.i_skip = 0;
+            pl_priv(p_playlist)->request.i_status = PLAYLIST_RUNNING;
+            pl_priv(p_playlist)->request.b_request = true;
+            pl_priv(p_playlist)->request.p_node = get_current_status_node( p_playlist );
+            pl_priv(p_playlist)->request.p_item = get_current_status_item( p_playlist );
+            pl_priv(p_playlist)->request.i_skip = 0;
         }
         break;
 
-    case PLAYLIST_AUTOPLAY:
-        // AUTOPLAY is an ugly hack for initial status.
-        // Hopefully it will disappear
-        p_playlist->status.i_status = PLAYLIST_RUNNING;
-        p_playlist->request.p_node = p_playlist->status.p_node;
-        p_playlist->request.b_request = VLC_FALSE;
-        break;
-
     case PLAYLIST_PAUSE:
-        val.i_int = 0;
-        if( p_playlist->p_input )
-            var_Get( p_playlist->p_input, "state", &val );
+        if( !pl_priv(p_playlist)->p_input )
+        {    /* FIXME: is this really useful without input? */
+             pl_priv(p_playlist)->status.i_status = PLAYLIST_PAUSED;
+             break;
+        }
 
-        if( val.i_int == PAUSE_S )
+        if( var_GetInteger( pl_priv(p_playlist)->p_input, "state" ) == PAUSE_S )
         {
-            p_playlist->status.i_status = PLAYLIST_RUNNING;
-            if( p_playlist->p_input )
-            {
-                val.i_int = PLAYING_S;
-                var_Set( p_playlist->p_input, "state", val );
-            }
+            pl_priv(p_playlist)->status.i_status = PLAYLIST_RUNNING;
+            var_SetInteger( pl_priv(p_playlist)->p_input, "state", PLAYING_S );
         }
         else
         {
-            p_playlist->status.i_status = PLAYLIST_PAUSED;
-            if( p_playlist->p_input )
-            {
-                val.i_int = PAUSE_S;
-                var_Set( p_playlist->p_input, "state", val );
-            }
+            pl_priv(p_playlist)->status.i_status = PLAYLIST_PAUSED;
+            var_SetInteger( pl_priv(p_playlist)->p_input, "state", PAUSE_S );
         }
         break;
 
     case PLAYLIST_SKIP:
-        p_playlist->request.p_node = p_playlist->status.p_node;
-        p_playlist->request.p_item = p_playlist->status.p_item;
-        p_playlist->request.i_skip = (int) va_arg( args, int );
-        p_playlist->request.b_request = VLC_TRUE;
+        pl_priv(p_playlist)->request.p_node = get_current_status_node( p_playlist );
+        pl_priv(p_playlist)->request.p_item = get_current_status_item( p_playlist );
+        pl_priv(p_playlist)->request.i_skip = (int) va_arg( args, int );
+        /* if already running, keep running */
+        if( pl_priv(p_playlist)->status.i_status != PLAYLIST_STOPPED )
+            pl_priv(p_playlist)->request.i_status = pl_priv(p_playlist)->status.i_status;
+        pl_priv(p_playlist)->request.b_request = true;
         break;
 
     default:
         msg_Err( p_playlist, "unknown playlist query" );
         return VLC_EBADVAR;
-        break;
     }
+    vlc_cond_signal( &pl_priv(p_playlist)->signal );
 
     return VLC_SUCCESS;
 }
@@ -184,248 +198,23 @@ int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args )
  * Preparse control
  *****************************************************************************/
 /** Enqueue an item for preparsing */
-int playlist_PreparseEnqueue( playlist_t *p_playlist,
-                              input_item_t *p_item )
+int playlist_PreparseEnqueue( playlist_t *p_playlist, input_item_t *p_item )
 {
-    vlc_mutex_lock( &p_playlist->p_preparse->object_lock );
-    vlc_gc_incref( p_item );
-    INSERT_ELEM( p_playlist->p_preparse->pp_waiting,
-                 p_playlist->p_preparse->i_waiting,
-                 p_playlist->p_preparse->i_waiting,
-                 p_item );
-    vlc_mutex_unlock( &p_playlist->p_preparse->object_lock );
-    return VLC_SUCCESS;
-}
+    playlist_private_t *p_sys = pl_priv(p_playlist);
 
-/** Enqueue a playlist item or a node for peparsing.
- *  This function should be entered without playlist and preparser locks */
-int playlist_PreparseEnqueueItem( playlist_t *p_playlist,
-                                  playlist_item_t *p_item )
-{
-    vlc_mutex_lock( &p_playlist->object_lock );
-    vlc_mutex_lock( &p_playlist->p_preparse->object_lock );
-    PreparseEnqueueItemSub( p_playlist, p_item );
-    vlc_mutex_unlock( &p_playlist->p_preparse->object_lock );
-    vlc_mutex_unlock( &p_playlist->object_lock );
-    return VLC_SUCCESS;
-}
+    if( p_sys->p_preparser )
+        playlist_preparser_Push( p_sys->p_preparser, p_item );
 
-void PreparseEnqueueItemSub( playlist_t *p_playlist,
-                             playlist_item_t *p_item )
-{
-    int i;
-    if( p_item->i_children == -1 )
-    {
-        vlc_gc_incref( p_item );
-        INSERT_ELEM( p_playlist->p_preparse->pp_waiting,
-                     p_playlist->p_preparse->i_waiting,
-                     p_playlist->p_preparse->i_waiting,
-                     p_item->p_input );
-    }
-    else
-    {
-        for( i = 0; i < p_item->i_children; i++)
-        {
-            PreparseEnqueueItemSub( p_playlist,
-                                             p_item->pp_children[i] );
-        }
-    }
-}
-
-/*****************************************************************************
- * Playback logic
- *****************************************************************************/
-
-/** This function calculates the next playlist item, depending
- *  on the playlist course mode (forward, backward, random, view,...). */
-playlist_item_t * playlist_NextItem( playlist_t *p_playlist )
-{
-    playlist_item_t *p_new = NULL;
-    int i_skip,i;
-
-    vlc_bool_t b_loop = var_GetBool( p_playlist, "loop" );
-    vlc_bool_t b_random = var_GetBool( p_playlist, "random" );
-    vlc_bool_t b_repeat = var_GetBool( p_playlist, "repeat" );
-    vlc_bool_t b_playstop = var_GetBool( p_playlist, "play-and-stop" );
-
-    /* Handle quickly a few special cases */
-    /* No items to play */
-    if( p_playlist->i_size == 0 )
-    {
-        msg_Info( p_playlist, "playlist is empty" );
-        return NULL;
-    }
-
-    /* Repeat and play/stop */
-    if( !p_playlist->request.b_request && b_repeat == VLC_TRUE &&
-         p_playlist->status.p_item )
-    {
-        msg_Dbg( p_playlist,"repeating item" );
-        return p_playlist->status.p_item;
-    }
-    if( !p_playlist->request.b_request && b_playstop == VLC_TRUE )
-    {
-        msg_Dbg( p_playlist,"stopping (play and stop)");
-        return NULL;
-    }
-
-    if( !p_playlist->request.b_request && p_playlist->status.p_item &&
-         p_playlist->status.p_item->i_flags & PLAYLIST_SKIP_FLAG )
-    {
-        msg_Dbg( p_playlist, "blocking item, stopping") ;
-        return NULL;
-    }
-
-    /* Random case. This is an exception: if request, but request is skip +- 1
-     * we don't go to next item but select a new random one. */
-    if( b_random )
-        msg_Err( p_playlist, "random unsupported" );
-#if 0
-            &&
-        ( !p_playlist->request.b_request ||
-        ( p_playlist->request.b_request && ( p_playlist->request.p_item == NULL ||
-          p_playlist->request.i_skip == 1 || p_playlist->request.i_skip == -1 ) ) ) )
-    {
-        /* how many items to choose from ? */
-        i_count = 0;
-        for ( i = 0; i < p_playlist->i_size; i++ )
-        {
-            if ( p_playlist->pp_items[i]->p_input->i_nb_played == 0 )
-                i_count++;
-        }
-        /* Nothing left? */
-        if ( i_count == 0 )
-        {
-            /* Don't loop? Exit! */
-            if( !b_loop )
-                return NULL;
-            /* Otherwise reset the counter */
-            for ( i = 0; i < p_playlist->i_size; i++ )
-            {
-                p_playlist->pp_items[i]->p_input->i_nb_played = 0;
-            }
-            i_count = p_playlist->i_size;
-        }
-        srand( (unsigned int)mdate() );
-        i = rand() % i_count + 1 ;
-        /* loop thru the list and count down the unplayed items to the selected one */
-        for ( i_new = 0; i_new < p_playlist->i_size && i > 0; i_new++ )
-        {
-            if ( p_playlist->pp_items[i_new]->p_input->i_nb_played == 0 )
-                i--;
-        }
-        i_new--;
-
-        p_playlist->request.i_skip = 0;
-        p_playlist->request.b_request = VLC_FALSE;
-        return p_playlist->pp_items[i_new];
-    }
-#endif
-
-    /* Start the real work */
-    if( p_playlist->request.b_request )
-    {
-        PL_DEBUG( "processing request" );
-        p_new = p_playlist->request.p_item;
-        i_skip = p_playlist->request.i_skip;
-
-        if( p_playlist->request.p_node )
-            p_playlist->status.p_node = p_playlist->request.p_node;
-
-        /* If we are asked for a node, dont take it */
-        if( i_skip == 0 && ( p_new == NULL || p_new->i_children != -1 ) )
-            i_skip++;
-
-        if( i_skip > 0 )
-        {
-            for( i = i_skip; i > 0 ; i-- )
-            {
-                p_new = playlist_GetNextEnabledLeaf( p_playlist,
-                                                     p_playlist->request.p_node,
-                                                     p_new );
-                if( p_new == NULL )
-                {
-                    PL_DEBUG( "looping - restarting at beginning of node" );
-                    p_new = playlist_GetNextLeaf( p_playlist,
-                                                  p_playlist->request.p_node,
-                                                  NULL );
-                    if( p_new == NULL ) break;
-                }
-            }
-        }
-        else if( i_skip < 0 )
-        {
-            for( i = i_skip; i < 0 ; i++ )
-            {
-                p_new = playlist_GetPrevLeaf( p_playlist,
-                                              p_playlist->request.p_node,
-                                              p_new );
-                if( p_new == NULL )
-                {
-                    PL_DEBUG( "looping - restarting at end of node" );
-                    /** \bug This is needed because GetPrevLeaf does not loop
-                      * by itself */
-                    p_new = playlist_GetLastLeaf( p_playlist,
-                                                 p_playlist->request.p_node );
-                }
-                if( p_new == NULL ) break;
-            }
-        }
-        /* Clear the request */
-        p_playlist->request.b_request = VLC_FALSE;
-    }
-    /* "Automatic" item change ( next ) */
-    else
-    {
-        PL_DEBUG( "changing item without a request" );
-        /* Cant go to next from current item */
-        if( p_playlist->status.p_item &&
-            p_playlist->status.p_item->i_flags & PLAYLIST_SKIP_FLAG )
-            return NULL;
-
-        p_new = playlist_GetNextLeaf( p_playlist,
-                                      p_playlist->status.p_node,
-                                      p_playlist->status.p_item );
-        if( p_new == NULL && b_loop )
-        {
-            PL_DEBUG( "looping" );
-            p_new = playlist_GetNextLeaf( p_playlist,
-                                          p_playlist->status.p_node,
-                                          NULL );
-        }
-        /* The new item can't be autoselected  */
-        if( p_new != NULL && p_new->i_flags & PLAYLIST_SKIP_FLAG )
-            return NULL;
-    }
-    if( p_new == NULL )
-    {
-        msg_Dbg( p_playlist, "did not find something to play" );
-    }
-    return p_new;
+    return VLC_SUCCESS;
 }
 
-/** Start the input for an item */
-int playlist_PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
+int playlist_AskForArtEnqueue( playlist_t *p_playlist, input_item_t *p_item )
 {
-    vlc_value_t val;
-    int i_activity = var_GetInteger( p_playlist, "activity") ;
-
-    msg_Dbg( p_playlist, "creating new input thread" );
-
-    p_item->p_input->i_nb_played++;
-    p_playlist->status.p_item = p_item;
+    playlist_private_t *p_sys = pl_priv(p_playlist);
 
-    p_playlist->status.i_status = PLAYLIST_RUNNING;
-
-    var_SetInteger( p_playlist, "activity", i_activity +
-                    DEFAULT_INPUT_ACTIVITY );
-    p_playlist->p_input = input_CreateThread( p_playlist, p_item->p_input );
-
-    val.i_int = p_item->p_input->i_id;
-    /* unlock the playlist to set the var...mmm */
-    vlc_mutex_unlock( &p_playlist->object_lock);
-    var_Set( p_playlist, "playlist-current", val);
-    vlc_mutex_lock( &p_playlist->object_lock);
+    if( p_sys->p_fetcher )
+        playlist_fetcher_Push( p_sys->p_fetcher, p_item );
 
     return VLC_SUCCESS;
 }
+