2 * Copyright (C) 2016 "IoT.bzh"
3 * Author "Manuel Bachmann"
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "media-api.h"
21 /* -------------- MEDIA RYGEL IMPLEMENTATION ---------------- */
23 /* --- PUBLIC FUNCTIONS --- */
25 PUBLIC unsigned char _rygel_init (mediaCtxHandleT *ctx) {
28 GUPnPContext *context;
29 GUPnPControlPoint *control_point;
30 struct timeval tv_start, tv_now;
32 context = gupnp_context_new (NULL, NULL, 0, NULL);
34 control_point = gupnp_control_point_new (context, URN_MEDIA_SERVER);
36 g_signal_connect (control_point, "device-proxy-available",
37 G_CALLBACK (_rygel_device_cb), ctx);
39 /* start searching for servers */
40 gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (control_point), TRUE);
42 loop = g_main_context_default ();
44 /* 5 seconds should be sufficient to find Rygel */
45 gettimeofday (&tv_start, NULL);
46 gettimeofday (&tv_now, NULL);
47 while (tv_now.tv_sec - tv_start.tv_sec <= 5) {
49 g_main_context_iteration (loop, FALSE);
51 if (ctx->media_server)
54 /* fail if we found no server */
55 if (!ctx->media_server)
58 dev_ctx[client_count]->loop = loop;
59 dev_ctx[client_count]->context = context;
66 PUBLIC void _rygel_free (mediaCtxHandleT *ctx) {
68 dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server;
72 g_main_context_unref (dev_ctx_c->loop);
73 dev_ctx_c->loop = NULL;
74 dev_ctx_c->context = NULL;
75 dev_ctx_c->device_info = NULL;
76 dev_ctx_c->content_dir = NULL;
79 PUBLIC char* _rygel_list (mediaCtxHandleT *ctx) {
81 dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server;
82 GUPnPServiceProxy *content_dir_proxy;
84 dev_ctx_c->content_res = NULL;
85 content_dir_proxy = GUPNP_SERVICE_PROXY (dev_ctx_c->content_dir);
87 gupnp_service_proxy_begin_action (content_dir_proxy, "Browse", _rygel_content_cb, dev_ctx_c,
88 "ObjectID", G_TYPE_STRING, "Filesystem",
89 "BrowseFlag", G_TYPE_STRING, "BrowseDirectChildren",
90 "Filter", G_TYPE_STRING, "@childCount",
91 "StartingIndex", G_TYPE_UINT, 0,
92 "RequestedCount", G_TYPE_UINT, 64,
93 "SortCriteria", G_TYPE_STRING, "",
96 while (!dev_ctx_c->content_res)
97 g_main_context_iteration (dev_ctx_c->loop, FALSE);
99 return dev_ctx_c->content_res;
102 /* ---- LOCAL CALLBACK FUNCTIONS ---- */
104 STATIC void _rygel_device_cb (GUPnPControlPoint *point, GUPnPDeviceProxy *proxy,
107 mediaCtxHandleT *ctx = (mediaCtxHandleT*)data;
108 GUPnPDeviceInfo *device_info;
109 GUPnPServiceInfo *content_dir;
110 const char *device_name;
112 device_info = GUPNP_DEVICE_INFO (proxy);
113 device_name = gupnp_device_info_get_model_name (device_info);
114 content_dir = gupnp_device_info_get_service (device_info, URN_CONTENT_DIR);
116 if (strcmp (device_name, "Rygel") != 0)
121 /* allocate the global array if it has not been not done */
123 dev_ctx = (dev_ctx_T**) malloc (sizeof(dev_ctx_T));
125 dev_ctx = (dev_ctx_T**) realloc (dev_ctx, (client_count+1)*sizeof(dev_ctx_T));
127 /* create an element for the client in the global array */
128 dev_ctx[client_count] = malloc (sizeof(dev_ctx_T));
129 dev_ctx[client_count]->device_info = device_info;
130 dev_ctx[client_count]->content_dir = content_dir;
132 /* make the client context aware of it */
133 ctx->media_server = (void*)dev_ctx[client_count];
136 STATIC void _rygel_content_cb (GUPnPServiceProxy *content_dir, GUPnPServiceProxyAction *action,
139 dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data;
140 GUPnPServiceProxy *content_dir_proxy = GUPNP_SERVICE_PROXY (content_dir);
143 guint32 number_returned;
144 guint32 total_matches;
148 gupnp_service_proxy_end_action (content_dir, action, &error,
149 "Result", G_TYPE_STRING, &result,
150 "NumberReturned", G_TYPE_UINT, &number_returned,
151 "TotalMatches", G_TYPE_UINT, &total_matches,
154 if (number_returned == 0)
157 if (number_returned == 1) {
158 found = strstr (result, "id=\"");
160 strncpy (subid, found, 32); subid[32] = '\0';
162 gupnp_service_proxy_begin_action (content_dir_proxy, "Browse", _rygel_content_cb, NULL,
163 "ObjectID", G_TYPE_STRING, subid,
164 "BrowseFlag", G_TYPE_STRING, "BrowseDirectChildren",
165 "Filter", G_TYPE_STRING, "@childCount",
166 "StartingIndex", G_TYPE_UINT, 0,
167 "RequestedCount", G_TYPE_UINT, 64,
168 "SortCriteria", G_TYPE_STRING, "",
173 if (number_returned > 1)
174 dev_ctx_c->content_res = strdup (result);