]> git.sesse.net Git - vlc/commitdiff
ML: Media Library Core
authorSrikanth Raju <srikiraju@gmail.com>
Mon, 21 Jun 2010 16:56:52 +0000 (22:26 +0530)
committerSrikanth Raju <srikiraju@gmail.com>
Sat, 26 Jun 2010 13:02:56 +0000 (18:32 +0530)
Core functions and singleton media library object

src/Makefile.am
src/libvlc-module.c
src/libvlc.c
src/libvlc.h
src/libvlccore.sym
src/misc/media_library.c [new file with mode: 0644]
src/missing.c

index 638c7e4ed1f61943eac5a7693f05ce5f366652b1..1ce58d56357ef3916211370de89bac78329c7e57 100644 (file)
@@ -77,6 +77,7 @@ pluginsinclude_HEADERS = \
        ../include/vlc_md5.h \
        ../include/vlc_messages.h \
        ../include/vlc_meta.h \
+       ../include/vlc_media_library.h \
        ../include/vlc_modules.h \
        ../include/vlc_mouse.h \
        ../include/vlc_mtime.h \
@@ -452,6 +453,7 @@ SOURCES_libvlc_common = \
        misc/update.c \
        misc/update_crypto.c \
        misc/xml.c \
+       misc/media_library.c \
        extras/libc.c \
        extras/tdestroy.c \
        misc/filter.c \
index 80962bee561a8550c00f94a68b83868091c70b29..435fd65b18392024b0817ba82ffceadb2fadca64 100644 (file)
@@ -1259,6 +1259,10 @@ static const char *const ppsz_albumart_descriptions[] =
     "The media library is automatically saved and reloaded each time you " \
     "start VLC." )
 
+#define LOAD_ML_TEXT N_( "Load Media Library" )
+#define LOAD_ML_LONGTEXT N_( \
+    "Enable this option to load the SQL-based Media Library at VLC startup" )
+
 #define PLTREE_TEXT N_("Display playlist tree")
 #define PLTREE_LONGTEXT N_( \
     "The playlist can use a tree to categorize some items, like the " \
@@ -2123,6 +2127,10 @@ vlc_module_begin ()
     add_bool( "play-and-pause", 0, NULL, PAP_TEXT, PAP_LONGTEXT, true )
         change_safe()
     add_bool( "media-library", 1, NULL, ML_TEXT, ML_LONGTEXT, false )
+#if defined( MEDIA_LIBRARY )
+    add_bool( "load-media-library-on-startup", 1, NULL, LOAD_ML_TEXT,
+            LOAD_ML_LONGTEXT, false )
+#endif
     add_bool( "playlist-tree", 0, NULL, PLTREE_TEXT, PLTREE_LONGTEXT, false )
 
     add_string( "open", "", NULL, OPEN_TEXT, OPEN_LONGTEXT, false )
index efd4952445624efa3436cd354c03e98b3b4df537..9ec04a6b5590d8d63197d36d849e087009e0ed62 100644 (file)
@@ -68,6 +68,8 @@
 #   include <dbus/dbus.h>
 #endif
 
+
+#include <vlc_media_library.h>
 #include <vlc_playlist.h>
 #include <vlc_interface.h>
 
@@ -251,6 +253,7 @@ libvlc_int_t * libvlc_InternalCreate( void )
 
     priv = libvlc_priv (p_libvlc);
     priv->p_playlist = NULL;
+    priv->p_ml = NULL;
     priv->p_dialog_provider = NULL;
     priv->p_vlm = NULL;
 
@@ -819,6 +822,23 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
     /* System specific configuration */
     system_Configure( p_libvlc, i_argc - vlc_optind, ppsz_argv + vlc_optind );
 
+#if defined(MEDIA_LIBRARY)
+    /* Get the ML */
+    if( var_GetBool( p_libvlc, "load-media-library-on-startup" ) == true )
+    {
+        priv->p_ml = __ml_Create( VLC_OBJECT( p_libvlc ), NULL );
+        if( !priv->p_ml )
+        {
+            msg_Err( p_libvlc, "ML initialization failed" );
+            return VLC_EGENERIC;
+        }
+    }
+    else
+    {
+        priv->p_ml = NULL;
+    }
+#endif
+
     /* Add service discovery modules */
     psz_modules = var_InheritString( p_libvlc, "services-discovery" );
     if( psz_modules )
@@ -1014,6 +1034,22 @@ void libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
     /* Free playlist now, all threads are gone */
     playlist_Destroy( p_playlist );
 
+    /* Free playlist now */
+#if defined(MEDIA_LIBRARY)
+    media_library_t* p_ml = priv->p_ml;
+    if( p_ml )
+    {
+        __ml_Destroy( VLC_OBJECT( p_ml ) );
+        vlc_object_release( p_ml );
+        libvlc_priv(p_playlist->p_libvlc)->p_ml = NULL;
+    }
+#endif
+
+    /* Free playlist */
+    /* Any thread still running must not assume pl_Hold() succeeds. */
+    msg_Dbg( p_libvlc, "removing playlist" );
+    vlc_object_release( p_playlist );
+
     stats_TimersDumpAll( p_libvlc );
     stats_TimersCleanAll( p_libvlc );
 
index 873b73cd9d63af7d906a3ad1b194f9e063f7647b..48205b1471b96712a354a811ace5022a0ddef251 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef LIBVLC_LIBVLC_H
 # define LIBVLC_LIBVLC_H 1
 
+#include<vlc_media_library.h>
+
 typedef struct variable_t variable_t;
 
 /* Actions (hot keys) */
@@ -211,7 +213,8 @@ typedef struct libvlc_priv_t
 
     /* Singleton objects */
     module_t          *p_memcpy_module;  ///< Fast memcpy plugin used
-    playlist_t        *p_playlist; //< the playlist singleton
+    playlist_t        *p_playlist; ///< the playlist singleton
+    media_library_t   *p_ml;    ///< the ML singleton
     vlm_t             *p_vlm;  ///< the VLM singleton (or NULL)
     vlc_object_t      *p_dialog_provider; ///< dialog provider
     httpd_t           *p_httpd; ///< HTTP daemon (src/network/httpd.c)
index 49942250e9e71d64b56ea8badcb267a36a59c060..02100b0b473d8fc0b5a971e901130c6f5771d28b 100644 (file)
@@ -241,6 +241,20 @@ LocaleFree
 make_URI
 make_path
 mdate
+__ml_Create
+__ml_Destroy
+__ml_Hold
+__ml_Release
+media_Destroy
+media_New
+ml_OpConnectChilds
+__ml_FtreeSpec
+__ml_UpdateSimple
+ml_GetPersonsFromMedia
+ml_DeletePersonTypeFromMedia
+ml_PlaySmartPlaylistBasedOn
+ml_gc_decref
+ml_gc_incref
 module_config_free
 module_config_get
 module_exists
diff --git a/src/misc/media_library.c b/src/misc/media_library.c
new file mode 100644 (file)
index 0000000..1105b4a
--- /dev/null
@@ -0,0 +1,469 @@
+/*****************************************************************************
+ * media_library.c: SQL-based media library: ML creators and destructors
+ *****************************************************************************
+ * Copyright (C) 2009-2010 the VideoLAN team and AUTHORS
+ * $Id$
+ *
+ * Authors: Srikanth Raju <srikiraju at gmail dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#if !defined( __LIBVLC__ )
+  #error You are not libvlc or one of its plugins. You cannot include this file
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(MEDIA_LIBRARY)
+
+#include <assert.h>
+#include <vlc_media_library.h>
+#include "../libvlc.h"
+
+/**
+ * @brief Destroy the medialibrary object
+ * @param Parent object that holds the media library object
+ */
+void __ml_Destroy( vlc_object_t * p_this )
+{
+    media_library_t* p_ml = ( media_library_t* )p_this;
+    module_unneed( p_ml, p_ml->p_module );
+}
+
+
+/**
+ * Atomically set the reference count to 1.
+ * @param p_gc reference counted object
+ * @param pf_destruct destruction calback
+ * @return p_gc.
+ */
+static void *ml_gc_init (ml_gc_object_t *p_gc, void (*pf_destruct) (ml_gc_object_t *))
+{
+    /* There is no point in using the GC if there is no destructor... */
+    assert (pf_destruct);
+    p_gc->pf_destructor = pf_destruct;
+
+    p_gc->pool = false;
+    p_gc->refs = 1;
+    /* Nobody else can possibly lock the spin - it's there as a barrier */
+    vlc_spin_init (&p_gc->spin);
+    vlc_spin_lock (&p_gc->spin);
+    vlc_spin_unlock (&p_gc->spin);
+    return p_gc;
+}
+
+
+
+/**
+ * @brief Create an instance of the media library
+ * @param p_this Parent object
+ * @param psz_name Name which is passed to module_need (not needed)
+ * @return p_ml created and attached, module loaded. NULL if
+ * not able to load
+ */
+media_library_t *__ml_Create( vlc_object_t *p_this, char *psz_name )
+{
+    media_library_t *p_ml = NULL;
+
+    p_ml = ( media_library_t * ) vlc_custom_create(
+                                p_this, sizeof( media_library_t ),
+                                VLC_OBJECT_GENERIC, "media-library" );
+    if( !p_ml )
+    {
+        msg_Err( p_this, "unable to create media library object" );
+        return NULL;
+    }
+    vlc_object_attach( p_ml, p_this );
+
+    p_ml->p_module = module_need( p_ml, "media-library", psz_name, false );
+    if( !p_ml->p_module )
+    {
+        vlc_object_release( p_ml );
+        msg_Err( p_this, "Media Library provider not found" );
+        return NULL;
+    }
+
+    return p_ml;
+}
+
+/**
+ * @brief Acquire a reference to the media library singleton
+ * @param p_this Object that holds the reference
+ * @return media_library_t The ml object. NULL if not compiled with
+ * media library or if unable to load
+ */
+media_library_t* __ml_Hold( vlc_object_t* p_this )
+{
+    media_library_t* p_ml = NULL;
+    p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
+    assert( VLC_OBJECT( p_ml ) != p_this );
+    if( p_ml == NULL &&
+            var_GetBool( p_this->p_libvlc, "load-media-library-on-startup" ) == false )
+    {
+        libvlc_priv (p_this->p_libvlc)->p_ml
+            = __ml_Create( VLC_OBJECT( p_this->p_libvlc ), NULL );
+        p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
+    }
+    if( p_ml )
+        vlc_object_hold( p_ml );
+    return p_ml;
+}
+
+/**
+ * @brief Release a reference to the media library singleton
+ * @param p_this Object that holds the reference
+ */
+void __ml_Release( vlc_object_t* p_this )
+{
+    media_library_t* p_ml;
+    p_ml = libvlc_priv (p_this->p_libvlc)->p_ml;
+    if( p_ml == NULL )
+    {
+        msg_Warn( p_this->p_libvlc , "Spurious release ML called");
+        return;
+    }
+    assert( VLC_OBJECT( p_ml ) != p_this );
+    vlc_object_release( p_ml );
+}
+
+/**
+ * @brief Destructor for ml_media_t
+ */
+static void media_Destroy( ml_gc_object_t *p_gc )
+{
+    ml_media_t* p_media = ml_priv( p_gc, ml_media_t );
+    vlc_mutex_destroy( &p_media->lock );
+    ml_FreeMediaContent( p_media );
+    free( p_media );
+}
+
+/**
+ * @brief Object constructor for ml_media_t
+ * @param p_ml The media library object
+ * @param id If 0, this item isn't in database. If non zero, it is and
+ * it will be a singleton
+ * @param select Type of object
+ * @param reload Whether to reload from database
+ */
+ml_media_t* media_New( media_library_t* p_ml, int id,
+        ml_select_e select, bool reload )
+{
+    if( id == 0 )
+    {
+        ml_media_t* p_media = NULL;
+        p_media = ( ml_media_t* )calloc( 1, sizeof( ml_media_t ) );
+        ml_gc_init( &p_media->ml_gc_data, media_Destroy );
+        vlc_mutex_init( &p_media->lock );
+        return p_media;
+    }
+    else
+        return p_ml->functions.pf_GetMedia( p_ml, id, select, reload );
+}
+
+/**
+ * @brief Update a given table
+ * @param p_media_library The media library object
+ * @param selected_type The table to update
+ * @param psz_lvalue The role of the person if selected_type = ML_PEOPLE
+ * @param id The id of the row to update
+ * @param ... The update data. [SelectType [RoleType] Value] ... ML_END
+ */
+int __ml_UpdateSimple( media_library_t *p_media_library,
+                                     ml_select_e selected_type,
+                                     const char* psz_lvalue,
+                                     int id, ... )
+{
+    ml_element_t *update = NULL;
+    vlc_array_t *array = vlc_array_new();
+    int i_ret = VLC_SUCCESS;
+
+    va_list args;
+    va_start( args, id );
+
+    ml_select_e sel;
+    do {
+        update = ( ml_element_t* ) calloc( 1, sizeof( ml_element_t ) );
+        sel = ( ml_select_e ) va_arg( args, int );
+        update->criteria = sel;
+        if( sel == ML_PEOPLE )
+        {
+            update->lvalue.str = va_arg( args, char* );
+            update->value.str = va_arg( args, char* );
+            vlc_array_append( array, update );
+        }
+        else if( sel == ML_PEOPLE_ID )
+        {
+           update->lvalue.str = va_arg( args, char* );
+           update->value.i = va_arg( args, int );
+           vlc_array_append( array, update );
+        }
+        else if( sel == ML_PEOPLE_ROLE )
+        {
+#ifndef NDEBUG
+            msg_Dbg( p_media_library,
+                     "this argument is invalid for Update: %d",
+                     (int)sel );
+#endif
+        }
+        else
+        {
+            switch( ml_AttributeIsString( sel ) )
+            {
+                case -1:
+                    if( sel != ML_END )
+                    {
+#ifndef NDEBUG
+                        msg_Dbg( p_media_library,
+                                 "this argument is invalid for Update: %d",
+                                 (int)sel );
+#endif
+                        i_ret = VLC_EGENERIC;
+                    }
+                    else if( sel == ML_END )
+                        vlc_array_append( array, update );
+                    break;
+                case 0:
+                    update->value.str = va_arg( args, char* );
+                    vlc_array_append( array, update );
+                    break;
+                case 1:
+                    update->value.i = va_arg( args, int );
+                    vlc_array_append( array, update );
+                    break;
+            }
+        }
+    } while( sel != ML_END );
+
+    va_end( args );
+
+    ml_ftree_t* p_where = NULL;
+    ml_ftree_t* find = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
+    find->criteria = ML_ID;
+    find->value.i = id ;
+    find->comp = ML_COMP_EQUAL;
+    p_where = ml_FtreeFastAnd( p_where, find );
+
+    /* Let's update the database ! */
+    if( i_ret == VLC_SUCCESS )
+        i_ret = ml_Update( p_media_library, selected_type, psz_lvalue,
+                            p_where, array );
+
+    /* Destroying array */
+    for( int i = 0; i < vlc_array_count( array ); i++ )
+    {
+        free( vlc_array_item_at_index( array, i ) );
+    }
+    vlc_array_destroy( array );
+    ml_FreeFindTree( p_where );
+
+    return i_ret;
+}
+
+/**
+ * @brief Connect up a find tree
+ * @param op operator to connect with
+ * If op = ML_OP_NONE, then you are connecting to a tree consisting of
+ * only SPECIAL nodes.
+ * If op = ML_OP_NOT, then right MUST be NULL
+ * op must not be ML_OP_SPECIAL, @see __ml_FtreeSpec
+ * @param left part of the tree
+ * @param right part of the tree
+ * @return Pointer to new tree
+ * @note Use the helpers!
+ */
+ml_ftree_t* ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left,
+        ml_ftree_t* right )
+{
+    /* Use this Op for fresh trees (with only special nodes/none at all!) */
+    if( op == ML_OP_NONE )
+    {
+        assert( ml_FtreeHasOp( left ) == 0 );
+        if( left == NULL )
+            return right;
+        /* Percolate down tree only for special nodes */
+        assert( left->op == ML_OP_SPECIAL );
+        if( left->left == NULL )
+        {
+            left->left = right;
+            return left;
+        }
+        else
+        {
+            return ml_OpConnectChilds( ML_OP_NONE, left->left, right );
+        }
+    }
+    else if( op == ML_OP_NOT )
+    {
+        assert( right == NULL && left != NULL );
+        assert( ml_FtreeHasOp( left ) > 0 );
+    }
+    else if( op == ML_OP_SPECIAL )
+    {
+        assert( 0 );
+    }
+    else
+    {
+        assert( right != NULL && left != NULL );
+        assert( ml_FtreeHasOp( left ) > 0 );
+        assert( ml_FtreeHasOp( right ) > 0 );
+    }
+    ml_ftree_t* p_parent = (ml_ftree_t *) calloc( 1, sizeof( ml_ftree_t ) );
+    p_parent->op = op;
+    p_parent->left = left;
+    p_parent->right = right;
+    return p_parent;
+}
+
+/**
+ * @brief Attaches a special node to a tree
+ * @param tree Tree to attach special node to
+ * @param crit Criteria may be SORT_ASC, SORT_DESC, LIMIT or DISTINCT
+ * @param limit Limit used if LIMIT criteria used
+ * @param Sort string used if SORT criteria is used
+ * @return Pointer to new tree
+ * @note Use the helpers
+ */
+ml_ftree_t* __ml_FtreeSpec( ml_ftree_t* tree,
+                                          ml_select_e crit,
+                                          int limit,
+                                          char* sort )
+{
+    assert( crit == ML_SORT_ASC || crit == ML_LIMIT || crit == ML_SORT_DESC ||
+            crit == ML_DISTINCT );
+    ml_ftree_t* right = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
+    right->criteria = crit;
+    if( crit == ML_LIMIT )
+        right->value.i = limit;
+    else if( crit == ML_SORT_ASC || crit == ML_SORT_DESC )
+        right->value.str = strdup( sort );
+    right->op = ML_OP_NONE;
+    ml_ftree_t* p_parent = ( ml_ftree_t* ) calloc( 1, sizeof( ml_ftree_t ) );
+    p_parent->right = right;
+    p_parent->op = ML_OP_SPECIAL;
+    p_parent->left = tree;
+    return p_parent;
+}
+
+
+/**
+ * @brief Creates and adds the playlist based on a given find tree
+ * @param p_ml Media library object
+ * @param p_tree Find tree to create SELECT
+ */
+void ml_PlaySmartPlaylistBasedOn( media_library_t* p_ml,
+                                                ml_ftree_t* p_tree )
+{
+    assert( p_tree );
+    vlc_array_t* p_results = vlc_array_new();
+    ml_FindAdv( p_ml, p_results, ML_ID, NULL, p_tree );
+    playlist_t* p_pl = pl_Hold( p_ml );
+    playlist_Lock( p_pl );
+    playlist_Clear( p_pl, true );
+    for( int i = 0; i < vlc_array_count( p_results ); i++ )
+    {
+        ml_result_t* p_res = ( ml_result_t* ) vlc_array_item_at_index( p_results, i );
+        input_item_t* p_item;
+        if( p_res )
+        {
+            p_item = ml_CreateInputItem( p_ml, p_res->value.i );
+            playlist_AddInput( p_pl, p_item, PLAYLIST_APPEND,
+                           PLAYLIST_END, true, true );
+        }
+    }
+    playlist_Unlock( p_pl );
+    ml_DestroyResultArray( p_results );
+    vlc_array_destroy( p_results );
+}
+
+/**
+ * @brief Returns a person list of given type
+ * @param p_ml The ML object
+ * @param p_media The Media object
+ * @param i_type The person type
+ * @note This function is thread safe
+ */
+ml_person_t*  ml_GetPersonsFromMedia( media_library_t* p_ml,
+                                                    ml_media_t* p_media,
+                                                    const char *psz_role )
+{
+    VLC_UNUSED( p_ml );
+    assert( p_media != NULL );
+    ml_person_t* p_return = NULL;
+    ml_LockMedia( p_media );
+    ml_person_t* p_person = p_media->p_people;
+    while( p_person )
+    {
+        if( strcmp( p_person->psz_role, psz_role ) == 0 )
+        {
+            int i_ret = ml_CreateAppendPerson( &p_return, p_person );
+            if( i_ret != VLC_SUCCESS )
+            {
+                ml_UnlockMedia( p_media );
+                ml_FreePeople( p_return );
+                return NULL;
+            }
+        }
+        p_person = p_person->p_next;
+    }
+    ml_UnlockMedia( p_media );
+    //TODO: Fill up empty names + clean up list
+    return p_return;
+}
+
+/**
+ * @brief Delete a certain type of people from a media
+ * @param p_media Media to delete from
+ * @param i_type Type of person to delete
+ * @note This function is threadsafe
+ */
+void ml_DeletePersonTypeFromMedia( ml_media_t* p_media, const char *psz_role )
+{
+    assert( p_media );
+    ml_LockMedia( p_media );
+    ml_person_t* p_prev = NULL;
+    ml_person_t* p_person = p_media->p_people;
+
+    while( p_person )
+    {
+        if( strcmp( p_person->psz_role, psz_role ) == 0 )
+        {
+            if( p_prev == NULL )
+            {
+                p_media->p_people = p_person->p_next;
+                p_person->p_next = NULL;
+                ml_FreePeople( p_person );
+                p_person = p_media->p_people;
+            }
+            else
+            {
+                p_prev->p_next = p_person->p_next;
+                p_person->p_next = NULL;
+                ml_FreePeople( p_person );
+                p_person = p_prev->p_next;
+            }
+        }
+        else
+        {
+            p_prev = p_person;
+            p_person = p_person->p_next;
+        }
+    }
+    ml_UnlockMedia( p_media );
+}
+
+#endif /* MEDIA_LIBRARY */
index b96f911b7d2cf66e1247d50fc37cedb6e1bcc969..46e125946a7986596d5711ad20996f44c61450ff 100644 (file)
@@ -395,3 +395,60 @@ vlm_t *vlm_New (vlc_object_t *obj)
      return NULL;
 }
 #endif /* !ENABLE_VLM */
+
+#ifndef MEDIA_LIBRARY
+#include<vlc_media_library.h>
+
+media_library_t* __ml_Hold ( vlc_object_t* p_this )
+{
+    return NULL;
+}
+
+void __ml_Release ( vlc_object_t* p_this )
+{
+    assert( 0 );
+}
+
+media_library_t* __ml_Create ( vlc_object_t *p_this, char* psz_name )
+{
+    return NULL;
+}
+
+void __ml_Destroy( vlc_object_t * p_this )
+{
+    assert( 0 );
+}
+
+ml_media_t* media_New( media_library_t* p_ml, int id, ml_select_e select, bool reload )
+{
+    assert( 0 );
+}
+
+int __ml_UpdateSimple( media_library_t *p_media_library, ml_select_e selected_type,
+                                     const char* psz_lvalue, int id, ... )
+{
+    assert( 0 );
+}
+
+ml_ftree_t* ml_OpConnectChilds( ml_op_e op, ml_ftree_t* left, ml_ftree_t* right )
+{
+    assert( 0 );
+}
+
+ml_ftree_t* __ml_FtreeSpec( ml_ftree_t* tree, ml_select_e crit, int limit,
+                                          char* sort )
+{
+    assert( 0 );
+}
+
+void ml_PlaySmartPlaylistBasedOn( media_library_t* p_ml,
+                                                ml_ftree_t* p_tree )
+{
+    assert( 0 );
+}
+
+void ml_DeletePersonTypeFromMedia( ml_media_t* p_media, const char *psz_role )
+{
+    assert( 0 );
+}
+#endif /* !MEDIA_LIBRARY */