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 handler_cb = 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)
53 gettimeofday (&tv_now, NULL);
55 /* fail if we found no server */
56 if (!ctx->media_server)
59 dev_ctx[client_count]->loop = loop;
60 dev_ctx[client_count]->context = context;
67 PUBLIC void _rygel_free (mediaCtxHandleT *ctx) {
69 dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server;
73 g_main_context_unref (dev_ctx_c->loop);
74 dev_ctx_c->loop = NULL;
75 dev_ctx_c->context = NULL;
76 dev_ctx_c->device_info = NULL;
77 dev_ctx_c->content_dir = NULL;
78 if (dev_ctx_c->content_res)
79 free (dev_ctx_c->content_res);
80 dev_ctx_c->content_res = NULL;
83 PUBLIC char* _rygel_list (mediaCtxHandleT *ctx) {
85 dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server;
86 GUPnPServiceProxy *content_dir_proxy;
87 struct timeval tv_start, tv_now;
89 if (dev_ctx_c->content_res)
90 free (dev_ctx_c->content_res);
91 dev_ctx_c->content_res = NULL;
93 content_dir_proxy = GUPNP_SERVICE_PROXY (dev_ctx_c->content_dir);
95 gupnp_service_proxy_begin_action (content_dir_proxy, "Browse", _rygel_content_cb, dev_ctx_c,
96 "ObjectID", G_TYPE_STRING, "Filesystem",
97 "BrowseFlag", G_TYPE_STRING, "BrowseDirectChildren",
98 "Filter", G_TYPE_STRING, "@childCount",
99 "StartingIndex", G_TYPE_UINT, 0,
100 "RequestedCount", G_TYPE_UINT, 64,
101 "SortCriteria", G_TYPE_STRING, "",
104 gettimeofday (&tv_start, NULL);
105 gettimeofday (&tv_now, NULL);
106 while (tv_now.tv_sec - tv_start.tv_sec <= 5) {
108 g_main_context_iteration (dev_ctx_c->loop, FALSE);
110 if (dev_ctx_c->content_res)
112 gettimeofday (&tv_now, NULL);
115 return dev_ctx_c->content_res;
118 /* ---- LOCAL CALLBACK FUNCTIONS ---- */
120 STATIC void _rygel_device_cb (GUPnPControlPoint *point, GUPnPDeviceProxy *proxy,
123 mediaCtxHandleT *ctx = (mediaCtxHandleT*)data;
124 GUPnPDeviceInfo *device_info;
125 GUPnPServiceInfo *content_dir;
126 const char *device_name;
128 device_info = GUPNP_DEVICE_INFO (proxy);
129 device_name = gupnp_device_info_get_model_name (device_info);
130 content_dir = gupnp_device_info_get_service (device_info, URN_CONTENT_DIR);
132 if (strcmp (device_name, "Rygel") != 0)
137 /* we have found Rygel ; stop looking for it... */
138 g_signal_handler_disconnect (point, handler_cb);
140 /* allocate the global array if it has not been not done */
142 dev_ctx = (dev_ctx_T**) malloc (sizeof(dev_ctx_T));
144 dev_ctx = (dev_ctx_T**) realloc (dev_ctx, (client_count+1)*sizeof(dev_ctx_T));
146 /* create an element for the client in the global array */
147 dev_ctx[client_count] = (dev_ctx_T*) malloc (sizeof(dev_ctx_T));
148 dev_ctx[client_count]->device_info = device_info;
149 dev_ctx[client_count]->content_dir = content_dir;
151 /* make the client context aware of it */
152 ctx->media_server = (void*)dev_ctx[client_count];
155 STATIC void _rygel_content_cb (GUPnPServiceProxy *content_dir, GUPnPServiceProxyAction *action,
158 dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data;
159 GUPnPServiceProxy *content_dir_proxy = GUPNP_SERVICE_PROXY (content_dir);
162 guint32 number_returned;
163 guint32 total_matches;
167 gupnp_service_proxy_end_action (content_dir, action, &error,
168 "Result", G_TYPE_STRING, &result,
169 "NumberReturned", G_TYPE_UINT, &number_returned,
170 "TotalMatches", G_TYPE_UINT, &total_matches,
173 if (number_returned == 0)
176 if (number_returned == 1) {
177 found = strstr (result, "id=\"");
179 strncpy (subid, found, 32); subid[32] = '\0';
181 gupnp_service_proxy_begin_action (content_dir_proxy, "Browse", _rygel_content_cb, dev_ctx_c,
182 "ObjectID", G_TYPE_STRING, subid,
183 "BrowseFlag", G_TYPE_STRING, "BrowseDirectChildren",
184 "Filter", G_TYPE_STRING, "@childCount",
185 "StartingIndex", G_TYPE_UINT, 0,
186 "RequestedCount", G_TYPE_UINT, 64,
187 "SortCriteria", G_TYPE_STRING, "",
192 if (number_returned > 1)
193 dev_ctx_c->content_res = strdup (result);