2006-10-07 James Livingston <doclivingston@gmail.com>
[rhythmbox.git] / plugins / audioscrobbler / rb-lastfm-gst-src.c
blob1edc651e8aaf8f6dbf573d49468adae730ced7b1
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * Copyright (C) 2006 Jonathan Matthew <jonathan@kaolin.wh9.net>
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 2 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, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "config.h"
23 #define _GNU_SOURCE
24 #include <string.h>
26 #include "rb-debug.h"
28 #include <libsoup/soup.h>
29 #include <gst/gst.h>
31 #define RB_TYPE_LASTFM_SRC (rb_lastfm_src_get_type())
32 #define RB_LASTFM_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RB_TYPE_LASTFM_SRC,RBLastFMSrc))
33 #define RB_LASTFM_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RB_TYPE_LASTFM_SRC,RBLastFMSrcClass))
34 #define RB_IS_LASTFM_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RB_TYPE_LASTFM_SRC))
35 #define RB_IS_LASTFM_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),RB_TYPE_LASTFM_SRC))
37 typedef struct _RBLastFMSrc RBLastFMSrc;
38 typedef struct _RBLastFMSrcClass RBLastFMSrcClass;
40 struct _RBLastFMSrc
42 GstBin parent;
44 char *lastfm_uri;
45 GstElement *http_src;
46 GstPad *ghostpad;
49 struct _RBLastFMSrcClass
51 GstBinClass parent_class;
54 enum
56 PROP_0,
57 PROP_URI,
60 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
61 GST_PAD_SRC,
62 GST_PAD_ALWAYS,
63 GST_STATIC_CAPS_ANY);
65 static GstElementDetails rb_lastfm_src_details =
66 GST_ELEMENT_DETAILS ("RB Last.FM Source",
67 "Source/File",
68 "Reads a last.fm radio stream",
69 "Jonathan Matthew <jonathan@kaolin.wh9.net>");
71 static void rb_lastfm_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
73 static void
74 _do_init (GType lastfm_src_type)
76 static const GInterfaceInfo urihandler_info = {
77 rb_lastfm_src_uri_handler_init,
78 NULL,
79 NULL
82 g_type_add_interface_static (lastfm_src_type, GST_TYPE_URI_HANDLER,
83 &urihandler_info);
86 GST_BOILERPLATE_FULL (RBLastFMSrc, rb_lastfm_src, GstBin, GST_TYPE_BIN, _do_init);
88 static void
89 rb_lastfm_src_base_init (gpointer g_class)
91 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
92 gst_element_class_add_pad_template (element_class,
93 gst_static_pad_template_get (&srctemplate));
94 gst_element_class_set_details (element_class, &rb_lastfm_src_details);
97 static void
98 rb_lastfm_src_init (RBLastFMSrc *src, RBLastFMSrcClass *klass)
100 rb_debug ("creating rb last.fm src element");
103 static gboolean
104 rb_lastfm_src_pad_probe_cb (GstPad *pad, GstBuffer *buffer, RBLastFMSrc *src)
106 guint8 *data = GST_BUFFER_DATA (buffer);
107 char *s;
108 static char sync[5] = "SYNC";
110 s = memmem (data, GST_BUFFER_SIZE (buffer), sync, 4);
111 if (s != NULL) {
112 GstMessage *msg;
113 GstStructure *s;
115 rb_debug ("got song change tag");
116 s = gst_structure_new ("rb-lastfm-new-song", NULL);
117 msg = gst_message_new_application (GST_OBJECT (src), s);
118 gst_element_post_message (GST_ELEMENT (src), msg);
121 return TRUE;
124 static void
125 rb_lastfm_src_set_uri (RBLastFMSrc *src, const char *uri)
127 GstPad *pad;
129 rb_debug ("stream uri: %s", uri);
130 g_free (src->lastfm_uri);
131 src->lastfm_uri = g_strdup (uri);
133 if (src->http_src) {
134 gst_element_remove_pad (GST_ELEMENT (src), src->ghostpad);
135 gst_object_unref (src->ghostpad);
136 src->ghostpad = NULL;
138 gst_bin_remove (GST_BIN (src), src->http_src);
139 gst_object_unref (src->http_src);
140 src->http_src = NULL;
143 /* create actual HTTP source */
144 src->http_src = gst_element_make_from_uri (GST_URI_SRC, src->lastfm_uri, NULL);
145 gst_bin_add (GST_BIN (src), src->http_src);
146 gst_object_ref (src->http_src);
148 /* create ghost pad */
149 pad = gst_element_get_pad (src->http_src, "src");
150 src->ghostpad = gst_ghost_pad_new ("src", pad);
151 gst_element_add_pad (GST_ELEMENT (src), src->ghostpad);
152 gst_object_ref (src->ghostpad);
153 gst_object_unref (pad);
155 /* attach probe */
156 gst_pad_add_buffer_probe (pad, G_CALLBACK (rb_lastfm_src_pad_probe_cb), src);
159 static void
160 rb_lastfm_src_set_property (GObject *object,
161 guint prop_id,
162 const GValue *value,
163 GParamSpec *pspec)
165 RBLastFMSrc *src = RB_LASTFM_SRC (object);
167 switch (prop_id) {
168 case PROP_URI:
169 rb_lastfm_src_set_uri (src, g_value_get_string (value));
170 break;
171 default:
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
173 break;
177 static void
178 rb_lastfm_src_get_property (GObject *object,
179 guint prop_id,
180 GValue *value,
181 GParamSpec *pspec)
183 RBLastFMSrc *src = RB_LASTFM_SRC (object);
185 switch (prop_id) {
186 case PROP_URI:
187 g_value_set_string (value, src->lastfm_uri);
188 break;
189 default:
190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
191 break;
195 static void
196 rb_lastfm_src_finalize (GObject *object)
198 RBLastFMSrc *src;
199 src = RB_LASTFM_SRC (object);
201 g_free (src->lastfm_uri);
203 if (src->ghostpad)
204 gst_object_unref (src->ghostpad);
206 if (src->http_src)
207 gst_object_unref (src->http_src);
209 G_OBJECT_CLASS (parent_class)->finalize (object);
212 static void
213 rb_lastfm_src_class_init (RBLastFMSrcClass *klass)
215 GObjectClass *gobject_class;
216 GstElementClass *element_class;
218 gobject_class = G_OBJECT_CLASS (klass);
219 gobject_class->finalize = rb_lastfm_src_finalize;
220 gobject_class->set_property = rb_lastfm_src_set_property;
221 gobject_class->get_property = rb_lastfm_src_get_property;
223 element_class = GST_ELEMENT_CLASS (klass);
225 g_object_class_install_property (gobject_class,
226 PROP_URI,
227 g_param_spec_string ("uri",
228 "uri",
229 "last.fm stream uri",
230 NULL,
231 G_PARAM_READWRITE));
235 /* URI handler interface */
237 static guint
238 rb_lastfm_src_uri_get_type (void)
240 return GST_URI_SRC;
243 static gchar **
244 rb_lastfm_src_uri_get_protocols (void)
246 static gchar *protocols[] = {"xrblastfm", NULL};
247 return protocols;
250 static const gchar *
251 rb_lastfm_src_uri_get_uri (GstURIHandler *handler)
253 RBLastFMSrc *src = RB_LASTFM_SRC (handler);
255 return src->lastfm_uri;
258 static gboolean
259 rb_lastfm_src_uri_set_uri (GstURIHandler *handler,
260 const gchar *uri)
262 RBLastFMSrc *src = RB_LASTFM_SRC (handler);
263 char *http_uri;
265 if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
266 return FALSE;
269 if (g_str_has_prefix (uri, "xrblastfm://") == FALSE) {
270 return FALSE;
273 http_uri = g_strdup_printf ("http://%s", uri + strlen ("xrblastfm://"));
274 g_object_set (src, "uri", http_uri, NULL);
275 g_free (http_uri);
277 return TRUE;
280 static void
281 rb_lastfm_src_uri_handler_init (gpointer g_iface,
282 gpointer iface_data)
284 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
286 iface->get_type = rb_lastfm_src_uri_get_type;
287 iface->get_protocols = rb_lastfm_src_uri_get_protocols;
288 iface->get_uri = rb_lastfm_src_uri_get_uri;
289 iface->set_uri = rb_lastfm_src_uri_set_uri;
292 static gboolean
293 plugin_init (GstPlugin *plugin)
295 gboolean ret = gst_element_register (plugin, "rblastfmsrc", GST_RANK_PRIMARY, RB_TYPE_LASTFM_SRC);
296 return ret;
299 GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
300 GST_VERSION_MINOR,
301 "rblastfm",
302 "element to access last.fm streams",
303 plugin_init,
304 VERSION,
305 "GPL",
306 PACKAGE,
307 "");