hythmbox-2.98/plugins/daap/rb-daap-src.c

No issues found

  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2  *
  3  *  Implementatin of DAAP (iTunes Music Sharing) GStreamer source
  4  *
  5  *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
  6  *
  7  *  This program is free software; you can redistribute it and/or modify
  8  *  it under the terms of the GNU General Public License as published by
  9  *  the Free Software Foundation; either version 2 of the License, or
 10  *  (at your option) any later version.
 11  *
 12  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 13  *  GStreamer plugins to be used and distributed together with GStreamer
 14  *  and Rhythmbox. This permission is above and beyond the permissions granted
 15  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 16  *  you may extend this exception to your version of the code, but you are not
 17  *  obligated to do so. If you do not wish to do so, delete this exception
 18  *  statement from your version.
 19  *
 20  *  This program is distributed in the hope that it will be useful,
 21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 23  *  GNU General Public License for more details.
 24  *
 25  *  You should have received a copy of the GNU General Public License
 26  *  along with this program; if not, write to the Free Software
 27  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 28  *
 29  */
 30 
 31 #include "config.h"
 32 
 33 #include <gst/gst.h>
 34 #include <string.h>
 35 
 36 #include "rb-daap-plugin.h"
 37 #include "rb-daap-src.h"
 38 
 39 #define RB_TYPE_DAAP_SRC (rb_daap_src_get_type())
 40 #define RB_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RB_TYPE_DAAP_SRC,RBDAAPSrc))
 41 #define RB_DAAP_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RB_TYPE_DAAP_SRC,RBDAAPSrcClass))
 42 #define RB_IS_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RB_TYPE_DAAP_SRC))
 43 #define RB_IS_DAAP_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),RB_TYPE_DAAP_SRC))
 44 
 45 typedef struct _RBDAAPSrc RBDAAPSrc;
 46 typedef struct _RBDAAPSrcClass RBDAAPSrcClass;
 47 
 48 struct _RBDAAPSrc
 49 {
 50 	GstBin parent;
 51 
 52 	/* uri */
 53 	gchar *daap_uri;
 54 
 55 	GstElement *souphttpsrc;
 56 	GstPad *ghostpad;
 57 };
 58 
 59 struct _RBDAAPSrcClass
 60 {
 61 	GstBinClass parent_class;
 62 };
 63 
 64 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
 65 	GST_PAD_SRC,
 66 	GST_PAD_ALWAYS,
 67 	GST_STATIC_CAPS_ANY);
 68 
 69 GST_DEBUG_CATEGORY_STATIC (rb_daap_src_debug);
 70 #define GST_CAT_DEFAULT rb_daap_src_debug
 71 
 72 static GstElementDetails rb_daap_src_details =
 73 GST_ELEMENT_DETAILS ("RBDAAP Source",
 74 	"Source/File",
 75 	"Read a DAAP (music share) file",
 76 	"Charles Schmidt <cschmidt2@emich.edu");
 77 
 78 static RBDaapPlugin *daap_plugin = NULL;
 79 
 80 static void rb_daap_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
 81 
 82 static void
 83 _do_init (GType daap_src_type)
 84 {
 85 	static const GInterfaceInfo urihandler_info = {
 86 		rb_daap_src_uri_handler_init,
 87 		NULL,
 88 		NULL
 89 	};
 90 	GST_DEBUG_CATEGORY_INIT (rb_daap_src_debug,
 91 				 "daapsrc", GST_DEBUG_FG_WHITE,
 92 				 "Rhythmbox built in DAAP source element");
 93 
 94 	g_type_add_interface_static (daap_src_type, GST_TYPE_URI_HANDLER,
 95 			&urihandler_info);
 96 }
 97 
 98 GST_BOILERPLATE_FULL (RBDAAPSrc, rb_daap_src, GstBin, GST_TYPE_BIN, _do_init);
 99 
100 static void rb_daap_src_dispose (GObject *object);
101 static void rb_daap_src_set_property (GObject *object,
102 			  guint prop_id,
103 			  const GValue *value,
104 			  GParamSpec *pspec);
105 static void rb_daap_src_get_property (GObject *object,
106 		          guint prop_id,
107 			  GValue *value,
108 			  GParamSpec *pspec);
109 
110 static GstStateChangeReturn rb_daap_src_change_state (GstElement *element, GstStateChange transition);
111 
112 void
113 rb_daap_src_set_plugin (GObject *plugin)
114 {
115 	g_assert (RB_IS_DAAP_PLUGIN (plugin));
116 	daap_plugin = RB_DAAP_PLUGIN (plugin);
117 }
118 
119 enum
120 {
121 	PROP_0,
122 	PROP_LOCATION,
123 };
124 
125 static void
126 rb_daap_src_base_init (gpointer g_class)
127 {
128 	GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
129 	gst_element_class_add_pad_template (element_class,
130 		gst_static_pad_template_get (&srctemplate));
131 	gst_element_class_set_details (element_class, &rb_daap_src_details);
132 }
133 
134 static void
135 rb_daap_src_class_init (RBDAAPSrcClass *klass)
136 {
137 	GObjectClass *gobject_class;
138 	GstElementClass *element_class;
139 
140 	gobject_class = G_OBJECT_CLASS (klass);
141 	gobject_class->dispose = rb_daap_src_dispose;
142 	gobject_class->set_property = rb_daap_src_set_property;
143 	gobject_class->get_property = rb_daap_src_get_property;
144 
145 	element_class = GST_ELEMENT_CLASS (klass);
146 	element_class->change_state = rb_daap_src_change_state;
147 
148 	g_object_class_install_property (gobject_class, PROP_LOCATION,
149 			g_param_spec_string ("location",
150 					     "file location",
151 					     "location of the file to read",
152 					     NULL,
153 					     G_PARAM_READWRITE));
154 }
155 
156 static void
157 rb_daap_src_init (RBDAAPSrc *src, RBDAAPSrcClass *klass)
158 {
159 	GstPad *pad;
160 
161 	/* create actual source */
162 	src->souphttpsrc = gst_element_factory_make ("souphttpsrc", NULL);
163 	if (src->souphttpsrc == NULL) {
164 		g_warning ("couldn't create souphttpsrc element");
165 		return;
166 	}
167 
168 	gst_bin_add (GST_BIN (src), src->souphttpsrc);
169 	gst_object_ref (src->souphttpsrc);
170 
171 	/* create ghost pad */
172 	pad = gst_element_get_pad (src->souphttpsrc, "src");
173 	src->ghostpad = gst_ghost_pad_new ("src", pad);
174 	gst_element_add_pad (GST_ELEMENT (src), src->ghostpad);
175 	gst_object_ref (src->ghostpad);
176 	gst_object_unref (pad);
177 
178 	src->daap_uri = NULL;
179 }
180 
181 static void
182 rb_daap_src_dispose (GObject *object)
183 {
184 	RBDAAPSrc *src;
185 	src = RB_DAAP_SRC (object);
186 
187 	if (src->ghostpad) {
188 		gst_object_unref (src->ghostpad);
189 		src->ghostpad = NULL;
190 	}
191 
192 	if (src->souphttpsrc) {
193 		gst_object_unref (src->souphttpsrc);
194 		src->souphttpsrc = NULL;
195 	}
196 
197 	g_free (src->daap_uri);
198 	src->daap_uri = NULL;
199 
200 	G_OBJECT_CLASS (parent_class)->dispose (object);
201 }
202 
203 static void
204 rb_daap_src_set_property (GObject *object,
205 			  guint prop_id,
206 			  const GValue *value,
207 			  GParamSpec *pspec)
208 {
209 	RBDAAPSrc *src = RB_DAAP_SRC (object);
210 
211 	switch (prop_id) {
212 		case PROP_LOCATION:
213 			/* XXX check stuff */
214 			if (src->daap_uri) {
215 				g_free (src->daap_uri);
216 				src->daap_uri = NULL;
217 			}
218 			src->daap_uri = g_strdup (g_value_get_string (value));
219 			break;
220 		default:
221 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
222 			break;
223 	}
224 }
225 
226 static void
227 rb_daap_src_get_property (GObject *object,
228 		          guint prop_id,
229 			  GValue *value,
230 			  GParamSpec *pspec)
231 {
232 	RBDAAPSrc *src = RB_DAAP_SRC (object);
233 
234 	switch (prop_id) {
235 		case PROP_LOCATION:
236 			g_value_set_string (value, src->daap_uri);
237 			break;
238 		default:
239 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
240 			break;
241 	}
242 }
243 
244 static void
245 rb_daap_src_set_header (const char *name, const char *value, gpointer headers)
246 {
247 	gst_structure_set (headers, name, G_TYPE_STRING, value, NULL);
248 }
249 
250 static GstStructure *
251 rb_daap_src_soup_message_headers_to_gst_structure (SoupMessageHeaders *headers)
252 {
253 	GstStructure *gst_headers = gst_structure_new ("extra-headers", NULL);
254 
255 	if (gst_headers == NULL)
256 		return gst_headers;
257 
258 	soup_message_headers_foreach (headers,
259 				      rb_daap_src_set_header,
260 				      gst_headers);
261 
262 	return gst_headers;
263 }
264 
265 GstStateChangeReturn
266 rb_daap_src_change_state (GstElement *element, GstStateChange transition)
267 {
268 	RBDAAPSrc *src = RB_DAAP_SRC (element);
269 
270 	switch (transition) {
271 		case GST_STATE_CHANGE_NULL_TO_READY:
272 		{
273 			const char *http = "http";
274 			char *httpuri;
275 			SoupMessageHeaders *headers;
276 			GstStructure *gst_headers;
277 			RBDAAPSource *source;
278 
279 			/* Retrieve extra headers for the HTTP connection. */
280 			source = rb_daap_plugin_find_source_for_uri (daap_plugin, src->daap_uri);
281 			if (source == NULL) {
282 				g_warning ("Unable to lookup source for URI: %s", src->daap_uri);
283 				return GST_STATE_CHANGE_FAILURE;
284 			}
285 
286 			/* The following can fail if the source is no longer connected */
287 			headers = rb_daap_source_get_headers (source, src->daap_uri);
288 			if (headers == NULL) {
289 				return GST_STATE_CHANGE_FAILURE;
290 			}
291 
292 			gst_headers = rb_daap_src_soup_message_headers_to_gst_structure
293 					(headers);
294 			if (gst_headers == NULL) {
295 				return GST_STATE_CHANGE_FAILURE;
296 			}
297 			soup_message_headers_free (headers);
298 
299 			g_object_set (src->souphttpsrc, "extra-headers", gst_headers, NULL);
300 			gst_structure_free (gst_headers);
301 
302 			/* Set daap://... URI as http:// on souphttpsrc to ready connection. */
303 			httpuri = g_strdup (src->daap_uri);
304 			strncpy (httpuri, http, 4);
305 
306 			g_object_set (src->souphttpsrc, "location", httpuri, NULL);
307 			g_free (httpuri);
308 			break;
309 		}
310 
311 		case GST_STATE_CHANGE_READY_TO_PAUSED:
312 			break;
313 
314 		case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
315 			break;
316 
317 		default:
318 			break;
319 	}
320 
321 	return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
322 }
323 
324 static gboolean
325 plugin_init (GstPlugin *plugin)
326 {
327 	gboolean ret = gst_element_register (plugin, "rbdaapsrc", GST_RANK_PRIMARY, RB_TYPE_DAAP_SRC);
328 	return ret;
329 }
330 
331 GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
332 			  GST_VERSION_MINOR,
333 			  "rbdaap",
334 			  "element to access DAAP music share files",
335 			  plugin_init,
336 			  VERSION,
337 			  "GPL",
338 			  PACKAGE,
339 			  "");
340 
341 /*** GSTURIHANDLER INTERFACE *************************************************/
342 
343 static guint
344 rb_daap_src_uri_get_type (void)
345 {
346 	return GST_URI_SRC;
347 }
348 
349 static gchar **
350 rb_daap_src_uri_get_protocols (void)
351 {
352 	static gchar *protocols[] = {"daap", NULL};
353 
354 	return protocols;
355 }
356 
357 static const gchar *
358 rb_daap_src_uri_get_uri (GstURIHandler *handler)
359 {
360 	RBDAAPSrc *src = RB_DAAP_SRC (handler);
361 
362 	return src->daap_uri;
363 }
364 
365 static gboolean
366 rb_daap_src_uri_set_uri (GstURIHandler *handler,
367 			 const gchar *uri)
368 {
369 	RBDAAPSrc *src = RB_DAAP_SRC (handler);
370 
371 	if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
372 		return FALSE;
373 	}
374 
375 	g_object_set (G_OBJECT (src), "location", uri, NULL);
376 
377 	return TRUE;
378 }
379 
380 static void
381 rb_daap_src_uri_handler_init (gpointer g_iface,
382 			      gpointer iface_data)
383 {
384 	GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
385 
386 	iface->get_type = rb_daap_src_uri_get_type;
387 	iface->get_protocols = rb_daap_src_uri_get_protocols;
388 	iface->get_uri = rb_daap_src_uri_get_uri;
389 	iface->set_uri = rb_daap_src_uri_set_uri;
390 }