player: osd: add missing calls
[vlc.git] / src / media_source / media_source.c
blob1bf7c4db83f2cf37ed772769e5ea63646bc526f9
1 /*****************************************************************************
2 * media_source.c
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include "media_source.h"
27 #include <assert.h>
28 #include <vlc_atomic.h>
29 #include <vlc_playlist.h>
30 #include <vlc_services_discovery.h>
31 #include <vlc_vector.h>
32 #include "libvlc.h"
33 #include "media_tree.h"
35 #ifdef TEST_MEDIA_SOURCE
36 #define vlc_module_name "test"
37 #endif /* TEST_MEDIA_SOURCE */
39 typedef struct
41 vlc_media_source_t public_data;
43 services_discovery_t *sd;
44 vlc_atomic_rc_t rc;
45 vlc_media_source_provider_t *owner;
46 struct vlc_list node;
47 char name[];
48 } media_source_private_t;
50 #define ms_priv(ms) container_of(ms, media_source_private_t, public_data)
52 struct vlc_media_source_provider_t
54 struct vlc_common_members obj;
55 vlc_mutex_t lock;
56 struct vlc_list media_sources;
59 /* A new item has been added to a certain services discovery */
60 static void
61 services_discovery_item_added(services_discovery_t *sd,
62 input_item_t *parent, input_item_t *media,
63 const char *cat)
65 assert(!parent || !cat);
66 VLC_UNUSED(cat);
68 vlc_media_source_t *ms = sd->owner.sys;
69 vlc_media_tree_t *tree = ms->tree;
71 msg_Dbg(sd, "adding: %s", media->psz_name ? media->psz_name : "(null)");
73 vlc_media_tree_Lock(tree);
75 input_item_node_t *parent_node;
76 if (parent)
77 vlc_media_tree_Find(tree, parent, &parent_node, NULL);
78 else
79 parent_node = &tree->root;
81 bool added = vlc_media_tree_Add(tree, parent_node, media) != NULL;
82 if (unlikely(!added))
83 msg_Err(sd, "could not allocate media tree node");
85 vlc_media_tree_Unlock(tree);
88 static void
89 services_discovery_item_removed(services_discovery_t *sd, input_item_t *media)
91 vlc_media_source_t *ms = sd->owner.sys;
92 vlc_media_tree_t *tree = ms->tree;
94 msg_Dbg(sd, "removing: %s", media->psz_name ? media->psz_name : "(null)");
96 vlc_media_tree_Lock(tree);
97 bool removed = vlc_media_tree_Remove(tree, media);
98 vlc_media_tree_Unlock(tree);
100 if (unlikely(!removed))
102 msg_Err(sd, "removing item not added"); /* SD plugin bug */
103 return;
107 static const struct services_discovery_callbacks sd_cbs = {
108 .item_added = services_discovery_item_added,
109 .item_removed = services_discovery_item_removed,
112 static vlc_media_source_t *
113 vlc_media_source_New(vlc_media_source_provider_t *provider, const char *name)
115 media_source_private_t *priv = malloc(sizeof(*priv) + strlen(name) + 1);
116 if (unlikely(!priv))
117 return NULL;
119 vlc_atomic_rc_init(&priv->rc);
121 vlc_media_source_t *ms = &priv->public_data;
123 /* vlc_sd_Create() may call services_discovery_item_added(), which will read
124 * its tree, so it must be initialized first */
125 ms->tree = vlc_media_tree_New();
126 if (unlikely(!ms->tree))
128 free(priv);
129 return NULL;
132 strcpy(priv->name, name);
134 struct services_discovery_owner_t owner = {
135 .cbs = &sd_cbs,
136 .sys = ms,
139 priv->sd = vlc_sd_Create(provider, name, &owner);
140 if (unlikely(!priv->sd))
142 vlc_media_tree_Release(ms->tree);
143 free(priv);
144 return NULL;
147 /* sd->description is set during vlc_sd_Create() */
148 ms->description = priv->sd->description;
150 priv->owner = provider;
152 return ms;
155 static void
156 vlc_media_source_provider_Remove(vlc_media_source_provider_t *provider,
157 vlc_media_source_t *ms)
159 vlc_mutex_lock(&provider->lock);
160 vlc_list_remove(&ms_priv(ms)->node);
161 vlc_mutex_unlock(&provider->lock);
164 static void
165 vlc_media_source_Delete(vlc_media_source_t *ms)
167 media_source_private_t *priv = ms_priv(ms);
168 vlc_media_source_provider_Remove(priv->owner, ms);
169 vlc_sd_Destroy(priv->sd);
170 vlc_media_tree_Release(ms->tree);
171 free(priv);
174 void
175 vlc_media_source_Hold(vlc_media_source_t *ms)
177 media_source_private_t *priv = ms_priv(ms);
178 vlc_atomic_rc_inc(&priv->rc);
181 void
182 vlc_media_source_Release(vlc_media_source_t *ms)
184 media_source_private_t *priv = ms_priv(ms);
185 if (vlc_atomic_rc_dec(&priv->rc))
186 vlc_media_source_Delete(ms);
189 static vlc_media_source_t *
190 vlc_media_source_provider_Find(vlc_media_source_provider_t *provider,
191 const char *name)
193 vlc_mutex_assert(&provider->lock);
194 media_source_private_t *entry;
195 vlc_list_foreach(entry, &provider->media_sources, node)
196 if (!strcmp(name, entry->name))
197 return &entry->public_data;
198 return NULL;
201 vlc_media_source_provider_t *
202 vlc_media_source_provider_Get(libvlc_int_t *libvlc)
204 return libvlc_priv(libvlc)->media_source_provider;
207 static void *
208 CreateObject(vlc_object_t *parent, size_t length, const char *typename)
210 #ifdef TEST_MEDIA_SOURCE
211 VLC_UNUSED(parent);
212 VLC_UNUSED(typename);
213 return malloc(length);
214 #else
215 return vlc_custom_create(parent, length, typename);
216 #endif
219 static void
220 ReleaseObject(void *obj)
222 #ifdef TEST_MEDIA_SOURCE
223 free(obj);
224 #else
225 vlc_object_release((vlc_object_t *) obj);
226 #endif
229 #undef vlc_media_source_provider_New
230 vlc_media_source_provider_t *
231 vlc_media_source_provider_New(vlc_object_t *parent)
233 vlc_media_source_provider_t *provider =
234 CreateObject(parent, sizeof(*provider), "media-source-provider");
235 if (unlikely(!provider))
236 return NULL;
238 vlc_mutex_init(&provider->lock);
239 vlc_list_init(&provider->media_sources);
240 return provider;
243 void
244 vlc_media_source_provider_Delete(vlc_media_source_provider_t *provider)
246 vlc_mutex_destroy(&provider->lock);
247 ReleaseObject(provider);
250 static vlc_media_source_t *
251 vlc_media_source_provider_Add(vlc_media_source_provider_t *provider,
252 const char *name)
254 vlc_mutex_assert(&provider->lock);
256 vlc_media_source_t *ms = vlc_media_source_New(provider, name);
257 if (unlikely(!ms))
258 return NULL;
260 vlc_list_append(&ms_priv(ms)->node, &provider->media_sources);
261 return ms;
264 vlc_media_source_t *
265 vlc_media_source_provider_GetMediaSource(vlc_media_source_provider_t *provider,
266 const char *name)
268 vlc_mutex_lock(&provider->lock);
269 vlc_media_source_t *ms = vlc_media_source_provider_Find(provider, name);
270 if (!ms)
271 ms = vlc_media_source_provider_Add(provider, name);
272 vlc_mutex_unlock(&provider->lock);
274 return ms;
277 struct vlc_media_source_meta_list
279 struct VLC_VECTOR(struct vlc_media_source_meta) vec;
282 struct vlc_media_source_meta_list *
283 vlc_media_source_provider_List(vlc_media_source_provider_t *provider,
284 enum services_discovery_category_e category)
286 char **longnames;
287 int *categories;
288 char **names = vlc_sd_GetNames(provider, &longnames, &categories);
289 if (!names)
290 /* vlc_sd_GetNames() returns NULL both on error or no result */
291 return NULL;
293 struct vlc_media_source_meta_list *list = malloc(sizeof(*list));
294 if (unlikely(!list))
295 return NULL;
297 vlc_vector_init(&list->vec);
298 for (size_t i = 0; names[i]; ++i)
300 if (category && categories[i] != (int) category)
302 free(names[i]);
303 free(longnames[i]);
304 /* only list items for the requested category */
305 continue;
308 struct vlc_media_source_meta meta = {
309 .name = names[i],
310 .longname = longnames[i],
311 .category = categories[i],
313 bool ok = vlc_vector_push(&list->vec, meta);
314 if (unlikely(!ok)) {
315 /* failure, clean up */
316 for (char **p = names; *p; ++p)
317 free(*p);
318 for (char **p = longnames; *p; ++p)
319 free(*p);
320 vlc_vector_destroy(&list->vec);
321 free(list);
322 list = NULL;
323 break;
327 free(names);
328 free(longnames);
329 free(categories);
331 return list;
334 size_t
335 vlc_media_source_meta_list_Count(vlc_media_source_meta_list_t *list)
337 return list->vec.size;
340 struct vlc_media_source_meta *
341 vlc_media_source_meta_list_Get(vlc_media_source_meta_list_t *list, size_t index)
343 return &list->vec.data[index];
346 void
347 vlc_media_source_meta_list_Delete(vlc_media_source_meta_list_t *list) {
348 for (size_t i = 0; i < list->vec.size; ++i)
350 free(list->vec.data[i].name);
351 free(list->vec.data[i].longname);
353 vlc_vector_destroy(&list->vec);
354 free(list);