1 /*****************************************************************************
2 * services_discovery.c : Manage playlist services_discovery modules
3 *****************************************************************************
4 * Copyright (C) 1999-2004 the VideoLAN team
7 * Authors: 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 *****************************************************************************/
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"
44 int vlc_sd_probe_Add (vlc_probe_t
*probe
, const char *name
,
45 const char *longname
, int category
)
47 vlc_sd_probe_t names
= { strdup(name
), strdup(longname
), category
};
49 if (unlikely (names
.name
== NULL
|| names
.longname
== NULL
50 || vlc_probe_add (probe
, &names
, sizeof (names
))))
53 free (names
.longname
);
56 return VLC_PROBE_CONTINUE
;
59 #undef vlc_sd_GetNames
62 * Gets the list of available services discovery plugins.
64 char **vlc_sd_GetNames (vlc_object_t
*obj
, char ***pppsz_longnames
, int **pp_categories
)
67 vlc_sd_probe_t
*tab
= vlc_probe (obj
, "services probe", &count
);
75 char **names
= malloc (sizeof(char *) * (count
+ 1));
76 char **longnames
= malloc (sizeof(char *) * (count
+ 1));
77 int *categories
= malloc(sizeof(int) * (count
+ 1));
79 if (unlikely (names
== NULL
|| longnames
== NULL
|| categories
== NULL
))
81 for( size_t i
= 0; i
< count
; i
++ )
83 names
[i
] = tab
[i
].name
;
84 longnames
[i
] = tab
[i
].longname
;
85 categories
[i
] = tab
[i
].category
;
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
);
97 static void services_discovery_Destructor ( vlc_object_t
*p_obj
);
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
106 /***********************************************************************
108 ***********************************************************************/
109 services_discovery_t
*vlc_sd_Create( vlc_object_t
*p_super
,
112 services_discovery_t
*p_sd
;
114 p_sd
= vlc_custom_create( p_super
, sizeof( *p_sd
), VLC_OBJECT_GENERIC
,
115 "services discovery" );
118 free(config_ChainCreate( &p_sd
->psz_name
, &p_sd
->p_cfg
, cfg
));
120 vlc_event_manager_t
*em
= &p_sd
->event_manager
;
121 vlc_event_manager_init( em
, p_sd
, (vlc_object_t
*)p_sd
);
122 vlc_event_manager_register_event_type(em
, vlc_ServicesDiscoveryItemAdded
);
123 vlc_event_manager_register_event_type(em
, vlc_ServicesDiscoveryItemRemoved
);
124 vlc_event_manager_register_event_type(em
, vlc_ServicesDiscoveryStarted
);
125 vlc_event_manager_register_event_type(em
, vlc_ServicesDiscoveryEnded
);
127 vlc_object_set_destructor( p_sd
, services_discovery_Destructor
);
128 vlc_object_attach( p_sd
, p_super
);
133 /***********************************************************************
135 ***********************************************************************/
136 bool vlc_sd_Start ( services_discovery_t
* p_sd
)
138 assert(!p_sd
->p_module
);
140 p_sd
->p_module
= module_need( p_sd
, "services_discovery",
141 p_sd
->psz_name
, true );
142 if( p_sd
->p_module
== NULL
)
144 msg_Err( p_sd
, "no suitable services discovery module" );
148 vlc_event_t event
= {
149 .type
= vlc_ServicesDiscoveryStarted
151 vlc_event_send( &p_sd
->event_manager
, &event
);
155 /***********************************************************************
157 ***********************************************************************/
158 void vlc_sd_Stop ( services_discovery_t
* p_sd
)
160 vlc_event_t event
= {
161 .type
= vlc_ServicesDiscoveryEnded
164 vlc_event_send( &p_sd
->event_manager
, &event
);
166 module_unneed( p_sd
, p_sd
->p_module
);
167 p_sd
->p_module
= NULL
;
170 void vlc_sd_Destroy( services_discovery_t
*p_sd
)
172 config_ChainDestroy( p_sd
->p_cfg
);
173 free( p_sd
->psz_name
);
174 vlc_object_release( p_sd
);
177 /***********************************************************************
179 ***********************************************************************/
180 static void services_discovery_Destructor ( vlc_object_t
*p_obj
)
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
);
187 /***********************************************************************
189 ***********************************************************************/
191 services_discovery_GetLocalizedName ( services_discovery_t
* p_sd
)
193 return strdup( module_get_name( p_sd
->p_module
, true ) );
196 /***********************************************************************
198 ***********************************************************************/
199 vlc_event_manager_t
*
200 services_discovery_EventManager ( services_discovery_t
* p_sd
)
202 return &p_sd
->event_manager
;
205 /***********************************************************************
207 ***********************************************************************/
209 services_discovery_AddItem ( services_discovery_t
* p_sd
, input_item_t
* p_item
,
210 const char * psz_category
)
213 event
.type
= vlc_ServicesDiscoveryItemAdded
;
214 event
.u
.services_discovery_item_added
.p_new_item
= p_item
;
215 event
.u
.services_discovery_item_added
.psz_category
= psz_category
;
217 vlc_event_send( &p_sd
->event_manager
, &event
);
220 /***********************************************************************
222 ***********************************************************************/
224 services_discovery_RemoveItem ( services_discovery_t
* p_sd
, input_item_t
* p_item
)
227 event
.type
= vlc_ServicesDiscoveryItemRemoved
;
228 event
.u
.services_discovery_item_removed
.p_item
= p_item
;
230 vlc_event_send( &p_sd
->event_manager
, &event
);
234 * Playlist - Services discovery bridge
237 struct vlc_sd_internal_t
239 /* the playlist items for category and onelevel */
240 playlist_item_t
*p_node
;
241 services_discovery_t
*p_sd
; /**< Loaded service discovery modules */
245 /* A new item has been added to a certain sd */
246 static void playlist_sd_item_added( const vlc_event_t
* p_event
, void * user_data
)
248 input_item_t
* p_input
= p_event
->u
.services_discovery_item_added
.p_new_item
;
249 const char * psz_cat
= p_event
->u
.services_discovery_item_added
.psz_category
;
250 playlist_item_t
* p_parent
= user_data
;
251 playlist_t
* p_playlist
= p_parent
->p_playlist
;
253 msg_Dbg( p_playlist
, "Adding %s in %s",
254 p_input
->psz_name
? p_input
->psz_name
: "(null)",
255 psz_cat
? psz_cat
: "(null)" );
258 /* If p_parent is in root category (this is clearly a hack) and we have a cat */
259 if( !EMPTY_STR(psz_cat
) )
262 playlist_item_t
* p_cat
;
263 p_cat
= playlist_ChildSearchName( p_parent
, psz_cat
);
266 p_cat
= playlist_NodeCreate( p_playlist
, psz_cat
,
267 p_parent
, PLAYLIST_END
, 0, NULL
);
268 p_cat
->i_flags
&= ~PLAYLIST_SKIP_FLAG
;
273 playlist_NodeAddInput( p_playlist
, p_input
, p_parent
,
274 PLAYLIST_APPEND
, PLAYLIST_END
,
279 /* A new item has been removed from a certain sd */
280 static void playlist_sd_item_removed( const vlc_event_t
* p_event
, void * user_data
)
282 input_item_t
* p_input
= p_event
->u
.services_discovery_item_removed
.p_item
;
283 playlist_item_t
* p_sd_node
= user_data
;
284 playlist_t
*p_playlist
= p_sd_node
->p_playlist
;
287 playlist_item_t
*p_item
=
288 playlist_ItemFindFromInputAndRoot( p_playlist
, p_input
,
294 playlist_item_t
*p_parent
= p_item
->p_parent
;
295 /* if the item was added under a category and the category node
296 becomes empty, delete that node as well */
297 if( p_parent
->i_children
> 1 || p_parent
== p_sd_node
)
298 playlist_DeleteItem( p_playlist
, p_item
, true );
300 playlist_NodeDelete( p_playlist
, p_parent
, true, true );
304 int playlist_ServicesDiscoveryAdd( playlist_t
*p_playlist
,
305 const char *psz_name
)
307 /* Perform the addition */
308 services_discovery_t
*p_sd
;
310 msg_Dbg( p_playlist
, "adding services_discovery %s...", psz_name
);
311 p_sd
= vlc_sd_Create( VLC_OBJECT(p_playlist
), psz_name
);
315 /* Free in playlist_ServicesDiscoveryRemove */
316 vlc_sd_internal_t
* p_sds
= malloc( sizeof(*p_sds
) );
319 vlc_sd_Destroy( p_sd
);
323 playlist_item_t
*p_node
;
325 /* Look for configuration chain "longname" */
326 const char *psz_longname
= "?";
329 config_chain_t
*cfg
= p_sd
->p_cfg
;
332 if( cfg
->psz_name
&& !strcmp( cfg
->psz_name
, "longname" ) )
334 psz_longname
= cfg
->psz_value
;
342 p_node
= playlist_NodeCreate( p_playlist
, psz_longname
,
343 p_playlist
->p_root
, PLAYLIST_END
, 0, NULL
);
346 vlc_event_manager_t
*em
= services_discovery_EventManager( p_sd
);
347 vlc_event_attach( em
, vlc_ServicesDiscoveryItemAdded
,
348 playlist_sd_item_added
, p_node
);
350 vlc_event_attach( em
, vlc_ServicesDiscoveryItemRemoved
,
351 playlist_sd_item_removed
, p_node
);
353 if( !vlc_sd_Start( p_sd
) )
355 vlc_sd_Destroy( p_sd
);
361 p_sds
->p_node
= p_node
;
362 p_sds
->psz_name
= strdup( psz_name
);
365 TAB_APPEND( pl_priv(p_playlist
)->i_sds
, pl_priv(p_playlist
)->pp_sds
, p_sds
);
371 int playlist_ServicesDiscoveryRemove( playlist_t
* p_playlist
,
372 const char *psz_name
)
374 playlist_private_t
*priv
= pl_priv( p_playlist
);
375 vlc_sd_internal_t
* p_sds
= NULL
;
378 for( int i
= 0; i
< priv
->i_sds
; i
++ )
380 if( !strcmp( psz_name
, priv
->pp_sds
[i
]->psz_name
) )
382 p_sds
= priv
->pp_sds
[i
];
383 REMOVE_ELEM( priv
->pp_sds
, priv
->i_sds
, i
);
391 msg_Warn( p_playlist
, "discovery %s is not loaded", psz_name
);
395 services_discovery_t
*p_sd
= p_sds
->p_sd
;
400 vlc_event_detach( services_discovery_EventManager( p_sd
),
401 vlc_ServicesDiscoveryItemAdded
,
402 playlist_sd_item_added
,
405 vlc_event_detach( services_discovery_EventManager( p_sd
),
406 vlc_ServicesDiscoveryItemRemoved
,
407 playlist_sd_item_removed
,
410 /* Remove the sd playlist node if it exists */
412 playlist_NodeDelete( p_playlist
, p_sds
->p_node
, true, false );
415 vlc_sd_Destroy( p_sd
);
416 free( p_sds
->psz_name
);
422 bool playlist_IsServicesDiscoveryLoaded( playlist_t
* p_playlist
,
423 const char *psz_name
)
425 playlist_private_t
*priv
= pl_priv( p_playlist
);
429 for( int i
= 0; i
< priv
->i_sds
; i
++ )
431 vlc_sd_internal_t
*sd
= priv
->pp_sds
[i
];
433 if( sd
->psz_name
&& !strcmp( psz_name
, sd
->psz_name
) )
443 void playlist_ServicesDiscoveryKillAll( playlist_t
*p_playlist
)
445 playlist_private_t
*priv
= pl_priv( p_playlist
);
447 while( priv
->i_sds
> 0 )
448 playlist_ServicesDiscoveryRemove( p_playlist
,
449 priv
->pp_sds
[0]->psz_name
);