~thopiekar/+junk/vlc-2.0.8-github_community

« back to all changes in this revision

Viewing changes to src/playlist/services_discovery.c

  • Committer: Thomas-Karl Pietrowski
  • Date: 2014-02-25 08:48:22 UTC
  • Revision ID: thopiekar@googlemail.com-20140225084822-52495jnrzv3qlei6
vlc to build against libva-emgd-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * services_discovery.c : Manage playlist services_discovery modules
 
3
 *****************************************************************************
 
4
 * Copyright (C) 1999-2004 VLC authors and VideoLAN
 
5
 * $Id: d8b93d6f12209a043d1d1fd673c94885698d0198 $
 
6
 *
 
7
 * Authors: Clément Stenac <zorglub@videolan.org>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify it
 
10
 * under the terms of the GNU Lesser General Public License as published by
 
11
 * the Free Software Foundation; either version 2.1 of the License, or
 
12
 * (at your option) any later version.
 
13
 *
 
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 Lesser General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Lesser General Public License
 
20
 * along with this program; if not, write to the Free Software Foundation,
 
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 
22
 *****************************************************************************/
 
23
#ifdef HAVE_CONFIG_H
 
24
# include "config.h"
 
25
#endif
 
26
#include <assert.h>
 
27
 
 
28
#include <vlc_common.h>
 
29
#include "vlc_playlist.h"
 
30
#include "vlc_events.h"
 
31
#include <vlc_services_discovery.h>
 
32
#include <vlc_probe.h>
 
33
#include <vlc_modules.h>
 
34
#include "playlist_internal.h"
 
35
#include "../libvlc.h"
 
36
 
 
37
typedef struct
 
38
{
 
39
    char *name;
 
40
    char *longname;
 
41
    int category;
 
42
} vlc_sd_probe_t;
 
43
 
 
44
int vlc_sd_probe_Add (vlc_probe_t *probe, const char *name,
 
45
                      const char *longname, int category)
 
46
{
 
47
    vlc_sd_probe_t names = { strdup(name), strdup(longname), category };
 
48
 
 
49
    if (unlikely (names.name == NULL || names.longname == NULL
 
50
               || vlc_probe_add (probe, &names, sizeof (names))))
 
51
    {
 
52
        free (names.name);
 
53
        free (names.longname);
 
54
        return VLC_ENOMEM;
 
55
    }
 
56
    return VLC_PROBE_CONTINUE;
 
57
}
 
58
 
 
59
#undef vlc_sd_GetNames
 
60
 
 
61
/**
 
62
 * Gets the list of available services discovery plugins.
 
63
 */
 
64
char **vlc_sd_GetNames (vlc_object_t *obj, char ***pppsz_longnames, int **pp_categories)
 
65
{
 
66
    size_t count;
 
67
    vlc_sd_probe_t *tab = vlc_probe (obj, "services probe", &count);
 
68
 
 
69
    if (count == 0)
 
70
    {
 
71
        free (tab);
 
72
        return NULL;
 
73
    }
 
74
 
 
75
    char **names = malloc (sizeof(char *) * (count + 1));
 
76
    char **longnames = malloc (sizeof(char *) * (count + 1));
 
77
    int *categories = malloc(sizeof(int) * (count + 1));
 
78
 
 
79
    if (unlikely (names == NULL || longnames == NULL || categories == NULL))
 
80
        abort();
 
81
    for( size_t i = 0; i < count; i++ )
 
82
    {
 
83
        names[i] = tab[i].name;
 
84
        longnames[i] = tab[i].longname;
 
85
        categories[i] = tab[i].category;
 
86
    }
 
87
    free (tab);
 
88
    names[count] = longnames[count] = NULL;
 
89
    categories[count] = 0;
 
90
    *pppsz_longnames = longnames;
 
91
    if( pp_categories ) *pp_categories = categories;
 
92
    else free( categories );
 
93
    return names;
 
94
}
 
95
 
 
96
 
 
97
static void services_discovery_Destructor ( vlc_object_t *p_obj );
 
98
 
 
99
/*
 
100
 * Services discovery
 
101
 * Basically you just listen to Service discovery event through the
 
102
 * sd's event manager.
 
103
 * That's how the playlist get's Service Discovery information
 
104
 */
 
105
 
 
106
/*******************************************************************//**
 
107
 * Create a Service discovery
 
108
 ***********************************************************************/
 
109
services_discovery_t *vlc_sd_Create( vlc_object_t *p_super,
 
110
                                     const char *cfg )
 
111
{
 
112
    services_discovery_t *p_sd;
 
113
 
 
114
    p_sd = vlc_custom_create( p_super, sizeof( *p_sd ), "services discovery" );
 
115
    if( !p_sd )
 
116
        return NULL;
 
117
    free(config_ChainCreate( &p_sd->psz_name, &p_sd->p_cfg, cfg ));
 
118
 
 
119
    vlc_event_manager_t *em = &p_sd->event_manager;
 
120
    vlc_event_manager_init( em, p_sd );
 
121
    vlc_event_manager_register_event_type(em, vlc_ServicesDiscoveryItemAdded);
 
122
    vlc_event_manager_register_event_type(em, vlc_ServicesDiscoveryItemRemoved);
 
123
    vlc_event_manager_register_event_type(em, vlc_ServicesDiscoveryStarted);
 
124
    vlc_event_manager_register_event_type(em, vlc_ServicesDiscoveryEnded);
 
125
 
 
126
    vlc_object_set_destructor( p_sd, services_discovery_Destructor );
 
127
    return p_sd;
 
128
}
 
129
 
 
130
/*******************************************************************//**
 
131
 * Start a Service Discovery
 
132
 ***********************************************************************/
 
133
bool vlc_sd_Start ( services_discovery_t * p_sd )
 
134
{
 
135
    assert(!p_sd->p_module);
 
136
 
 
137
    p_sd->p_module = module_need( p_sd, "services_discovery",
 
138
                                  p_sd->psz_name, true );
 
139
    if( p_sd->p_module == NULL )
 
140
    {
 
141
        msg_Err( p_sd, "no suitable services discovery module" );
 
142
        return false;
 
143
    }
 
144
 
 
145
    vlc_event_t event = {
 
146
        .type = vlc_ServicesDiscoveryStarted
 
147
    };
 
148
    vlc_event_send( &p_sd->event_manager, &event );
 
149
    return true;
 
150
}
 
151
 
 
152
/*******************************************************************//**
 
153
 * Stop a Service Discovery
 
154
 ***********************************************************************/
 
155
void vlc_sd_Stop ( services_discovery_t * p_sd )
 
156
{
 
157
    vlc_event_t event = {
 
158
        .type = vlc_ServicesDiscoveryEnded
 
159
    };
 
160
 
 
161
    vlc_event_send( &p_sd->event_manager, &event );
 
162
 
 
163
    module_unneed( p_sd, p_sd->p_module );
 
164
    p_sd->p_module = NULL;
 
165
}
 
166
 
 
167
/*******************************************************************//**
 
168
 * Destroy a Service Discovery
 
169
 ***********************************************************************/
 
170
void vlc_sd_Destroy( services_discovery_t *p_sd )
 
171
{
 
172
    config_ChainDestroy( p_sd->p_cfg );
 
173
    free( p_sd->psz_name );
 
174
    vlc_object_release( p_sd );
 
175
}
 
176
 
 
177
/*******************************************************************//**
 
178
 * Destructor of the Service Discovery
 
179
 ***********************************************************************/
 
180
static void services_discovery_Destructor ( vlc_object_t *p_obj )
 
181
{
 
182
    services_discovery_t * p_sd = (services_discovery_t *)p_obj;
 
183
    assert(!p_sd->p_module); /* Forgot to call Stop */
 
184
    vlc_event_manager_fini( &p_sd->event_manager );
 
185
}
 
186
 
 
187
/*******************************************************************//**
 
188
 * Get the Localized Name
 
189
 *
 
190
 * This is useful for interfaces and libVLC
 
191
 ***********************************************************************/
 
192
char *
 
193
services_discovery_GetLocalizedName ( services_discovery_t * p_sd )
 
194
{
 
195
    return strdup( module_get_name( p_sd->p_module, true ) );
 
196
}
 
197
 
 
198
/*******************************************************************//**
 
199
 * Getter for the EventManager
 
200
 *
 
201
 * You can receive event notification
 
202
 * This is the preferred way to get new items
 
203
 ***********************************************************************/
 
204
vlc_event_manager_t *
 
205
services_discovery_EventManager ( services_discovery_t * p_sd )
 
206
{
 
207
    return &p_sd->event_manager;
 
208
}
 
209
 
 
210
/*******************************************************************//**
 
211
 * Add an item to the Service Discovery listing
 
212
 ***********************************************************************/
 
213
void
 
214
services_discovery_AddItem ( services_discovery_t * p_sd, input_item_t * p_item,
 
215
                             const char * psz_category )
 
216
{
 
217
    vlc_event_t event;
 
218
    event.type = vlc_ServicesDiscoveryItemAdded;
 
219
    event.u.services_discovery_item_added.p_new_item = p_item;
 
220
    event.u.services_discovery_item_added.psz_category = psz_category;
 
221
 
 
222
    vlc_event_send( &p_sd->event_manager, &event );
 
223
}
 
224
 
 
225
/*******************************************************************//**
 
226
 * Remove an item from the Service Discovery listing
 
227
 ***********************************************************************/
 
228
void
 
229
services_discovery_RemoveItem ( services_discovery_t * p_sd, input_item_t * p_item )
 
230
{
 
231
    vlc_event_t event;
 
232
    event.type = vlc_ServicesDiscoveryItemRemoved;
 
233
    event.u.services_discovery_item_removed.p_item = p_item;
 
234
 
 
235
    vlc_event_send( &p_sd->event_manager, &event );
 
236
}
 
237
 
 
238
/*
 
239
 * Playlist - Services discovery bridge
 
240
 */
 
241
 
 
242
struct vlc_sd_internal_t
 
243
{
 
244
    /* the playlist items for category and onelevel */
 
245
    playlist_item_t      *p_node;
 
246
    services_discovery_t *p_sd; /**< Loaded service discovery modules */
 
247
    char                 *psz_name;
 
248
};
 
249
 
 
250
 /* A new item has been added to a certain sd */
 
251
static void playlist_sd_item_added( const vlc_event_t * p_event, void * user_data )
 
252
{
 
253
    input_item_t * p_input = p_event->u.services_discovery_item_added.p_new_item;
 
254
    const char * psz_cat = p_event->u.services_discovery_item_added.psz_category;
 
255
    playlist_item_t * p_parent = user_data;
 
256
    playlist_t * p_playlist = p_parent->p_playlist;
 
257
 
 
258
    msg_Dbg( p_playlist, "Adding %s in %s",
 
259
                p_input->psz_name ? p_input->psz_name : "(null)",
 
260
                psz_cat ? psz_cat : "(null)" );
 
261
 
 
262
    PL_LOCK;
 
263
    /* If p_parent is in root category (this is clearly a hack) and we have a cat */
 
264
    if( !EMPTY_STR(psz_cat) )
 
265
    {
 
266
        /* */
 
267
        playlist_item_t * p_cat;
 
268
        p_cat = playlist_ChildSearchName( p_parent, psz_cat );
 
269
        if( !p_cat )
 
270
        {
 
271
            p_cat = playlist_NodeCreate( p_playlist, psz_cat,
 
272
                                         p_parent, PLAYLIST_END, 0, NULL );
 
273
            p_cat->i_flags &= ~PLAYLIST_SKIP_FLAG;
 
274
        }
 
275
        p_parent = p_cat;
 
276
    }
 
277
 
 
278
    playlist_NodeAddInput( p_playlist, p_input, p_parent,
 
279
                           PLAYLIST_APPEND, PLAYLIST_END,
 
280
                           pl_Locked );
 
281
    PL_UNLOCK;
 
282
}
 
283
 
 
284
 /* A new item has been removed from a certain sd */
 
285
static void playlist_sd_item_removed( const vlc_event_t * p_event, void * user_data )
 
286
{
 
287
    input_item_t * p_input = p_event->u.services_discovery_item_removed.p_item;
 
288
    playlist_item_t * p_sd_node = user_data;
 
289
    playlist_t *p_playlist = p_sd_node->p_playlist;
 
290
 
 
291
    PL_LOCK;
 
292
    playlist_item_t *p_item =
 
293
        playlist_ItemFindFromInputAndRoot( p_playlist, p_input,
 
294
                                           p_sd_node, false );
 
295
    if( !p_item )
 
296
    {
 
297
        PL_UNLOCK; return;
 
298
    }
 
299
    playlist_item_t *p_parent = p_item->p_parent;
 
300
    /* if the item was added under a category and the category node
 
301
       becomes empty, delete that node as well */
 
302
    if( p_parent->i_children > 1 || p_parent == p_sd_node )
 
303
        playlist_DeleteItem( p_playlist, p_item, true );
 
304
    else
 
305
        playlist_NodeDelete( p_playlist, p_parent, true, true );
 
306
    PL_UNLOCK;
 
307
}
 
308
 
 
309
int playlist_ServicesDiscoveryAdd( playlist_t *p_playlist,
 
310
                                   const char *psz_name )
 
311
{
 
312
    /* Perform the addition */
 
313
    services_discovery_t *p_sd;
 
314
 
 
315
    msg_Dbg( p_playlist, "adding services_discovery %s...", psz_name );
 
316
    p_sd = vlc_sd_Create( VLC_OBJECT(p_playlist), psz_name );
 
317
    if( !p_sd )
 
318
        return VLC_ENOMEM;
 
319
 
 
320
    /* Free in playlist_ServicesDiscoveryRemove */
 
321
    vlc_sd_internal_t * p_sds = malloc( sizeof(*p_sds) );
 
322
    if( !p_sds )
 
323
    {
 
324
        vlc_sd_Destroy( p_sd );
 
325
        return VLC_ENOMEM;
 
326
    }
 
327
 
 
328
    playlist_item_t *p_node;
 
329
 
 
330
    /* Look for configuration chain "longname" */
 
331
    const char *psz_longname = "?";
 
332
    if( p_sd->p_cfg )
 
333
    {
 
334
        config_chain_t *cfg = p_sd->p_cfg;
 
335
        while( cfg )
 
336
        {
 
337
            if( cfg->psz_name && !strcmp( cfg->psz_name, "longname" ) )
 
338
            {
 
339
                psz_longname = cfg->psz_value;
 
340
                break;
 
341
            }
 
342
            cfg = cfg->p_next;
 
343
        }
 
344
    }
 
345
 
 
346
    PL_LOCK;
 
347
    p_node = playlist_NodeCreate( p_playlist, psz_longname,
 
348
                                  p_playlist->p_root, PLAYLIST_END, 0, NULL );
 
349
    PL_UNLOCK;
 
350
 
 
351
    vlc_event_manager_t *em = services_discovery_EventManager( p_sd );
 
352
    vlc_event_attach( em, vlc_ServicesDiscoveryItemAdded,
 
353
                      playlist_sd_item_added, p_node );
 
354
 
 
355
    vlc_event_attach( em, vlc_ServicesDiscoveryItemRemoved,
 
356
                      playlist_sd_item_removed, p_node );
 
357
 
 
358
    if( !vlc_sd_Start( p_sd ) )
 
359
    {
 
360
        vlc_sd_Destroy( p_sd );
 
361
        free( p_sds );
 
362
        return VLC_EGENERIC;
 
363
    }
 
364
 
 
365
    p_sds->p_sd = p_sd;
 
366
    p_sds->p_node = p_node;
 
367
    p_sds->psz_name = strdup( psz_name );
 
368
 
 
369
    PL_LOCK;
 
370
    TAB_APPEND( pl_priv(p_playlist)->i_sds, pl_priv(p_playlist)->pp_sds, p_sds );
 
371
    PL_UNLOCK;
 
372
 
 
373
    return VLC_SUCCESS;
 
374
}
 
375
 
 
376
int playlist_ServicesDiscoveryRemove( playlist_t * p_playlist,
 
377
                                      const char *psz_name )
 
378
{
 
379
    playlist_private_t *priv = pl_priv( p_playlist );
 
380
    vlc_sd_internal_t * p_sds = NULL;
 
381
 
 
382
    PL_LOCK;
 
383
    for( int i = 0; i < priv->i_sds; i++ )
 
384
    {
 
385
        if( !strcmp( psz_name, priv->pp_sds[i]->psz_name ) )
 
386
        {
 
387
            p_sds = priv->pp_sds[i];
 
388
            REMOVE_ELEM( priv->pp_sds, priv->i_sds, i );
 
389
            break;
 
390
        }
 
391
    }
 
392
    PL_UNLOCK;
 
393
 
 
394
    if( !p_sds )
 
395
    {
 
396
        msg_Warn( p_playlist, "discovery %s is not loaded", psz_name );
 
397
        return VLC_EGENERIC;
 
398
    }
 
399
 
 
400
    services_discovery_t *p_sd = p_sds->p_sd;
 
401
    assert( p_sd );
 
402
 
 
403
    vlc_sd_Stop( p_sd );
 
404
 
 
405
    vlc_event_detach( services_discovery_EventManager( p_sd ),
 
406
                        vlc_ServicesDiscoveryItemAdded,
 
407
                        playlist_sd_item_added,
 
408
                        p_sds->p_node );
 
409
 
 
410
    vlc_event_detach( services_discovery_EventManager( p_sd ),
 
411
                        vlc_ServicesDiscoveryItemRemoved,
 
412
                        playlist_sd_item_removed,
 
413
                        p_sds->p_node );
 
414
 
 
415
    /* Remove the sd playlist node if it exists */
 
416
    PL_LOCK;
 
417
    playlist_NodeDelete( p_playlist, p_sds->p_node, true, false );
 
418
    PL_UNLOCK;
 
419
 
 
420
    vlc_sd_Destroy( p_sd );
 
421
    free( p_sds->psz_name );
 
422
    free( p_sds );
 
423
 
 
424
    return VLC_SUCCESS;
 
425
}
 
426
 
 
427
bool playlist_IsServicesDiscoveryLoaded( playlist_t * p_playlist,
 
428
                                         const char *psz_name )
 
429
{
 
430
    playlist_private_t *priv = pl_priv( p_playlist );
 
431
    bool found = false;
 
432
    PL_LOCK;
 
433
 
 
434
    for( int i = 0; i < priv->i_sds; i++ )
 
435
    {
 
436
        vlc_sd_internal_t *sd = priv->pp_sds[i];
 
437
 
 
438
        if( sd->psz_name && !strcmp( psz_name, sd->psz_name ) )
 
439
        {
 
440
            found = true;
 
441
            break;
 
442
        }
 
443
    }
 
444
    PL_UNLOCK;
 
445
    return found;
 
446
}
 
447
 
 
448
int playlist_ServicesDiscoveryControl( playlist_t *p_playlist, const char *psz_name, int i_control, ... )
 
449
{
 
450
    playlist_private_t *priv = pl_priv( p_playlist );
 
451
    int i_ret = VLC_EGENERIC;
 
452
    int i;
 
453
 
 
454
    PL_LOCK;
 
455
    for( i = 0; i < priv->i_sds; i++ )
 
456
    {
 
457
        vlc_sd_internal_t *sd = priv->pp_sds[i];
 
458
        if( sd->psz_name && !strcmp( psz_name, sd->psz_name ) )
 
459
        {
 
460
            va_list args;
 
461
            va_start( args, i_control );
 
462
            i_ret = vlc_sd_control( sd->p_sd, i_control, args );
 
463
            va_end( args );
 
464
            break;
 
465
        }
 
466
    }
 
467
 
 
468
    assert( i != priv->i_sds );
 
469
    PL_UNLOCK;
 
470
 
 
471
    return i_ret;
 
472
}
 
473
 
 
474
void playlist_ServicesDiscoveryKillAll( playlist_t *p_playlist )
 
475
{
 
476
    playlist_private_t *priv = pl_priv( p_playlist );
 
477
 
 
478
    while( priv->i_sds > 0 )
 
479
        playlist_ServicesDiscoveryRemove( p_playlist,
 
480
                                          priv->pp_sds[0]->psz_name );
 
481
}