media_discoverer.c 14.2 KB
Newer Older
1 2 3
/*****************************************************************************
 * media_discoverer.c: libvlc new API media discoverer functions
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2007 VLC authors and VideoLAN
5 6 7 8
 * $Id$
 *
 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser 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.
22 23
 *****************************************************************************/

24 25 26 27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

28
#include <assert.h>
29 30 31 32 33 34 35 36 37 38 39

#include <vlc/libvlc.h>
#include <vlc/libvlc_media.h>
#include <vlc/libvlc_media_list.h>
#include <vlc/libvlc_media_discoverer.h>
#include <vlc/libvlc_events.h>

#include <vlc_services_discovery.h>

#include "libvlc_internal.h"
#include "media_internal.h" // libvlc_media_new_from_input_item()
40
#include "media_list_internal.h" // libvlc_media_list_internal_add_media()
41 42 43 44 45 46 47 48 49 50

struct libvlc_media_discoverer_t
{
    libvlc_event_manager_t * p_event_manager;
    libvlc_instance_t *      p_libvlc_instance;
    services_discovery_t *   p_sd;
    libvlc_media_list_t *    p_mlist;
    bool                     running;
    vlc_dictionary_t         catname_to_submedialist;
};
51 52 53 54

/*
 * Private functions
 */
55

56 57 58 59 60 61 62 63
/**************************************************************************
 *       services_discovery_item_added (Private) (VLC event callback)
 **************************************************************************/

static void services_discovery_item_added( const vlc_event_t * p_event,
                                           void * user_data )
{
    input_item_t * p_item = p_event->u.services_discovery_item_added.p_new_item;
64
    const char * psz_cat = p_event->u.services_discovery_item_added.psz_category;
65
    libvlc_media_t * p_md;
66
    libvlc_media_discoverer_t * p_mdis = user_data;
67
    libvlc_media_list_t * p_mlist = p_mdis->p_mlist;
68

69 70
    p_md = libvlc_media_new_from_input_item( p_mdis->p_libvlc_instance,
                                             p_item );
71

72 73 74 75 76
    /* If we have a category, that mean we have to group the items having
     * that category in a media_list. */
    if( psz_cat )
    {
        p_mlist = vlc_dictionary_value_for_key( &p_mdis->catname_to_submedialist, psz_cat );
77

78 79
        if( p_mlist == kVLCDictionaryNotFound )
        {
80
            libvlc_media_t * p_catmd;
81
            p_catmd = libvlc_media_new_as_node( p_mdis->p_libvlc_instance, psz_cat );
82
            p_mlist = libvlc_media_subitems( p_catmd );
83
            p_mlist->b_read_only = true;
84

85
            /* Insert the newly created mlist in our dictionary */
86
            vlc_dictionary_insert( &p_mdis->catname_to_submedialist, psz_cat, p_mlist );
87

88
            /* Insert the md into the root list */
89
            libvlc_media_list_lock( p_mdis->p_mlist );
90
            libvlc_media_list_internal_add_media( p_mdis->p_mlist, p_catmd );
91
            libvlc_media_list_unlock( p_mdis->p_mlist );
92 93 94

            /* We don't release the mlist cause the dictionary
             * doesn't retain the object. But we release the md. */
95
            libvlc_media_release( p_catmd );
96 97
        }
    }
98 99

    libvlc_media_list_lock( p_mlist );
100
    libvlc_media_list_internal_add_media( p_mlist, p_md );
101
    libvlc_media_list_unlock( p_mlist );
102 103

    libvlc_media_release( p_md );
104 105 106 107 108 109 110 111 112
}

/**************************************************************************
 *       services_discovery_item_removed (Private) (VLC event callback)
 **************************************************************************/

static void services_discovery_item_removed( const vlc_event_t * p_event,
                                             void * user_data )
{
113
    input_item_t * p_item = p_event->u.services_discovery_item_added.p_new_item;
114
    libvlc_media_t * p_md;
115 116
    libvlc_media_discoverer_t * p_mdis = user_data;

117
    int i, count = libvlc_media_list_count( p_mdis->p_mlist );
118 119 120
    libvlc_media_list_lock( p_mdis->p_mlist );
    for( i = 0; i < count; i++ )
    {
121
        p_md = libvlc_media_list_item_at_index( p_mdis->p_mlist, i );
122 123
        if( p_md->p_input_item == p_item )
        {
124
            libvlc_media_list_internal_remove_index( p_mdis->p_mlist, i );
125 126 127 128 129 130
            break;
        }
    }
    libvlc_media_list_unlock( p_mdis->p_mlist );
}

131 132 133 134 135 136
/**************************************************************************
 *       services_discovery_removeall (Private) (VLC event callback)
 **************************************************************************/
static void services_discovery_removeall( const vlc_event_t * p_event,
                                             void * user_data )
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
137
    VLC_UNUSED(p_event);
138 139 140 141 142
    libvlc_media_discoverer_t * p_mdis = user_data;

    libvlc_media_list_lock( p_mdis->p_mlist );
    for( int i = 0; i < libvlc_media_list_count( p_mdis->p_mlist ); i++ )
    {
143
        libvlc_media_list_internal_remove_index( p_mdis->p_mlist, i );
144 145 146 147
    }
    libvlc_media_list_unlock( p_mdis->p_mlist );
}

148 149 150 151 152 153 154
/**************************************************************************
 *       services_discovery_started (Private) (VLC event callback)
 **************************************************************************/

static void services_discovery_started( const vlc_event_t * p_event,
                                        void * user_data )
{
155
    VLC_UNUSED(p_event);
156 157
    libvlc_media_discoverer_t * p_mdis = user_data;
    libvlc_event_t event;
158
    p_mdis->running = true;
159 160 161 162 163 164 165 166 167 168 169
    event.type = libvlc_MediaDiscovererStarted;
    libvlc_event_send( p_mdis->p_event_manager, &event );
}

/**************************************************************************
 *       services_discovery_ended (Private) (VLC event callback)
 **************************************************************************/

static void services_discovery_ended( const vlc_event_t * p_event,
                                      void * user_data )
{
170
    VLC_UNUSED(p_event);
171
    libvlc_media_discoverer_t * p_mdis = user_data;
172
    libvlc_media_list_t * p_mlist = p_mdis->p_mlist;
173
    libvlc_event_t event;
174

175
    p_mdis->running = false;
176 177 178 179 180

    libvlc_media_list_lock( p_mlist );
    libvlc_media_list_internal_end_reached( p_mlist );
    libvlc_media_list_unlock( p_mlist );

181 182
    event.type = libvlc_MediaDiscovererEnded;
    libvlc_event_send( p_mdis->p_event_manager, &event );
183 184 185 186 187 188 189 190 191 192
}

/*
 * Public libvlc functions
 */

/**************************************************************************
 *       new (Public)
 **************************************************************************/
libvlc_media_discoverer_t *
193
libvlc_media_discoverer_new( libvlc_instance_t * p_inst, const char * psz_name )
194
{
195 196 197
    /* podcast SD is a hack and only works with custom playlist callbacks. */
    if( !strncasecmp( psz_name, "podcast", 7 ) )
        return NULL;
198

199
    libvlc_media_discoverer_t *p_mdis = malloc(sizeof(*p_mdis));
200
    if( unlikely(!p_mdis) )
201
    {
202
        libvlc_printerr( "Not enough memory" );
203 204 205 206
        return NULL;
    }

    p_mdis->p_libvlc_instance = p_inst;
207
    p_mdis->p_mlist = libvlc_media_list_new( p_inst );
208 209
    p_mdis->p_mlist->b_read_only = true;
    p_mdis->running = false;
210

211 212
    vlc_dictionary_init( &p_mdis->catname_to_submedialist, 0 );

213
    p_mdis->p_event_manager = libvlc_event_manager_new( p_mdis );
214 215 216 217 218
    if( unlikely(p_mdis->p_event_manager == NULL) )
    {
        free( p_mdis );
        return NULL;
    }
219 220

    libvlc_event_manager_register_event_type( p_mdis->p_event_manager,
221
            libvlc_MediaDiscovererStarted );
222
    libvlc_event_manager_register_event_type( p_mdis->p_event_manager,
223
            libvlc_MediaDiscovererEnded );
224

225 226 227
    p_mdis->p_sd = vlc_sd_Create( (vlc_object_t*)p_inst->p_libvlc_int,
                                  psz_name );
    if( unlikely(p_mdis->p_sd == NULL) )
228
    {
229
        libvlc_printerr( "%s: no such discovery module found", psz_name );
230 231
        libvlc_media_list_release( p_mdis->p_mlist );
        libvlc_event_manager_release( p_mdis->p_event_manager );
232
        free( p_mdis );
233 234 235 236 237 238 239 240 241 242 243
        return NULL;
    }

    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
                      vlc_ServicesDiscoveryItemAdded,
                      services_discovery_item_added,
                      p_mdis );
    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
                      vlc_ServicesDiscoveryItemRemoved,
                      services_discovery_item_removed,
                      p_mdis );
244 245 246 247 248 249 250 251
    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
                      vlc_ServicesDiscoveryStarted,
                      services_discovery_started,
                      p_mdis );
    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
                      vlc_ServicesDiscoveryEnded,
                      services_discovery_ended,
                      p_mdis );
252 253 254 255
    vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
                      vlc_ServicesDiscoveryItemRemoveAll,
                      services_discovery_removeall,
                      p_mdis );
256

257
    libvlc_retain( p_inst );
258 259 260 261 262 263 264 265 266
    return p_mdis;
}

/**************************************************************************
 *       start (Public)
 **************************************************************************/
LIBVLC_API int
libvlc_media_discoverer_start( libvlc_media_discoverer_t * p_mdis )
{
267
    /* Here we go */
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
    return vlc_sd_Start( p_mdis->p_sd ) ? 0 : -1;
}

/**************************************************************************
 *       stop (Public)
 **************************************************************************/
LIBVLC_API void
libvlc_media_discoverer_stop( libvlc_media_discoverer_t * p_mdis )
{
    return vlc_sd_Stop( p_mdis->p_sd );
}

/**************************************************************************
 *       new_from_name (Public)
 *
 * \deprecated Use libvlc_media_discoverer_new and libvlc_media_discoverer_start
 **************************************************************************/
libvlc_media_discoverer_t *
libvlc_media_discoverer_new_from_name( libvlc_instance_t * p_inst,
                                       const char * psz_name )
{
    libvlc_media_discoverer_t *p_mdis = libvlc_media_discoverer_new( p_inst, psz_name );

    if( !p_mdis )
        return NULL;

    if( libvlc_media_discoverer_start( p_mdis ) != 0)
295
    {
296
        libvlc_media_discoverer_release( p_mdis );
297 298
        return NULL;
    }
299 300 301 302 303 304 305 306 307 308

    return p_mdis;
}

/**************************************************************************
 * release (Public)
 **************************************************************************/
void
libvlc_media_discoverer_release( libvlc_media_discoverer_t * p_mdis )
{
309 310
    int i;

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
                     vlc_ServicesDiscoveryItemAdded,
                     services_discovery_item_added,
                     p_mdis );
    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
                     vlc_ServicesDiscoveryItemRemoved,
                     services_discovery_item_removed,
                     p_mdis );
    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
                     vlc_ServicesDiscoveryStarted,
                     services_discovery_started,
                     p_mdis );
    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
                     vlc_ServicesDiscoveryEnded,
                     services_discovery_ended,
                     p_mdis );
327 328 329 330
    vlc_event_detach( services_discovery_EventManager( p_mdis->p_sd ),
                     vlc_ServicesDiscoveryItemRemoveAll,
                     services_discovery_removeall,
                     p_mdis );
331

332
    libvlc_media_list_release( p_mdis->p_mlist );
333

334 335 336 337
    if( p_mdis->running )
        vlc_sd_Stop( p_mdis->p_sd );

    vlc_sd_Destroy( p_mdis->p_sd );
338 339 340 341 342 343 344 345 346 347 348

    /* Free catname_to_submedialist and all the mlist */
    char ** all_keys = vlc_dictionary_all_keys( &p_mdis->catname_to_submedialist );
    for( i = 0; all_keys[i]; i++ )
    {
        libvlc_media_list_t * p_catmlist = vlc_dictionary_value_for_key( &p_mdis->catname_to_submedialist, all_keys[i] );
        libvlc_media_list_release( p_catmlist );
        free( all_keys[i] );
    }
    free( all_keys );

349
    vlc_dictionary_clear( &p_mdis->catname_to_submedialist, NULL, NULL );
350
    libvlc_event_manager_release( p_mdis->p_event_manager );
351
    libvlc_release( p_mdis->p_libvlc_instance );
352

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    free( p_mdis );
}

/**************************************************************************
 * localized_name (Public)
 **************************************************************************/
char *
libvlc_media_discoverer_localized_name( libvlc_media_discoverer_t * p_mdis )
{
    return services_discovery_GetLocalizedName( p_mdis->p_sd );
}

/**************************************************************************
 * media_list (Public)
 **************************************************************************/
libvlc_media_list_t *
libvlc_media_discoverer_media_list( libvlc_media_discoverer_t * p_mdis )
{
371 372
    libvlc_media_list_retain( p_mdis->p_mlist );
    return p_mdis->p_mlist;
373 374
}

375 376 377 378 379 380 381 382 383
/**************************************************************************
 * event_manager (Public)
 **************************************************************************/
libvlc_event_manager_t *
libvlc_media_discoverer_event_manager( libvlc_media_discoverer_t * p_mdis )
{
    return p_mdis->p_event_manager;
}

384 385 386 387

/**************************************************************************
 * running (Public)
 **************************************************************************/
388
int
389 390 391 392
libvlc_media_discoverer_is_running( libvlc_media_discoverer_t * p_mdis )
{
    return p_mdis->running;
}