4 * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU Lesser General Public License,
8 * version 2.1, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19 * Mark Ryan <mark.d.ryan@intel.com>
24 #include <libgupnp-av/gupnp-didl-lite-contributor.h>
26 #include <libdleyna/core/log.h>
29 #include "interface.h"
33 static const gchar gUPnPContainer[] = "object.container";
34 static const gchar gUPnPAlbum[] = "object.container.album";
35 static const gchar gUPnPPerson[] = "object.container.person";
36 static const gchar gUPnPGenre[] = "object.container.genre";
37 static const gchar gUPnPAudioItem[] = "object.item.audioItem";
38 static const gchar gUPnPVideoItem[] = "object.item.videoItem";
39 static const gchar gUPnPImageItem[] = "object.item.imageItem";
40 static const gchar gUPnPPlaylistItem[] = "object.item.playlistItem";
41 static const gchar gUPnPItem[] = "object.item";
43 static const unsigned int gUPnPContainerLen =
44 (sizeof(gUPnPContainer) / sizeof(gchar)) - 1;
45 static const unsigned int gUPnPAlbumLen =
46 (sizeof(gUPnPAlbum) / sizeof(gchar)) - 1;
47 static const unsigned int gUPnPPersonLen =
48 (sizeof(gUPnPPerson) / sizeof(gchar)) - 1;
49 static const unsigned int gUPnPGenreLen =
50 (sizeof(gUPnPGenre) / sizeof(gchar)) - 1;
51 static const unsigned int gUPnPAudioItemLen =
52 (sizeof(gUPnPAudioItem) / sizeof(gchar)) - 1;
53 static const unsigned int gUPnPVideoItemLen =
54 (sizeof(gUPnPVideoItem) / sizeof(gchar)) - 1;
55 static const unsigned int gUPnPImageItemLen =
56 (sizeof(gUPnPImageItem) / sizeof(gchar)) - 1;
57 static const unsigned int gUPnPPlaylistItemLen =
58 (sizeof(gUPnPPlaylistItem) / sizeof(gchar)) - 1;
59 static const unsigned int gUPnPItemLen =
60 (sizeof(gUPnPItem) / sizeof(gchar)) - 1;
62 static const gchar gUPnPPhotoAlbum[] = "object.container.album.photoAlbum";
63 static const gchar gUPnPMusicAlbum[] = "object.container.album.musicAlbum";
64 static const gchar gUPnPMusicArtist[] = "object.container.person.musicArtist";
65 static const gchar gUPnPMovieGenre[] = "object.container.genre.movieGenre";
66 static const gchar gUPnPMusicGenre[] = "object.container.genre.musicGenre";
67 static const gchar gUPnPMusicTrack[] = "object.item.audioItem.musicTrack";
68 static const gchar gUPnPAudioBroadcast[] =
69 "object.item.audioItem.audioBroadcast";
70 static const gchar gUPnPAudioBook[] = "object.item.audioItem.audioBook";
71 static const gchar gUPnPMovie[] = "object.item.videoItem.movie";
72 static const gchar gUPnPMusicVideoClip[] =
73 "object.item.videoItem.musicVideoClip";
74 static const gchar gUPnPVideoBroadcast[] =
75 "object.item.videoItem.videoBroadcast";
76 static const gchar gUPnPPhoto[] = "object.item.imageItem.photo";
78 static const gchar gMediaSpec2Container[] = "container";
79 static const gchar gMediaSpec2Album[] = "album";
80 static const gchar gMediaSpec2AlbumPhoto[] = "album.photo";
81 static const gchar gMediaSpec2AlbumMusic[] = "album.music";
82 static const gchar gMediaSpec2Person[] = "person";
83 static const gchar gMediaSpec2PersonMusicArtist[] = "person.musicartist";
84 static const gchar gMediaSpec2Genre[] = "genre";
85 static const gchar gMediaSpec2GenreMovie[] = "genre.movie";
86 static const gchar gMediaSpec2GenreMusic[] = "genre.music";
87 static const gchar gMediaSpec2AudioMusic[] = "audio.music";
88 static const gchar gMediaSpec2AudioBroadcast[] = "audio.broadcast";
89 static const gchar gMediaSpec2AudioBook[] = "audio.book";
90 static const gchar gMediaSpec2Audio[] = "audio";
91 static const gchar gMediaSpec2VideoMovie[] = "video.movie";
92 static const gchar gMediaSpec2VideoMusicClip[] = "video.musicclip";
93 static const gchar gMediaSpec2VideoBroadcast[] = "video.broadcast";
94 static const gchar gMediaSpec2Video[] = "video";
95 static const gchar gMediaSpec2ImagePhoto[] = "image.photo";
96 static const gchar gMediaSpec2Image[] = "image";
97 static const gchar gMediaSpec2Playlist[] = "playlist";
98 static const gchar gMediaSpec2Item[] = "item";
100 static dls_prop_map_t *prv_prop_map_new(const gchar *prop_name,
101 dls_upnp_prop_mask type,
106 dls_prop_map_t *retval = g_new(dls_prop_map_t, 1);
107 retval->upnp_prop_name = prop_name;
109 retval->filter = filter;
110 retval->searchable = searchable;
111 retval->updateable = updateable;
115 void dls_prop_maps_new(GHashTable **property_map, GHashTable **filter_map)
117 dls_prop_map_t *prop_t;
121 p_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
122 f_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
125 prop_t = prv_prop_map_new("@childCount",
126 DLS_UPNP_MASK_PROP_CHILD_COUNT,
128 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CHILD_COUNT, prop_t);
129 g_hash_table_insert(p_map, "@childCount",
130 DLS_INTERFACE_PROP_CHILD_COUNT);
133 prop_t = prv_prop_map_new("@id",
134 DLS_UPNP_MASK_PROP_PATH,
136 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_PATH, prop_t);
137 g_hash_table_insert(p_map, "@id", DLS_INTERFACE_PROP_PATH);
140 prop_t = prv_prop_map_new("@parentID",
141 DLS_UPNP_MASK_PROP_PARENT,
143 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_PARENT, prop_t);
144 g_hash_table_insert(p_map, "@parentID", DLS_INTERFACE_PROP_PARENT);
147 prop_t = prv_prop_map_new("@refID",
148 DLS_UPNP_MASK_PROP_REFPATH,
150 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_REFPATH, prop_t);
151 g_hash_table_insert(p_map, "@refID", DLS_INTERFACE_PROP_REFPATH);
154 prop_t = prv_prop_map_new("@restricted",
155 DLS_UPNP_MASK_PROP_RESTRICTED,
157 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_RESTRICTED, prop_t);
158 g_hash_table_insert(p_map, "@restricted",
159 DLS_INTERFACE_PROP_RESTRICTED);
162 prop_t = prv_prop_map_new("@searchable",
163 DLS_UPNP_MASK_PROP_SEARCHABLE,
165 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_SEARCHABLE, prop_t);
166 g_hash_table_insert(p_map, "@searchable",
167 DLS_INTERFACE_PROP_SEARCHABLE);
170 prop_t = prv_prop_map_new("dc:creator",
171 DLS_UPNP_MASK_PROP_CREATOR,
173 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CREATOR, prop_t);
174 g_hash_table_insert(p_map, "dc:creator", DLS_INTERFACE_PROP_CREATOR);
177 prop_t = prv_prop_map_new("dc:date",
178 DLS_UPNP_MASK_PROP_DATE,
180 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DATE, prop_t);
181 g_hash_table_insert(p_map, "dc:date", DLS_INTERFACE_PROP_DATE);
184 prop_t = prv_prop_map_new("dc:title",
185 DLS_UPNP_MASK_PROP_DISPLAY_NAME,
187 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DISPLAY_NAME, prop_t);
188 g_hash_table_insert(p_map, "dc:title", DLS_INTERFACE_PROP_DISPLAY_NAME);
190 /* dlna:dlnaManaged */
191 prop_t = prv_prop_map_new("dlna:dlnaManaged",
192 DLS_UPNP_MASK_PROP_DLNA_MANAGED,
194 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DLNA_MANAGED, prop_t);
195 g_hash_table_insert(p_map, "dlna:dlnaManaged",
196 DLS_INTERFACE_PROP_DLNA_MANAGED);
200 prop_t = prv_prop_map_new("res",
201 DLS_UPNP_MASK_PROP_RESOURCES,
203 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_RESOURCES, prop_t);
206 prop_t = prv_prop_map_new("res",
207 DLS_UPNP_MASK_PROP_URL,
209 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_URL, prop_t);
212 prop_t = prv_prop_map_new("res",
213 DLS_UPNP_MASK_PROP_URLS,
215 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_URLS, prop_t);
218 prop_t = prv_prop_map_new("res@bitrate",
219 DLS_UPNP_MASK_PROP_BITRATE,
221 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_BITRATE, prop_t);
222 g_hash_table_insert(p_map, "res@bitrate", DLS_INTERFACE_PROP_BITRATE);
224 /* res@bitsPerSample */
225 prop_t = prv_prop_map_new("res@bitsPerSample",
226 DLS_UPNP_MASK_PROP_BITS_PER_SAMPLE,
228 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_BITS_PER_SAMPLE, prop_t);
229 g_hash_table_insert(p_map, "res@bitsPerSample",
230 DLS_INTERFACE_PROP_BITS_PER_SAMPLE);
233 prop_t = prv_prop_map_new("res@colorDepth",
234 DLS_UPNP_MASK_PROP_COLOR_DEPTH,
236 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_COLOR_DEPTH, prop_t);
237 g_hash_table_insert(p_map, "res@colorDepth",
238 DLS_INTERFACE_PROP_COLOR_DEPTH);
241 prop_t = prv_prop_map_new("res@duration",
242 DLS_UPNP_MASK_PROP_DURATION,
244 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DURATION, prop_t);
245 g_hash_table_insert(p_map, "res@duration",
246 DLS_INTERFACE_PROP_DURATION);
248 /* res@protocolInfo */
249 /* res@protocolInfo - DLNA PROFILE*/
250 prop_t = prv_prop_map_new("res@protocolInfo",
251 DLS_UPNP_MASK_PROP_DLNA_PROFILE,
253 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DLNA_PROFILE, prop_t);
255 /* res@protocolInfo - MIME TYPES*/
256 prop_t = prv_prop_map_new("res@protocolInfo",
257 DLS_UPNP_MASK_PROP_MIME_TYPE,
259 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_MIME_TYPE, prop_t);
262 /* res@resolution - HEIGH */
263 prop_t = prv_prop_map_new("res@resolution",
264 DLS_UPNP_MASK_PROP_HEIGHT,
266 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_HEIGHT, prop_t);
268 /* res@resolution - WIDTH */
269 prop_t = prv_prop_map_new("res@resolution",
270 DLS_UPNP_MASK_PROP_WIDTH,
272 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_WIDTH, prop_t);
274 /* res@sampleFrequency */
275 prop_t = prv_prop_map_new("res@sampleFrequency",
276 DLS_UPNP_MASK_PROP_SAMPLE_RATE,
278 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_SAMPLE_RATE, prop_t);
279 g_hash_table_insert(p_map, "res@sampleFrequency",
280 DLS_INTERFACE_PROP_SAMPLE_RATE);
283 prop_t = prv_prop_map_new("res@size",
284 DLS_UPNP_MASK_PROP_SIZE,
286 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_SIZE, prop_t);
287 g_hash_table_insert(p_map, "res@size", DLS_INTERFACE_PROP_SIZE);
289 /* res@updateCount */
290 prop_t = prv_prop_map_new("res@updateCount",
291 DLS_UPNP_MASK_PROP_UPDATE_COUNT,
293 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_UPDATE_COUNT, prop_t);
294 g_hash_table_insert(p_map, "res@updateCount",
295 DLS_INTERFACE_PROP_UPDATE_COUNT);
298 prop_t = prv_prop_map_new("upnp:album",
299 DLS_UPNP_MASK_PROP_ALBUM,
301 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ALBUM, prop_t);
302 g_hash_table_insert(p_map, "upnp:album", DLS_INTERFACE_PROP_ALBUM);
304 /* upnp:albumArtURI */
305 prop_t = prv_prop_map_new("upnp:albumArtURI",
306 DLS_UPNP_MASK_PROP_ALBUM_ART_URL,
308 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ALBUM_ART_URL, prop_t);
309 g_hash_table_insert(p_map, "upnp:albumArtURI",
310 DLS_INTERFACE_PROP_ALBUM_ART_URL);
313 /* upnp:artist - ARTIST*/
314 prop_t = prv_prop_map_new("upnp:artist",
315 DLS_UPNP_MASK_PROP_ARTIST,
317 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ARTIST, prop_t);
318 g_hash_table_insert(p_map, "upnp:artist", DLS_INTERFACE_PROP_ARTIST);
320 /* upnp:artist - ARTISTS*/
321 prop_t = prv_prop_map_new("upnp:artist",
322 DLS_UPNP_MASK_PROP_ARTISTS,
324 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ARTISTS, prop_t);
327 prop_t = prv_prop_map_new("upnp:class",
328 DLS_UPNP_MASK_PROP_TYPE,
330 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TYPE, prop_t);
331 g_hash_table_insert(p_map, "upnp:class", DLS_INTERFACE_PROP_TYPE);
333 /* upnp:containerUpdateID */
334 prop_t = prv_prop_map_new("upnp:containerUpdateID",
335 DLS_UPNP_MASK_PROP_CONTAINER_UPDATE_ID,
337 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID,
339 g_hash_table_insert(p_map, "upnp:containerUpdateID",
340 DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID);
342 /* upnp:createClass */
343 prop_t = prv_prop_map_new("upnp:createClass",
344 DLS_UPNP_MASK_PROP_CREATE_CLASSES,
346 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CREATE_CLASSES, prop_t);
349 prop_t = prv_prop_map_new("upnp:genre",
350 DLS_UPNP_MASK_PROP_GENRE,
352 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_GENRE, prop_t);
353 g_hash_table_insert(p_map, "upnp:genre", DLS_INTERFACE_PROP_GENRE);
355 /* upnp:objectUpdateID */
356 prop_t = prv_prop_map_new("upnp:objectUpdateID",
357 DLS_UPNP_MASK_PROP_OBJECT_UPDATE_ID,
359 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_OBJECT_UPDATE_ID, prop_t);
360 g_hash_table_insert(p_map, "upnp:objectUpdateID",
361 DLS_INTERFACE_PROP_OBJECT_UPDATE_ID);
363 /* upnp:originalTrackNumber */
364 prop_t = prv_prop_map_new("upnp:originalTrackNumber",
365 DLS_UPNP_MASK_PROP_TRACK_NUMBER,
367 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TRACK_NUMBER, prop_t);
368 g_hash_table_insert(p_map, "upnp:originalTrackNumber",
369 DLS_INTERFACE_PROP_TRACK_NUMBER);
371 /* upnp:totalDeletedChildCount */
372 prop_t = prv_prop_map_new("upnp:totalDeletedChildCount",
373 DLS_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT,
375 g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT,
377 g_hash_table_insert(p_map, "upnp:totalDeletedChildCount",
378 DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT);
381 *property_map = p_map;
384 static gchar *prv_compute_upnp_filter(GHashTable *upnp_props)
390 str = g_string_new("");
391 g_hash_table_iter_init(&iter, upnp_props);
392 if (g_hash_table_iter_next(&iter, &key, NULL)) {
393 g_string_append(str, (const gchar *)key);
394 while (g_hash_table_iter_next(&iter, &key, NULL)) {
395 g_string_append(str, ",");
396 g_string_append(str, (const gchar *)key);
400 return g_string_free(str, FALSE);
403 static dls_upnp_prop_mask prv_parse_filter_list(GHashTable *filter_map,
409 dls_prop_map_t *prop_map;
410 GHashTable *upnp_props;
411 dls_upnp_prop_mask mask = 0;
413 upnp_props = g_hash_table_new_full(g_str_hash, g_str_equal,
415 (void) g_variant_iter_init(&viter, filter);
417 while (g_variant_iter_next(&viter, "&s", &prop)) {
418 prop_map = g_hash_table_lookup(filter_map, prop);
422 mask |= prop_map->type;
424 if (!prop_map->filter)
427 g_hash_table_insert(upnp_props,
428 (gpointer) prop_map->upnp_prop_name, NULL);
431 *upnp_filter = prv_compute_upnp_filter(upnp_props);
432 g_hash_table_unref(upnp_props);
437 dls_upnp_prop_mask dls_props_parse_filter(GHashTable *filter_map,
442 gboolean parse_filter = TRUE;
443 dls_upnp_prop_mask mask;
445 if (g_variant_n_children(filter) == 1) {
446 g_variant_get_child(filter, 0, "&s", &str);
447 if (!strcmp(str, "*"))
448 parse_filter = FALSE;
452 mask = prv_parse_filter_list(filter_map, filter, upnp_filter);
454 mask = DLS_UPNP_MASK_ALL_PROPS;
455 *upnp_filter = g_strdup("*");
461 gboolean dls_props_parse_update_filter(GHashTable *filter_map,
462 GVariant *to_add_update,
464 dls_upnp_prop_mask *mask,
470 dls_prop_map_t *prop_map;
471 GHashTable *upnp_props;
472 gboolean retval = FALSE;
476 upnp_props = g_hash_table_new_full(g_str_hash, g_str_equal,
479 (void) g_variant_iter_init(&viter, to_add_update);
481 while (g_variant_iter_next(&viter, "{&sv}", &prop, &value)) {
482 DLEYNA_LOG_DEBUG("to_add_update = %s", prop);
484 prop_map = g_hash_table_lookup(filter_map, prop);
486 if ((!prop_map) || (!prop_map->updateable))
489 *mask |= prop_map->type;
491 if (!prop_map->filter)
494 g_hash_table_insert(upnp_props,
495 (gpointer) prop_map->upnp_prop_name, NULL);
498 (void) g_variant_iter_init(&viter, to_delete);
500 while (g_variant_iter_next(&viter, "&s", &prop)) {
501 DLEYNA_LOG_DEBUG("to_delete = %s", prop);
503 prop_map = g_hash_table_lookup(filter_map, prop);
505 if ((!prop_map) || (!prop_map->updateable) ||
506 (*mask & prop_map->type) != 0)
509 *mask |= prop_map->type;
511 if (!prop_map->filter)
514 g_hash_table_insert(upnp_props,
515 (gpointer) prop_map->upnp_prop_name, NULL);
518 *upnp_filter = prv_compute_upnp_filter(upnp_props);
524 g_hash_table_unref(upnp_props);
529 static void prv_add_string_prop(GVariantBuilder *vb, const gchar *key,
533 DLEYNA_LOG_DEBUG("Prop %s = %s", key, value);
535 g_variant_builder_add(vb, "{sv}", key,
536 g_variant_new_string(value));
540 static void prv_add_strv_prop(GVariantBuilder *vb, const gchar *key,
541 const gchar **value, unsigned int len)
544 g_variant_builder_add(vb, "{sv}", key,
545 g_variant_new_strv(value, len));
548 static void prv_add_path_prop(GVariantBuilder *vb, const gchar *key,
552 DLEYNA_LOG_DEBUG("Prop %s = %s", key, value);
554 g_variant_builder_add(vb, "{sv}", key,
555 g_variant_new_object_path(value));
559 static void prv_add_uint_prop(GVariantBuilder *vb, const gchar *key,
562 DLEYNA_LOG_DEBUG("Prop %s = %u", key, value);
564 g_variant_builder_add(vb, "{sv}", key, g_variant_new_uint32(value));
567 static void prv_add_int_prop(GVariantBuilder *vb, const gchar *key,
571 g_variant_builder_add(vb, "{sv}", key,
572 g_variant_new_int32(value));
575 static void prv_add_variant_prop(GVariantBuilder *vb, const gchar *key,
579 g_variant_builder_add(vb, "{sv}", key, prop);
582 void dls_props_add_child_count(GVariantBuilder *item_vb, gint value)
584 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_CHILD_COUNT, value);
587 static void prv_add_bool_prop(GVariantBuilder *vb, const gchar *key,
590 DLEYNA_LOG_DEBUG("Prop %s = %u", key, value);
592 g_variant_builder_add(vb, "{sv}", key, g_variant_new_boolean(value));
595 static void prv_add_int64_prop(GVariantBuilder *vb, const gchar *key,
599 DLEYNA_LOG_DEBUG("Prop %s = %"G_GINT64_FORMAT, key, value);
601 g_variant_builder_add(vb, "{sv}", key,
602 g_variant_new_int64(value));
606 static void prv_add_list_dlna_str(gpointer data, gpointer user_data)
608 GVariantBuilder *vb = (GVariantBuilder *)user_data;
609 gchar *cap_str = (gchar *)data;
613 if (g_str_has_prefix(cap_str, "srs-rt-retention-period-")) {
614 str = cap_str + strlen("srs-rt-retention-period-");
615 cap_str = "srs-rt-retention-period";
618 if (!g_strcmp0(str, "infinity"))
625 prv_add_uint_prop(vb, cap_str, value);
628 static GVariant *prv_add_list_dlna_prop(GList *list)
632 g_variant_builder_init(&vb, G_VARIANT_TYPE("a{sv}"));
634 g_list_foreach(list, prv_add_list_dlna_str, &vb);
636 return g_variant_builder_end(&vb);
639 static void prv_add_list_artists_str(gpointer data, gpointer user_data)
641 GVariantBuilder *vb = (GVariantBuilder *)user_data;
642 GUPnPDIDLLiteContributor *contributor = data;
645 str = gupnp_didl_lite_contributor_get_name(contributor);
646 g_variant_builder_add(vb, "s", str);
649 static GVariant *prv_get_artists_prop(GList *list)
653 g_variant_builder_init(&vb, G_VARIANT_TYPE("as"));
654 g_list_foreach(list, prv_add_list_artists_str, &vb);
656 return g_variant_builder_end(&vb);
659 void dls_props_add_device(GUPnPDeviceInfo *proxy,
660 const dls_device_t *device,
667 prv_add_string_prop(vb, DLS_INTERFACE_PROP_LOCATION,
668 gupnp_device_info_get_location(proxy));
670 prv_add_string_prop(vb, DLS_INTERFACE_PROP_UDN,
671 gupnp_device_info_get_udn(proxy));
673 prv_add_string_prop(vb, DLS_INTERFACE_PROP_DEVICE_TYPE,
674 gupnp_device_info_get_device_type(proxy));
676 str = gupnp_device_info_get_friendly_name(proxy);
677 prv_add_string_prop(vb, DLS_INTERFACE_PROP_FRIENDLY_NAME, str);
680 str = gupnp_device_info_get_manufacturer(proxy);
681 prv_add_string_prop(vb, DLS_INTERFACE_PROP_MANUFACTURER, str);
684 str = gupnp_device_info_get_manufacturer_url(proxy);
685 prv_add_string_prop(vb, DLS_INTERFACE_PROP_MANUFACTURER_URL, str);
688 str = gupnp_device_info_get_model_description(proxy);
689 prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_DESCRIPTION, str);
692 str = gupnp_device_info_get_model_name(proxy);
693 prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_NAME, str);
696 str = gupnp_device_info_get_model_number(proxy);
697 prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_NUMBER, str);
700 str = gupnp_device_info_get_model_url(proxy);
701 prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_URL, str);
704 str = gupnp_device_info_get_serial_number(proxy);
705 prv_add_string_prop(vb, DLS_INTERFACE_PROP_SERIAL_NUMBER, str);
708 str = gupnp_device_info_get_presentation_url(proxy);
709 prv_add_string_prop(vb, DLS_INTERFACE_PROP_PRESENTATION_URL, str);
712 str = gupnp_device_info_get_icon_url(proxy, NULL, -1, -1, -1, FALSE,
713 NULL, NULL, NULL, NULL);
714 prv_add_string_prop(vb, DLS_INTERFACE_PROP_ICON_URL, str);
717 list = gupnp_device_info_list_dlna_capabilities(proxy);
719 dlna_caps = prv_add_list_dlna_prop(list);
720 g_variant_builder_add(vb, "{sv}",
721 DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES,
723 g_list_free_full(list, g_free);
726 if (device->search_caps != NULL)
727 g_variant_builder_add(vb, "{sv}",
728 DLS_INTERFACE_PROP_SV_SEARCH_CAPABILITIES,
729 device->search_caps);
731 if (device->sort_caps != NULL)
732 g_variant_builder_add(vb, "{sv}",
733 DLS_INTERFACE_PROP_SV_SORT_CAPABILITIES,
736 if (device->sort_ext_caps != NULL)
737 g_variant_builder_add(
739 DLS_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES,
740 device->sort_ext_caps);
742 if (device->feature_list != NULL)
743 g_variant_builder_add(vb, "{sv}",
744 DLS_INTERFACE_PROP_SV_FEATURE_LIST,
745 device->feature_list);
748 GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy,
749 const dls_device_t *device,
752 GVariant *dlna_caps = NULL;
753 GVariant *retval = NULL;
754 const gchar *str = NULL;
758 if (!strcmp(DLS_INTERFACE_PROP_LOCATION, prop)) {
759 str = gupnp_device_info_get_location(proxy);
760 } else if (!strcmp(DLS_INTERFACE_PROP_UDN, prop)) {
761 str = gupnp_device_info_get_udn(proxy);
762 } else if (!strcmp(DLS_INTERFACE_PROP_DEVICE_TYPE, prop)) {
763 str = gupnp_device_info_get_device_type(proxy);
764 } else if (!strcmp(DLS_INTERFACE_PROP_FRIENDLY_NAME, prop)) {
765 copy = gupnp_device_info_get_friendly_name(proxy);
767 } else if (!strcmp(DLS_INTERFACE_PROP_MANUFACTURER, prop)) {
768 copy = gupnp_device_info_get_manufacturer(proxy);
770 } else if (!strcmp(DLS_INTERFACE_PROP_MANUFACTURER_URL, prop)) {
771 copy = gupnp_device_info_get_manufacturer_url(proxy);
773 } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_DESCRIPTION, prop)) {
774 copy = gupnp_device_info_get_model_description(proxy);
776 } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_NAME, prop)) {
777 copy = gupnp_device_info_get_model_name(proxy);
779 } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_NUMBER, prop)) {
780 copy = gupnp_device_info_get_model_number(proxy);
782 } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_URL, prop)) {
783 copy = gupnp_device_info_get_model_url(proxy);
785 } else if (!strcmp(DLS_INTERFACE_PROP_SERIAL_NUMBER, prop)) {
786 copy = gupnp_device_info_get_serial_number(proxy);
788 } else if (!strcmp(DLS_INTERFACE_PROP_PRESENTATION_URL, prop)) {
789 copy = gupnp_device_info_get_presentation_url(proxy);
791 } else if (!strcmp(DLS_INTERFACE_PROP_ICON_URL, prop)) {
792 copy = gupnp_device_info_get_icon_url(proxy, NULL,
794 NULL, NULL, NULL, NULL);
796 } else if (!strcmp(DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES, prop)) {
797 list = gupnp_device_info_list_dlna_capabilities(proxy);
799 dlna_caps = prv_add_list_dlna_prop(list);
800 g_list_free_full(list, g_free);
801 retval = g_variant_ref_sink(dlna_caps);
803 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
804 copy = g_variant_print(dlna_caps, FALSE);
805 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
808 } else if (!strcmp(DLS_INTERFACE_PROP_SV_SEARCH_CAPABILITIES, prop)) {
809 if (device->search_caps != NULL) {
810 retval = g_variant_ref(device->search_caps);
812 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
813 copy = g_variant_print(device->search_caps, FALSE);
814 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
817 } else if (!strcmp(DLS_INTERFACE_PROP_SV_SORT_CAPABILITIES, prop)) {
818 if (device->sort_caps != NULL) {
819 retval = g_variant_ref(device->sort_caps);
821 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
822 copy = g_variant_print(device->sort_caps, FALSE);
823 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
826 } else if (!strcmp(DLS_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES, prop)) {
827 if (device->sort_ext_caps != NULL) {
828 retval = g_variant_ref(device->sort_ext_caps);
830 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
831 copy = g_variant_print(device->sort_ext_caps, FALSE);
832 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
835 } else if (!strcmp(DLS_INTERFACE_PROP_SV_FEATURE_LIST, prop)) {
836 if (device->feature_list != NULL) {
837 retval = g_variant_ref(device->feature_list);
839 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
840 copy = g_variant_print(device->feature_list, FALSE);
841 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
848 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
850 retval = g_variant_ref_sink(g_variant_new_string(str));
852 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_WARNING
854 DLEYNA_LOG_WARNING("Property %s not defined", prop);
863 static GUPnPDIDLLiteResource *prv_match_resource(GUPnPDIDLLiteResource *res,
864 gchar **pi_str_array)
866 GUPnPDIDLLiteResource *retval = NULL;
867 GUPnPProtocolInfo *res_pi;
868 GUPnPProtocolInfo *pi;
877 res_pi = gupnp_didl_lite_resource_get_protocol_info(res);
881 for (i = 0; pi_str_array[i]; ++i) {
882 pi = gupnp_protocol_info_new_from_string(pi_str_array[i],
886 match = gupnp_protocol_info_is_compatible(pi, res_pi);
898 static GUPnPDIDLLiteResource *prv_get_matching_resource
899 (GUPnPDIDLLiteObject *object, const gchar *protocol_info)
901 GUPnPDIDLLiteResource *retval = NULL;
902 GUPnPDIDLLiteResource *res;
905 gchar **pi_str_array = NULL;
908 pi_str_array = g_strsplit(protocol_info, ",", 0);
910 resources = gupnp_didl_lite_object_get_resources(object);
916 retval = prv_match_resource(res, pi_str_array);
926 g_list_free(resources);
928 g_strfreev(pi_str_array);
933 static void prv_parse_resources(GVariantBuilder *item_vb,
934 GUPnPDIDLLiteResource *res,
935 dls_upnp_prop_mask filter_mask)
937 GUPnPProtocolInfo *protocol_info;
943 if (filter_mask & DLS_UPNP_MASK_PROP_SIZE) {
944 int64_val = gupnp_didl_lite_resource_get_size64(res);
945 prv_add_int64_prop(item_vb, DLS_INTERFACE_PROP_SIZE, int64_val);
948 if (filter_mask & DLS_UPNP_MASK_PROP_BITRATE) {
949 int_val = gupnp_didl_lite_resource_get_bitrate(res);
950 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_BITRATE, int_val);
953 if (filter_mask & DLS_UPNP_MASK_PROP_SAMPLE_RATE) {
954 int_val = gupnp_didl_lite_resource_get_sample_freq(res);
955 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_SAMPLE_RATE,
959 if (filter_mask & DLS_UPNP_MASK_PROP_BITS_PER_SAMPLE) {
960 int_val = gupnp_didl_lite_resource_get_bits_per_sample(res);
961 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_BITS_PER_SAMPLE,
965 if (filter_mask & DLS_UPNP_MASK_PROP_DURATION) {
966 int_val = (int) gupnp_didl_lite_resource_get_duration(res);
967 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_DURATION, int_val);
970 if (filter_mask & DLS_UPNP_MASK_PROP_WIDTH) {
971 int_val = (int) gupnp_didl_lite_resource_get_width(res);
972 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_WIDTH, int_val);
975 if (filter_mask & DLS_UPNP_MASK_PROP_HEIGHT) {
976 int_val = (int) gupnp_didl_lite_resource_get_height(res);
977 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_HEIGHT, int_val);
980 if (filter_mask & DLS_UPNP_MASK_PROP_COLOR_DEPTH) {
981 int_val = (int) gupnp_didl_lite_resource_get_color_depth(res);
982 prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_COLOR_DEPTH,
986 if (filter_mask & DLS_UPNP_MASK_PROP_UPDATE_COUNT) {
987 uint_val = gupnp_didl_lite_resource_get_update_count(res);
988 prv_add_uint_prop(item_vb, DLS_INTERFACE_PROP_UPDATE_COUNT,
992 protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
994 if (filter_mask & DLS_UPNP_MASK_PROP_DLNA_PROFILE) {
995 str_val = gupnp_protocol_info_get_dlna_profile(protocol_info);
996 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_DLNA_PROFILE,
1000 if (filter_mask & DLS_UPNP_MASK_PROP_MIME_TYPE) {
1001 str_val = gupnp_protocol_info_get_mime_type(protocol_info);
1002 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_MIME_TYPE,
1007 static GVariant *prv_compute_create_classes(GUPnPDIDLLiteContainer *container)
1009 GVariantBuilder create_classes_vb;
1010 GList *create_classes;
1012 GUPnPDIDLLiteCreateClass *create_class;
1013 const char *content;
1014 gboolean inc_derived;
1016 g_variant_builder_init(&create_classes_vb, G_VARIANT_TYPE("a(sb)"));
1018 create_classes = gupnp_didl_lite_container_get_create_classes_full(
1020 ptr = create_classes;
1022 create_class = ptr->data;
1023 content = gupnp_didl_lite_create_class_get_content(
1025 inc_derived = gupnp_didl_lite_create_class_get_include_derived(
1027 g_variant_builder_add(&create_classes_vb,
1028 "(sb)", content, inc_derived);
1029 g_object_unref(ptr->data);
1030 ptr = g_list_next(ptr);
1032 g_list_free(create_classes);
1034 return g_variant_builder_end(&create_classes_vb);
1037 const gchar *dls_props_media_spec_to_upnp_class(const gchar *m2spec_class)
1039 const gchar *retval = NULL;
1041 if (!strcmp(m2spec_class, gMediaSpec2AlbumPhoto))
1042 retval = gUPnPPhotoAlbum;
1043 else if (!strcmp(m2spec_class, gMediaSpec2AlbumMusic))
1044 retval = gUPnPMusicAlbum;
1045 else if (!strcmp(m2spec_class, gMediaSpec2Album))
1046 retval = gUPnPAlbum;
1047 else if (!strcmp(m2spec_class, gMediaSpec2PersonMusicArtist))
1048 retval = gUPnPMusicArtist;
1049 else if (!strcmp(m2spec_class, gMediaSpec2Person))
1050 retval = gUPnPPerson;
1051 else if (!strcmp(m2spec_class, gMediaSpec2GenreMovie))
1052 retval = gUPnPMovieGenre;
1053 else if (!strcmp(m2spec_class, gMediaSpec2GenreMusic))
1054 retval = gUPnPMusicGenre;
1055 else if (!strcmp(m2spec_class, gMediaSpec2Genre))
1056 retval = gUPnPGenre;
1057 else if (!strcmp(m2spec_class, gMediaSpec2Container))
1058 retval = gUPnPContainer;
1059 else if (!strcmp(m2spec_class, gMediaSpec2AudioMusic))
1060 retval = gUPnPMusicTrack;
1061 else if (!strcmp(m2spec_class, gMediaSpec2AudioBroadcast))
1062 retval = gUPnPAudioBroadcast;
1063 else if (!strcmp(m2spec_class, gMediaSpec2AudioBook))
1064 retval = gUPnPAudioBook;
1065 else if (!strcmp(m2spec_class, gMediaSpec2Audio))
1066 retval = gUPnPAudioItem;
1067 else if (!strcmp(m2spec_class, gMediaSpec2VideoMovie))
1068 retval = gUPnPMovie;
1069 else if (!strcmp(m2spec_class, gMediaSpec2VideoMusicClip))
1070 retval = gUPnPMusicVideoClip;
1071 else if (!strcmp(m2spec_class, gMediaSpec2VideoBroadcast))
1072 retval = gUPnPVideoBroadcast;
1073 else if (!strcmp(m2spec_class, gMediaSpec2Video))
1074 retval = gUPnPVideoItem;
1075 else if (!strcmp(m2spec_class, gMediaSpec2ImagePhoto))
1076 retval = gUPnPPhoto;
1077 else if (!strcmp(m2spec_class, gMediaSpec2Image))
1078 retval = gUPnPImageItem;
1079 else if (!strcmp(m2spec_class, gMediaSpec2Playlist))
1080 retval = gUPnPPlaylistItem;
1081 else if (!strcmp(m2spec_class, gMediaSpec2Item))
1087 const gchar *dls_props_upnp_class_to_media_spec(const gchar *upnp_class)
1089 const gchar *retval = NULL;
1092 if (!strncmp(upnp_class, gUPnPAlbum, gUPnPAlbumLen)) {
1093 ptr = upnp_class + gUPnPAlbumLen;
1094 if (!strcmp(ptr, ".photoAlbum"))
1095 retval = gMediaSpec2AlbumPhoto;
1096 else if (!strcmp(ptr, ".musicAlbum"))
1097 retval = gMediaSpec2AlbumMusic;
1099 retval = gMediaSpec2Album;
1100 } else if (!strncmp(upnp_class, gUPnPPerson, gUPnPPersonLen)) {
1101 ptr = upnp_class + gUPnPPersonLen;
1102 if (!strcmp(ptr, ".musicArtist"))
1103 retval = gMediaSpec2PersonMusicArtist;
1105 retval = gMediaSpec2Person;
1106 } else if (!strncmp(upnp_class, gUPnPGenre, gUPnPGenreLen)) {
1107 ptr = upnp_class + gUPnPGenreLen;
1108 if (!strcmp(ptr, ".movieGenre"))
1109 retval = gMediaSpec2GenreMovie;
1110 else if (!strcmp(ptr, ".musicGenre"))
1111 retval = gMediaSpec2GenreMusic;
1113 retval = gMediaSpec2Genre;
1114 } else if (!strncmp(upnp_class, gUPnPContainer, gUPnPContainerLen)) {
1115 ptr = upnp_class + gUPnPContainerLen;
1116 if (!*ptr || *ptr == '.')
1117 retval = gMediaSpec2Container;
1118 } else if (!strncmp(upnp_class, gUPnPAudioItem, gUPnPAudioItemLen)) {
1119 ptr = upnp_class + gUPnPAudioItemLen;
1120 if (!strcmp(ptr, ".musicTrack"))
1121 retval = gMediaSpec2AudioMusic;
1122 else if (!strcmp(ptr, ".audioBroadcast"))
1123 retval = gMediaSpec2AudioBroadcast;
1124 else if (!strcmp(ptr, ".audioBook"))
1125 retval = gMediaSpec2AudioBook;
1127 retval = gMediaSpec2Audio;
1128 } else if (!strncmp(upnp_class, gUPnPVideoItem, gUPnPVideoItemLen)) {
1129 ptr = upnp_class + gUPnPVideoItemLen;
1130 if (!strcmp(ptr, ".movie"))
1131 retval = gMediaSpec2VideoMovie;
1132 else if (!strcmp(ptr, ".musicVideoClip"))
1133 retval = gMediaSpec2VideoMusicClip;
1134 else if (!strcmp(ptr, ".videoBroadcast"))
1135 retval = gMediaSpec2VideoBroadcast;
1137 retval = gMediaSpec2Video;
1138 } else if (!strncmp(upnp_class, gUPnPImageItem, gUPnPImageItemLen)) {
1139 ptr = upnp_class + gUPnPImageItemLen;
1140 if (!strcmp(ptr, ".photo"))
1141 retval = gMediaSpec2ImagePhoto;
1143 retval = gMediaSpec2Image;
1144 } else if (!strncmp(upnp_class, gUPnPPlaylistItem,
1145 gUPnPPlaylistItemLen)) {
1146 retval = gMediaSpec2Playlist;
1147 } else if (!strncmp(upnp_class, gUPnPItem, gUPnPItemLen)) {
1148 ptr = upnp_class + gUPnPItemLen;
1149 if (!*ptr || *ptr == '.')
1150 retval = gMediaSpec2Item;
1156 static GVariant *prv_props_get_dlna_managed_dict(GUPnPOCMFlags flags)
1158 GVariantBuilder builder;
1161 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sb}"));
1163 managed = (flags & GUPNP_OCM_FLAGS_UPLOAD);
1164 g_variant_builder_add(&builder, "{sb}", "Upload", managed);
1166 managed = (flags & GUPNP_OCM_FLAGS_CREATE_CONTAINER);
1167 g_variant_builder_add(&builder, "{sb}", "CreateContainer", managed);
1169 managed = (flags & GUPNP_OCM_FLAGS_DESTROYABLE);
1170 g_variant_builder_add(&builder, "{sb}", "Delete", managed);
1172 managed = (flags & GUPNP_OCM_FLAGS_UPLOAD_DESTROYABLE);
1173 g_variant_builder_add(&builder, "{sb}", "UploadDelete", managed);
1175 managed = (flags & GUPNP_OCM_FLAGS_CHANGE_METADATA);
1176 g_variant_builder_add(&builder, "{sb}", "ChangeMeta", managed);
1178 return g_variant_builder_end(&builder);
1181 gboolean dls_props_add_object(GVariantBuilder *item_vb,
1182 GUPnPDIDLLiteObject *object,
1183 const char *root_path,
1184 const gchar *parent_path,
1185 dls_upnp_prop_mask filter_mask)
1190 const char *creator;
1191 const char *upnp_class;
1192 const char *media_spec_type;
1193 gboolean retval = FALSE;
1195 GUPnPOCMFlags flags;
1198 id = gupnp_didl_lite_object_get_id(object);
1202 upnp_class = gupnp_didl_lite_object_get_upnp_class(object);
1203 media_spec_type = dls_props_upnp_class_to_media_spec(upnp_class);
1205 if (!media_spec_type)
1208 title = gupnp_didl_lite_object_get_title(object);
1209 creator = gupnp_didl_lite_object_get_creator(object);
1210 rest = gupnp_didl_lite_object_get_restricted(object);
1211 path = dls_path_from_id(root_path, id);
1213 if (filter_mask & DLS_UPNP_MASK_PROP_DISPLAY_NAME)
1214 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_DISPLAY_NAME,
1217 if (filter_mask & DLS_UPNP_MASK_PROP_CREATOR)
1218 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_CREATOR,
1221 if (filter_mask & DLS_UPNP_MASK_PROP_PATH)
1222 prv_add_path_prop(item_vb, DLS_INTERFACE_PROP_PATH, path);
1224 if (filter_mask & DLS_UPNP_MASK_PROP_PARENT)
1225 prv_add_path_prop(item_vb, DLS_INTERFACE_PROP_PARENT,
1228 if (filter_mask & DLS_UPNP_MASK_PROP_TYPE)
1229 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_TYPE,
1232 if (filter_mask & DLS_UPNP_MASK_PROP_RESTRICTED)
1233 prv_add_bool_prop(item_vb, DLS_INTERFACE_PROP_RESTRICTED, rest);
1235 if (filter_mask & DLS_UPNP_MASK_PROP_DLNA_MANAGED) {
1236 flags = gupnp_didl_lite_object_get_dlna_managed(object);
1237 prv_add_variant_prop(item_vb,
1238 DLS_INTERFACE_PROP_DLNA_MANAGED,
1239 prv_props_get_dlna_managed_dict(flags));
1242 if (filter_mask & DLS_UPNP_MASK_PROP_OBJECT_UPDATE_ID) {
1243 uint_val = gupnp_didl_lite_object_get_update_id(object);
1244 prv_add_uint_prop(item_vb, DLS_INTERFACE_PROP_OBJECT_UPDATE_ID,
1257 void dls_props_add_container(GVariantBuilder *item_vb,
1258 GUPnPDIDLLiteContainer *object,
1259 dls_upnp_prop_mask filter_mask,
1260 gboolean *have_child_count)
1263 gboolean searchable;
1266 *have_child_count = FALSE;
1267 if (filter_mask & DLS_UPNP_MASK_PROP_CHILD_COUNT) {
1268 child_count = gupnp_didl_lite_container_get_child_count(object);
1269 if (child_count >= 0) {
1270 prv_add_uint_prop(item_vb,
1271 DLS_INTERFACE_PROP_CHILD_COUNT,
1272 (unsigned int) child_count);
1273 *have_child_count = TRUE;
1277 if (filter_mask & DLS_UPNP_MASK_PROP_SEARCHABLE) {
1278 searchable = gupnp_didl_lite_container_get_searchable(object);
1279 prv_add_bool_prop(item_vb, DLS_INTERFACE_PROP_SEARCHABLE,
1283 if (filter_mask & DLS_UPNP_MASK_PROP_CREATE_CLASSES)
1284 prv_add_variant_prop(item_vb,
1285 DLS_INTERFACE_PROP_CREATE_CLASSES,
1286 prv_compute_create_classes(object));
1288 if (filter_mask & DLS_UPNP_MASK_PROP_CONTAINER_UPDATE_ID) {
1289 uint_val = gupnp_didl_lite_container_get_container_update_id(
1291 prv_add_uint_prop(item_vb,
1292 DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID,
1296 if (filter_mask & DLS_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT) {
1298 gupnp_didl_lite_container_get_total_deleted_child_count(object);
1299 prv_add_uint_prop(item_vb,
1300 DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT,
1305 static GVariant *prv_compute_resources(GUPnPDIDLLiteObject *object,
1306 dls_upnp_prop_mask filter_mask)
1308 GUPnPDIDLLiteResource *res = NULL;
1311 GVariantBuilder *res_array_vb;
1312 GVariantBuilder *res_vb;
1313 const char *str_val;
1316 res_array_vb = g_variant_builder_new(G_VARIANT_TYPE("aa{sv}"));
1318 resources = gupnp_didl_lite_object_get_resources(object);
1323 res_vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
1324 if (filter_mask & DLS_UPNP_MASK_PROP_URL) {
1325 str_val = gupnp_didl_lite_resource_get_uri(res);
1327 prv_add_string_prop(res_vb,
1328 DLS_INTERFACE_PROP_URL,
1331 prv_parse_resources(res_vb, res, filter_mask);
1332 g_variant_builder_add(res_array_vb, "@a{sv}",
1333 g_variant_builder_end(res_vb));
1334 g_variant_builder_unref(res_vb);
1335 g_object_unref(ptr->data);
1336 ptr = g_list_next(ptr);
1338 retval = g_variant_builder_end(res_array_vb);
1339 g_variant_builder_unref(res_array_vb);
1341 g_list_free(resources);
1346 static void prv_add_resources(GVariantBuilder *item_vb,
1347 GUPnPDIDLLiteObject *object,
1348 dls_upnp_prop_mask filter_mask)
1352 val = prv_compute_resources(object, filter_mask);
1353 g_variant_builder_add(item_vb, "{sv}", DLS_INTERFACE_PROP_RESOURCES,
1357 void dls_props_add_item(GVariantBuilder *item_vb,
1358 GUPnPDIDLLiteObject *object,
1359 const gchar *root_path,
1360 dls_upnp_prop_mask filter_mask,
1361 const gchar *protocol_info)
1364 GUPnPDIDLLiteResource *res;
1365 const char *str_val;
1369 if (filter_mask & DLS_UPNP_MASK_PROP_ARTIST)
1370 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_ARTIST,
1371 gupnp_didl_lite_object_get_artist(object));
1373 if (filter_mask & DLS_UPNP_MASK_PROP_ARTISTS) {
1374 list = gupnp_didl_lite_object_get_artists(object);
1375 prv_add_variant_prop(item_vb, DLS_INTERFACE_PROP_ARTISTS,
1376 prv_get_artists_prop(list));
1377 g_list_free_full(list, g_object_unref);
1380 if (filter_mask & DLS_UPNP_MASK_PROP_ALBUM)
1381 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_ALBUM,
1382 gupnp_didl_lite_object_get_album(object));
1384 if (filter_mask & DLS_UPNP_MASK_PROP_DATE)
1385 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_DATE,
1386 gupnp_didl_lite_object_get_date(object));
1388 if (filter_mask & DLS_UPNP_MASK_PROP_GENRE)
1389 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_GENRE,
1390 gupnp_didl_lite_object_get_genre(object));
1392 if (filter_mask & DLS_UPNP_MASK_PROP_TRACK_NUMBER) {
1393 track_number = gupnp_didl_lite_object_get_track_number(object);
1394 if (track_number >= 0)
1395 prv_add_int_prop(item_vb,
1396 DLS_INTERFACE_PROP_TRACK_NUMBER,
1400 if (filter_mask & DLS_UPNP_MASK_PROP_ALBUM_ART_URL)
1401 prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_ALBUM_ART_URL,
1402 gupnp_didl_lite_object_get_album_art(
1405 if (filter_mask & DLS_UPNP_MASK_PROP_REFPATH) {
1406 str_val = gupnp_didl_lite_item_get_ref_id(
1407 GUPNP_DIDL_LITE_ITEM(object));
1408 if (str_val != NULL) {
1409 path = dls_path_from_id(root_path, str_val);
1410 prv_add_path_prop(item_vb, DLS_INTERFACE_PROP_REFPATH,
1416 res = prv_get_matching_resource(object, protocol_info);
1418 if (filter_mask & DLS_UPNP_MASK_PROP_URLS) {
1419 str_val = gupnp_didl_lite_resource_get_uri(res);
1421 prv_add_strv_prop(item_vb,
1422 DLS_INTERFACE_PROP_URLS,
1425 prv_parse_resources(item_vb, res, filter_mask);
1426 g_object_unref(res);
1429 if (filter_mask & DLS_UPNP_MASK_PROP_RESOURCES)
1430 prv_add_resources(item_vb, object, filter_mask);
1433 void dls_props_add_resource(GVariantBuilder *item_vb,
1434 GUPnPDIDLLiteObject *object,
1435 dls_upnp_prop_mask filter_mask,
1436 const gchar *protocol_info)
1438 GUPnPDIDLLiteResource *res;
1439 const char *str_val;
1441 res = prv_get_matching_resource(object, protocol_info);
1443 if (filter_mask & DLS_UPNP_MASK_PROP_URL) {
1444 str_val = gupnp_didl_lite_resource_get_uri(res);
1446 prv_add_string_prop(item_vb,
1447 DLS_INTERFACE_PROP_URL,
1450 prv_parse_resources(item_vb, res, filter_mask);
1451 g_object_unref(res);
1456 static GVariant *prv_get_resource_property(const gchar *prop,
1457 GUPnPDIDLLiteResource *res)
1461 const char *str_val;
1462 GVariant *retval = NULL;
1463 GUPnPProtocolInfo *protocol_info;
1465 if (!strcmp(prop, DLS_INTERFACE_PROP_DLNA_PROFILE)) {
1466 protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
1469 str_val = gupnp_protocol_info_get_dlna_profile(protocol_info);
1472 retval = g_variant_ref_sink(g_variant_new_string(str_val));
1473 } else if (!strcmp(prop, DLS_INTERFACE_PROP_MIME_TYPE)) {
1474 protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
1477 str_val = gupnp_protocol_info_get_mime_type(protocol_info);
1480 retval = g_variant_ref_sink(g_variant_new_string(str_val));
1481 } else if (!strcmp(prop, DLS_INTERFACE_PROP_SIZE)) {
1482 int64_val = gupnp_didl_lite_resource_get_size64(res);
1483 if (int64_val == -1)
1485 retval = g_variant_ref_sink(g_variant_new_int64(int64_val));
1486 } else if (!strcmp(prop, DLS_INTERFACE_PROP_DURATION)) {
1487 int_val = (int) gupnp_didl_lite_resource_get_duration(res);
1490 retval = g_variant_ref_sink(g_variant_new_int32(int_val));
1491 } else if (!strcmp(prop, DLS_INTERFACE_PROP_BITRATE)) {
1492 int_val = gupnp_didl_lite_resource_get_bitrate(res);
1495 retval = g_variant_ref_sink(g_variant_new_int32(int_val));
1496 } else if (!strcmp(prop, DLS_INTERFACE_PROP_SAMPLE_RATE)) {
1497 int_val = gupnp_didl_lite_resource_get_sample_freq(res);
1500 retval = g_variant_ref_sink(g_variant_new_int32(int_val));
1501 } else if (!strcmp(prop, DLS_INTERFACE_PROP_BITS_PER_SAMPLE)) {
1502 int_val = gupnp_didl_lite_resource_get_bits_per_sample(res);
1505 retval = g_variant_ref_sink(g_variant_new_int32(int_val));
1506 } else if (!strcmp(prop, DLS_INTERFACE_PROP_WIDTH)) {
1507 int_val = (int) gupnp_didl_lite_resource_get_width(res);
1510 retval = g_variant_ref_sink(g_variant_new_int32(int_val));
1511 } else if (!strcmp(prop, DLS_INTERFACE_PROP_HEIGHT)) {
1512 int_val = (int) gupnp_didl_lite_resource_get_height(res);
1515 retval = g_variant_ref_sink(g_variant_new_int32(int_val));
1516 } else if (!strcmp(prop, DLS_INTERFACE_PROP_COLOR_DEPTH)) {
1517 int_val = (int) gupnp_didl_lite_resource_get_color_depth(res);
1520 retval = g_variant_ref_sink(g_variant_new_int32(int_val));
1521 } else if (!strcmp(prop, DLS_INTERFACE_PROP_URLS)) {
1522 str_val = gupnp_didl_lite_resource_get_uri(res);
1524 retval = g_variant_new_strv(&str_val, 1);
1532 GVariant *dls_props_get_object_prop(const gchar *prop, const gchar *root_path,
1533 GUPnPDIDLLiteObject *object)
1537 const char *upnp_class;
1538 const char *media_spec_type;
1541 GVariant *retval = NULL;
1542 GUPnPOCMFlags dlna_managed;
1545 if (!strcmp(prop, DLS_INTERFACE_PROP_PARENT)) {
1546 id = gupnp_didl_lite_object_get_parent_id(object);
1547 if (!id || !strcmp(id, "-1")) {
1548 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, root_path);
1550 retval = g_variant_ref_sink(g_variant_new_string(
1553 path = dls_path_from_id(root_path, id);
1555 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, path);
1557 retval = g_variant_ref_sink(g_variant_new_string(
1561 } else if (!strcmp(prop, DLS_INTERFACE_PROP_PATH)) {
1562 id = gupnp_didl_lite_object_get_id(object);
1566 path = dls_path_from_id(root_path, id);
1568 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, path);
1570 retval = g_variant_ref_sink(g_variant_new_string(path));
1572 } else if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE)) {
1573 upnp_class = gupnp_didl_lite_object_get_upnp_class(object);
1575 dls_props_upnp_class_to_media_spec(upnp_class);
1576 if (!media_spec_type)
1579 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, media_spec_type);
1581 retval = g_variant_ref_sink(g_variant_new_string(
1583 } else if (!strcmp(prop, DLS_INTERFACE_PROP_DISPLAY_NAME)) {
1584 title = gupnp_didl_lite_object_get_title(object);
1588 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, title);
1590 retval = g_variant_ref_sink(g_variant_new_string(title));
1591 } else if (!strcmp(prop, DLS_INTERFACE_PROP_CREATOR)) {
1592 title = gupnp_didl_lite_object_get_creator(object);
1596 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, title);
1598 retval = g_variant_ref_sink(g_variant_new_string(title));
1599 } else if (!strcmp(prop, DLS_INTERFACE_PROP_RESTRICTED)) {
1600 rest = gupnp_didl_lite_object_get_restricted(object);
1602 DLEYNA_LOG_DEBUG("Prop %s = %d", prop, rest);
1604 retval = g_variant_ref_sink(g_variant_new_boolean(rest));
1605 } else if (!strcmp(prop, DLS_INTERFACE_PROP_DLNA_MANAGED)) {
1606 dlna_managed = gupnp_didl_lite_object_get_dlna_managed(object);
1608 DLEYNA_LOG_DEBUG("Prop %s = %0x", prop, dlna_managed);
1610 retval = g_variant_ref_sink(
1611 prv_props_get_dlna_managed_dict(dlna_managed));
1612 } else if (!strcmp(prop, DLS_INTERFACE_PROP_OBJECT_UPDATE_ID)) {
1613 uint_val = gupnp_didl_lite_object_get_update_id(object);
1615 DLEYNA_LOG_DEBUG("Prop %s = %u", prop, uint_val);
1617 retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
1625 GVariant *dls_props_get_item_prop(const gchar *prop, const gchar *root_path,
1626 GUPnPDIDLLiteObject *object,
1627 const gchar *protocol_info)
1632 GUPnPDIDLLiteResource *res;
1633 GVariant *retval = NULL;
1636 if (GUPNP_IS_DIDL_LITE_CONTAINER(object))
1639 if (!strcmp(prop, DLS_INTERFACE_PROP_ARTIST)) {
1640 str = gupnp_didl_lite_object_get_artist(object);
1644 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
1646 retval = g_variant_ref_sink(g_variant_new_string(str));
1647 } else if (!strcmp(prop, DLS_INTERFACE_PROP_ARTISTS)) {
1648 list = gupnp_didl_lite_object_get_artists(object);
1652 retval = g_variant_ref_sink(prv_get_artists_prop(list));
1653 g_list_free_full(list, g_object_unref);
1655 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
1656 path = g_variant_print(retval, FALSE);
1657 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, path);
1660 } else if (!strcmp(prop, DLS_INTERFACE_PROP_ALBUM)) {
1661 str = gupnp_didl_lite_object_get_album(object);
1665 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
1667 retval = g_variant_ref_sink(g_variant_new_string(str));
1668 } else if (!strcmp(prop, DLS_INTERFACE_PROP_DATE)) {
1669 str = gupnp_didl_lite_object_get_date(object);
1673 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
1675 retval = g_variant_ref_sink(g_variant_new_string(str));
1676 } else if (!strcmp(prop, DLS_INTERFACE_PROP_GENRE)) {
1677 str = gupnp_didl_lite_object_get_genre(object);
1681 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
1683 retval = g_variant_ref_sink(g_variant_new_string(str));
1684 } else if (!strcmp(prop, DLS_INTERFACE_PROP_TRACK_NUMBER)) {
1685 track_number = gupnp_didl_lite_object_get_track_number(object);
1686 if (track_number < 0)
1689 DLEYNA_LOG_DEBUG("Prop %s = %d", prop, track_number);
1691 retval = g_variant_ref_sink(
1692 g_variant_new_int32(track_number));
1693 } else if (!strcmp(prop, DLS_INTERFACE_PROP_ALBUM_ART_URL)) {
1694 str = gupnp_didl_lite_object_get_album_art(object);
1698 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
1700 retval = g_variant_ref_sink(g_variant_new_string(str));
1701 } else if (!strcmp(prop, DLS_INTERFACE_PROP_REFPATH)) {
1702 str = gupnp_didl_lite_item_get_ref_id(
1703 GUPNP_DIDL_LITE_ITEM(object));
1707 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
1709 path = dls_path_from_id(root_path, str);
1710 retval = g_variant_ref_sink(g_variant_new_string(path));
1712 } else if (!strcmp(prop, DLS_INTERFACE_PROP_RESOURCES)) {
1713 retval = g_variant_ref_sink(
1714 prv_compute_resources(object, DLS_UPNP_MASK_ALL_PROPS));
1716 res = prv_get_matching_resource(object, protocol_info);
1720 retval = prv_get_resource_property(prop, res);
1722 g_object_unref(res);
1730 GVariant *dls_props_get_container_prop(const gchar *prop,
1731 GUPnPDIDLLiteObject *object)
1734 gboolean searchable;
1735 GUPnPDIDLLiteContainer *container;
1736 GVariant *retval = NULL;
1738 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
1739 gchar *create_classes;
1741 if (!GUPNP_IS_DIDL_LITE_CONTAINER(object))
1744 container = (GUPnPDIDLLiteContainer *)object;
1745 if (!strcmp(prop, DLS_INTERFACE_PROP_CHILD_COUNT)) {
1747 gupnp_didl_lite_container_get_child_count(container);
1749 DLEYNA_LOG_DEBUG("Prop %s = %d", prop, child_count);
1751 if (child_count >= 0) {
1752 retval = g_variant_new_uint32((guint) child_count);
1753 retval = g_variant_ref_sink(retval);
1755 } else if (!strcmp(prop, DLS_INTERFACE_PROP_SEARCHABLE)) {
1757 gupnp_didl_lite_container_get_searchable(container);
1759 DLEYNA_LOG_DEBUG("Prop %s = %d", prop, searchable);
1761 retval = g_variant_ref_sink(
1762 g_variant_new_boolean(searchable));
1763 } else if (!strcmp(prop, DLS_INTERFACE_PROP_CREATE_CLASSES)) {
1764 retval = g_variant_ref_sink(
1765 prv_compute_create_classes(container));
1766 #if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
1767 create_classes = g_variant_print(retval, FALSE);
1768 DLEYNA_LOG_DEBUG("Prop %s = %s", prop, create_classes);
1769 g_free(create_classes);
1771 } else if (!strcmp(prop, DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID)) {
1772 uint_val = gupnp_didl_lite_container_get_container_update_id(
1775 DLEYNA_LOG_DEBUG("Prop %s = %u", prop, uint_val);
1777 retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
1778 } else if (!strcmp(prop,
1779 DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT)) {
1781 gupnp_didl_lite_container_get_total_deleted_child_count(
1784 DLEYNA_LOG_DEBUG("Prop %s = %u", prop, uint_val);
1786 retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));