1 /*****************************************************************************
2 * services_discovery.c : Manage playlist services_discovery modules
3 *****************************************************************************
4 * Copyright (C) 1999-2004 VLC authors and VideoLAN
7 * Authors: Clément Stenac <zorglub@videolan.org>
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.
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.
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 *****************************************************************************/
28 #include <vlc_common.h>
29 #include <vlc_playlist.h>
30 #include <vlc_services_discovery.h>
31 #include "playlist_internal.h"
33 struct vlc_sd_internal_t
35 /* the playlist items for category and onelevel */
36 playlist_item_t
*node
;
37 services_discovery_t
*sd
; /**< Loaded service discovery modules */
41 /* A new item has been added to a certain sd */
42 static void playlist_sd_item_added(services_discovery_t
*sd
,
43 input_item_t
*parent
, input_item_t
*p_input
,
46 assert(parent
== NULL
|| psz_cat
== NULL
);
48 vlc_sd_internal_t
*sds
= sd
->owner
.sys
;
49 playlist_t
*playlist
= (playlist_t
*)sd
->obj
.parent
;
50 playlist_item_t
*node
;
51 const char *longname
= (sd
->description
!= NULL
) ? sd
->description
: "?";
53 msg_Dbg(sd
, "adding: %s", p_input
->psz_name
? p_input
->psz_name
: "(null)");
55 playlist_Lock(playlist
);
56 if (sds
->node
== NULL
)
57 sds
->node
= playlist_NodeCreate(playlist
, longname
, &playlist
->root
,
58 PLAYLIST_END
, PLAYLIST_RO_FLAG
);
61 node
= playlist_ItemGetByInput(playlist
, parent
);
66 { /* Parent is NULL (root) and category is specified.
67 * This is clearly a hack. TODO: remove this. */
68 node
= playlist_ChildSearchName(sds
->node
, psz_cat
);
70 node
= playlist_NodeCreate(playlist
, psz_cat
, sds
->node
,
71 PLAYLIST_END
, PLAYLIST_RO_FLAG
);
74 playlist_NodeAddInput(playlist
, p_input
, node
, PLAYLIST_END
);
75 playlist_Unlock(playlist
);
78 /* A new item has been removed from a certain sd */
79 static void playlist_sd_item_removed(services_discovery_t
*sd
,
80 input_item_t
*p_input
)
82 vlc_sd_internal_t
*sds
= sd
->owner
.sys
;
83 playlist_t
*playlist
= (playlist_t
*)sd
->obj
.parent
;
84 playlist_item_t
*node
, *item
;
86 msg_Dbg(sd
, "removing: %s", p_input
->psz_name
? p_input
->psz_name
: "(null)");
88 playlist_Lock(playlist
);
89 item
= playlist_ItemGetByInput(playlist
, p_input
);
90 if (unlikely(item
== NULL
))
92 msg_Err(sd
, "removing item not added"); /* SD plugin bug */
93 playlist_Unlock(playlist
);
98 /* Check that the item belonged to the SD */
99 for (playlist_item_t
*i
= item
->p_parent
; i
!= sds
->node
; i
= i
->p_parent
)
103 node
= item
->p_parent
;
104 /* if the item was added under a category and the category node
105 becomes empty, delete that node as well */
106 if (node
!= sds
->node
&& node
->i_children
== 1)
108 playlist_NodeDeleteExplicit(playlist
, item
,
109 PLAYLIST_DELETE_FORCE
| PLAYLIST_DELETE_STOP_IF_CURRENT
);
110 playlist_Unlock(playlist
);
113 int playlist_ServicesDiscoveryAdd(playlist_t
*playlist
, const char *chain
)
115 vlc_sd_internal_t
*sds
= malloc(sizeof (*sds
) + strlen(chain
) + 1);
116 if (unlikely(sds
== NULL
))
121 struct services_discovery_owner_t owner
= {
123 playlist_sd_item_added
,
124 playlist_sd_item_removed
,
127 /* Perform the addition */
128 sds
->sd
= vlc_sd_Create(VLC_OBJECT(playlist
), chain
, &owner
);
129 if (unlikely(sds
->sd
== NULL
))
135 strcpy(sds
->name
, chain
);
137 playlist_Lock(playlist
);
138 /* Backward compatibility with Qt UI: create the node even if the SD
139 * has not discovered any item. */
140 if (sds
->node
== NULL
&& sds
->sd
->description
!= NULL
)
141 sds
->node
= playlist_NodeCreate(playlist
, sds
->sd
->description
,
142 &playlist
->root
, PLAYLIST_END
,
145 TAB_APPEND(pl_priv(playlist
)->i_sds
, pl_priv(playlist
)->pp_sds
, sds
);
146 playlist_Unlock(playlist
);
150 static void playlist_ServicesDiscoveryInternalRemove(playlist_t
*playlist
,
151 vlc_sd_internal_t
*sds
)
153 assert(sds
->sd
!= NULL
);
154 vlc_sd_Destroy(sds
->sd
);
156 /* Remove the sd playlist node if it exists */
157 playlist_Lock(playlist
);
158 if (sds
->node
!= NULL
)
159 playlist_NodeDeleteExplicit(playlist
, sds
->node
,
160 PLAYLIST_DELETE_FORCE
| PLAYLIST_DELETE_STOP_IF_CURRENT
);
161 playlist_Unlock(playlist
);
167 int playlist_ServicesDiscoveryRemove(playlist_t
*playlist
, const char *name
)
169 playlist_private_t
*priv
= pl_priv(playlist
);
170 vlc_sd_internal_t
*sds
= NULL
;
172 playlist_Lock(playlist
);
173 for (int i
= 0; i
< priv
->i_sds
; i
++)
175 vlc_sd_internal_t
*entry
= priv
->pp_sds
[i
];
177 if (!strcmp(name
, entry
->name
))
179 TAB_ERASE(priv
->i_sds
, priv
->pp_sds
, i
);
184 playlist_Unlock(playlist
);
188 msg_Warn(playlist
, "discovery %s is not loaded", name
);
192 playlist_ServicesDiscoveryInternalRemove(playlist
, sds
);
196 bool playlist_IsServicesDiscoveryLoaded( playlist_t
* playlist
,
197 const char *psz_name
)
199 playlist_private_t
*priv
= pl_priv( playlist
);
201 playlist_Lock(playlist
);
203 for( int i
= 0; i
< priv
->i_sds
; i
++ )
205 vlc_sd_internal_t
*sds
= priv
->pp_sds
[i
];
207 if (!strcmp(psz_name
, sds
->name
))
213 playlist_Unlock(playlist
);
217 int playlist_ServicesDiscoveryControl( playlist_t
*playlist
, const char *psz_name
, int i_control
, ... )
219 playlist_private_t
*priv
= pl_priv( playlist
);
220 int i_ret
= VLC_EGENERIC
;
223 playlist_Lock(playlist
);
224 for( i
= 0; i
< priv
->i_sds
; i
++ )
226 vlc_sd_internal_t
*sds
= priv
->pp_sds
[i
];
227 if (!strcmp(psz_name
, sds
->name
))
230 va_start( args
, i_control
);
231 i_ret
= vlc_sd_control(sds
->sd
, i_control
, args
);
237 assert( i
!= priv
->i_sds
);
238 playlist_Unlock(playlist
);
243 void playlist_ServicesDiscoveryKillAll(playlist_t
*playlist
)
245 playlist_private_t
*priv
= pl_priv(playlist
);
247 for (int i
= 0; i
< priv
->i_sds
; i
++)
248 playlist_ServicesDiscoveryInternalRemove(playlist
, priv
->pp_sds
[i
]);
250 TAB_CLEAN(priv
->i_sds
, priv
->pp_sds
);