1 /*****************************************************************************
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 *****************************************************************************/
25 #include "media_source.h"
28 #include <vlc_atomic.h>
29 #include <vlc_playlist.h>
30 #include <vlc_services_discovery.h>
31 #include <vlc_vector.h>
33 #include "media_tree.h"
35 #ifdef TEST_MEDIA_SOURCE
36 #define vlc_module_name "test"
37 #endif /* TEST_MEDIA_SOURCE */
41 vlc_media_source_t public_data
;
43 services_discovery_t
*sd
;
45 vlc_media_source_provider_t
*owner
;
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
;
56 struct vlc_list media_sources
;
59 /* A new item has been added to a certain services discovery */
61 services_discovery_item_added(services_discovery_t
*sd
,
62 input_item_t
*parent
, input_item_t
*media
,
65 assert(!parent
|| !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
;
77 vlc_media_tree_Find(tree
, parent
, &parent_node
, NULL
);
79 parent_node
= &tree
->root
;
81 bool added
= vlc_media_tree_Add(tree
, parent_node
, media
) != NULL
;
83 msg_Err(sd
, "could not allocate media tree node");
85 vlc_media_tree_Unlock(tree
);
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 */
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);
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
))
132 strcpy(priv
->name
, name
);
134 struct services_discovery_owner_t owner
= {
139 priv
->sd
= vlc_sd_Create(provider
, name
, &owner
);
140 if (unlikely(!priv
->sd
))
142 vlc_media_tree_Release(ms
->tree
);
147 /* sd->description is set during vlc_sd_Create() */
148 ms
->description
= priv
->sd
->description
;
150 priv
->owner
= provider
;
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
);
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
);
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
);
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
,
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
;
201 vlc_media_source_provider_t
*
202 vlc_media_source_provider_Get(libvlc_int_t
*libvlc
)
204 return libvlc_priv(libvlc
)->media_source_provider
;
208 CreateObject(vlc_object_t
*parent
, size_t length
, const char *typename
)
210 #ifdef TEST_MEDIA_SOURCE
212 VLC_UNUSED(typename
);
213 return malloc(length
);
215 return vlc_custom_create(parent
, length
, typename
);
220 ReleaseObject(void *obj
)
222 #ifdef TEST_MEDIA_SOURCE
225 vlc_object_release((vlc_object_t
*) obj
);
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
))
238 vlc_mutex_init(&provider
->lock
);
239 vlc_list_init(&provider
->media_sources
);
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
,
254 vlc_mutex_assert(&provider
->lock
);
256 vlc_media_source_t
*ms
= vlc_media_source_New(provider
, name
);
260 vlc_list_append(&ms_priv(ms
)->node
, &provider
->media_sources
);
265 vlc_media_source_provider_GetMediaSource(vlc_media_source_provider_t
*provider
,
268 vlc_mutex_lock(&provider
->lock
);
269 vlc_media_source_t
*ms
= vlc_media_source_provider_Find(provider
, name
);
271 ms
= vlc_media_source_provider_Add(provider
, name
);
272 vlc_mutex_unlock(&provider
->lock
);
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
)
288 char **names
= vlc_sd_GetNames(provider
, &longnames
, &categories
);
290 /* vlc_sd_GetNames() returns NULL both on error or no result */
293 struct vlc_media_source_meta_list
*list
= malloc(sizeof(*list
));
297 vlc_vector_init(&list
->vec
);
298 for (size_t i
= 0; names
[i
]; ++i
)
300 if (category
&& categories
[i
] != (int) category
)
304 /* only list items for the requested category */
308 struct vlc_media_source_meta meta
= {
310 .longname
= longnames
[i
],
311 .category
= categories
[i
],
313 bool ok
= vlc_vector_push(&list
->vec
, meta
);
315 /* failure, clean up */
316 for (char **p
= names
; *p
; ++p
)
318 for (char **p
= longnames
; *p
; ++p
)
320 vlc_vector_destroy(&list
->vec
);
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
];
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
);