gst-indent
[platform/upstream/gst-plugins-good.git] / ext / shout2 / gstshout2.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include "gstshout2.h"
24 #include <stdlib.h>
25 #include <string.h>
26
27 /* elementfactory information */
28 static GstElementDetails shout2send_details = {
29   "An Icecast plugin",
30   "Sink/Network",
31   "Sends data to an icecast server",
32   "Wim Taymans <wim.taymans@chello.be>\n" "Pedro Corte-Real <typo@netcabo.pt>"
33 };
34
35 unsigned int audio_format = 100;
36
37 /* Shout2send signals and args */
38 enum
39 {
40   /* FILL ME */
41   LAST_SIGNAL
42 };
43
44 enum
45 {
46   ARG_0,
47   ARG_IP,                       /* the ip of the server */
48   ARG_PORT,                     /* the encoder port number on the server */
49   ARG_PASSWORD,                 /* the encoder password on the server */
50   ARG_PUBLIC,                   /* is this stream public? */
51   ARG_NAME,                     /* Name of the stream */
52   ARG_DESCRIPTION,              /* Description of the stream */
53   ARG_GENRE,                    /* Genre of the stream */
54
55   ARG_PROTOCOL,                 /* Protocol to connect with */
56
57   ARG_MOUNT,                    /* mountpoint of stream (icecast only) */
58   ARG_URL,                      /* Url of stream (I'm guessing) */
59 };
60
61 static GstPadTemplate *
62 sink_template_factory (void)
63 {
64   static GstPadTemplate *template = NULL;
65
66   if (!template) {
67     template = gst_pad_template_new ("sink",
68         GST_PAD_SINK,
69         GST_PAD_ALWAYS,
70         gst_caps_new ("shout2send_sink",
71             "application/ogg",
72             NULL),
73         gst_caps_new ("shout2send_sink",
74             "audio/mpeg",
75             gst_props_new ("mpegversion", GST_PROPS_INT (1),
76                 "layer", GST_PROPS_INT_RANGE (1, 3), NULL)), NULL);
77   }
78
79   return template;
80 }
81
82 static void gst_shout2send_class_init (GstShout2sendClass * klass);
83 static void gst_shout2send_base_init (GstShout2sendClass * klass);
84 static void gst_shout2send_init (GstShout2send * shout2send);
85
86 static void gst_shout2send_chain (GstPad * pad, GstData * _data);
87 static GstPadLinkReturn gst_shout2send_connect (GstPad * pad, GstCaps * caps);
88
89 static void gst_shout2send_set_property (GObject * object, guint prop_id,
90     const GValue * value, GParamSpec * pspec);
91 static void gst_shout2send_get_property (GObject * object, guint prop_id,
92     GValue * value, GParamSpec * pspec);
93
94 static GstElementStateReturn gst_shout2send_change_state (GstElement * element);
95
96 static GstElementClass *parent_class = NULL;
97
98 /*static guint gst_shout2send_signals[LAST_SIGNAL] = { 0 }; */
99
100 #define GST_TYPE_SHOUT_PROTOCOL (gst_shout2send_protocol_get_type())
101 static GType
102 gst_shout2send_protocol_get_type (void)
103 {
104   static GType shout2send_protocol_type = 0;
105   static GEnumValue shout2send_protocol[] = {
106     {SHOUT2SEND_PROTOCOL_ICE, "1", "Ice Protocol"},
107     {SHOUT2SEND_PROTOCOL_XAUDIOCAST, "2",
108         "Xaudiocast Protocol (icecast 1.3.x)"},
109     {SHOUT2SEND_PROTOCOL_ICY, "3", "Icy Protocol (ShoutCast)"},
110     {SHOUT2SEND_PROTOCOL_HTTP, "4", "Http Protocol (icecast 2.x)"},
111     {0, NULL, NULL},
112   };
113   if (!shout2send_protocol_type) {
114     shout2send_protocol_type =
115         g_enum_register_static ("GstShout2SendProtocol", shout2send_protocol);
116   }
117   return shout2send_protocol_type;
118 }
119
120 GType
121 gst_shout2send_get_type (void)
122 {
123   static GType shout2send_type = 0;
124
125   if (!shout2send_type) {
126     static const GTypeInfo shout2send_info = {
127       sizeof (GstShout2sendClass),
128       (GBaseInitFunc) gst_shout2send_base_init,
129       NULL,
130       (GClassInitFunc) gst_shout2send_class_init,
131       NULL,
132       NULL,
133       sizeof (GstShout2send),
134       0,
135       (GInstanceInitFunc) gst_shout2send_init,
136     };
137     shout2send_type =
138         g_type_register_static (GST_TYPE_ELEMENT, "GstShout2send",
139         &shout2send_info, 0);
140   }
141   return shout2send_type;
142 }
143
144 static void
145 gst_shout2send_base_init (GstShout2sendClass * klass)
146 {
147   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
148
149   gst_element_class_add_pad_template (element_class, sink_template_factory ());
150   gst_element_class_set_details (element_class, &shout2send_details);
151 }
152
153 static void
154 gst_shout2send_class_init (GstShout2sendClass * klass)
155 {
156   GObjectClass *gobject_class;
157   GstElementClass *gstelement_class;
158
159   gobject_class = (GObjectClass *) klass;
160   gstelement_class = (GstElementClass *) klass;
161
162   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
163
164   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_IP, g_param_spec_string ("ip", "ip", "ip", NULL, G_PARAM_READWRITE));    /* CHECKME */
165   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PORT, g_param_spec_int ("port", "port", "port", 1, G_MAXUSHORT, 8000, G_PARAM_READWRITE));       /* CHECKME */
166
167   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PASSWORD, g_param_spec_string ("password", "password", "password", NULL, G_PARAM_READWRITE));    /* CHECKME */
168
169   /* metadata */
170   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NAME, g_param_spec_string ("name", "name", "name", NULL, G_PARAM_READWRITE));    /* CHECKME */
171
172   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DESCRIPTION, g_param_spec_string ("description", "description", "description", NULL, G_PARAM_READWRITE));        /* CHECKME */
173
174   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GENRE, g_param_spec_string ("genre", "genre", "genre", NULL, G_PARAM_READWRITE));        /* CHECKME */
175
176   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PROTOCOL,
177       g_param_spec_enum ("protocol", "protocol", "Connection Protocol to use",
178           GST_TYPE_SHOUT_PROTOCOL, SHOUT2SEND_PROTOCOL_HTTP,
179           G_PARAM_READWRITE));
180
181
182   /* icecast only */
183   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MOUNT, g_param_spec_string ("mount", "mount", "mount", NULL, G_PARAM_READWRITE));        /* CHECKME */
184
185   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_URL, g_param_spec_string ("url", "url", "url", NULL, G_PARAM_READWRITE));        /* CHECKME */
186
187
188
189   gobject_class->set_property = gst_shout2send_set_property;
190   gobject_class->get_property = gst_shout2send_get_property;
191
192   gstelement_class->change_state = gst_shout2send_change_state;
193 }
194
195 static void
196 gst_shout2send_init (GstShout2send * shout2send)
197 {
198   shout2send->sinkpad =
199       gst_pad_new_from_template (sink_template_factory (), "sink");
200   gst_element_add_pad (GST_ELEMENT (shout2send), shout2send->sinkpad);
201   gst_pad_set_chain_function (shout2send->sinkpad, gst_shout2send_chain);
202
203   gst_pad_set_link_function (shout2send->sinkpad, gst_shout2send_connect);
204
205   shout2send->ip = g_strdup ("127.0.0.1");
206   shout2send->port = 8000;
207   shout2send->password = g_strdup ("hackme");
208   shout2send->name = g_strdup ("");
209   shout2send->description = g_strdup ("");
210   shout2send->genre = g_strdup ("");
211   shout2send->mount = g_strdup ("");
212   shout2send->url = g_strdup ("");
213   shout2send->protocol = SHOUT2SEND_PROTOCOL_HTTP;
214 }
215
216 static void
217 gst_shout2send_chain (GstPad * pad, GstData * _data)
218 {
219   GstBuffer *buf = GST_BUFFER (_data);
220   GstShout2send *shout2send;
221   glong ret;
222
223   g_return_if_fail (pad != NULL);
224   g_return_if_fail (GST_IS_PAD (pad));
225   g_return_if_fail (buf != NULL);
226
227   shout2send = GST_SHOUT2SEND (GST_OBJECT_PARENT (pad));
228
229   g_return_if_fail (shout2send != NULL);
230   g_return_if_fail (GST_IS_SHOUT2SEND (shout2send));
231
232   ret = shout_send (shout2send->conn, GST_BUFFER_DATA (buf),
233       GST_BUFFER_SIZE (buf));
234   if (ret != SHOUTERR_SUCCESS) {
235     g_warning ("send error: %s...\n", shout_get_error (shout2send->conn));
236   }
237
238   shout_sync (shout2send->conn);
239
240   gst_buffer_unref (buf);
241 }
242
243 static void
244 gst_shout2send_set_property (GObject * object, guint prop_id,
245     const GValue * value, GParamSpec * pspec)
246 {
247   GstShout2send *shout2send;
248
249   /* it's not null if we got it, but it might not be ours */
250   g_return_if_fail (GST_IS_SHOUT2SEND (object));
251   shout2send = GST_SHOUT2SEND (object);
252
253   switch (prop_id) {
254
255     case ARG_IP:
256       if (shout2send->ip)
257         g_free (shout2send->ip);
258       shout2send->ip = g_strdup (g_value_get_string (value));
259       break;
260
261     case ARG_PORT:
262       shout2send->port = g_value_get_int (value);
263       break;
264
265     case ARG_PASSWORD:
266       if (shout2send->password)
267         g_free (shout2send->password);
268       shout2send->password = g_strdup (g_value_get_string (value));
269       break;
270
271     case ARG_NAME:              /* Name of the stream */
272       if (shout2send->name)
273         g_free (shout2send->name);
274       shout2send->name = g_strdup (g_value_get_string (value));
275       break;
276
277     case ARG_DESCRIPTION:       /* Description of the stream */
278       if (shout2send->description)
279         g_free (shout2send->description);
280       shout2send->description = g_strdup (g_value_get_string (value));
281       break;
282
283     case ARG_GENRE:             /* Genre of the stream */
284       if (shout2send->genre)
285         g_free (shout2send->genre);
286       shout2send->genre = g_strdup (g_value_get_string (value));
287       break;
288
289     case ARG_PROTOCOL:          /* protocol to connect with */
290       shout2send->protocol = g_value_get_enum (value);
291       break;
292
293     case ARG_MOUNT:             /* mountpoint of stream (icecast only) */
294       if (shout2send->mount)
295         g_free (shout2send->mount);
296       shout2send->mount = g_strdup (g_value_get_string (value));
297       break;
298
299     case ARG_URL:               /* Url of the stream (I'm guessing) */
300       if (shout2send->url)
301         g_free (shout2send->url);
302       shout2send->url = g_strdup (g_value_get_string (value));
303       break;
304
305     default:
306       break;
307   }
308 }
309
310 static void
311 gst_shout2send_get_property (GObject * object, guint prop_id, GValue * value,
312     GParamSpec * pspec)
313 {
314   GstShout2send *shout2send;
315
316   /* it's not null if we got it, but it might not be ours */
317   g_return_if_fail (GST_IS_SHOUT2SEND (object));
318   shout2send = GST_SHOUT2SEND (object);
319
320   switch (prop_id) {
321
322     case ARG_IP:
323       g_value_set_string (value, shout2send->ip);
324       break;
325     case ARG_PORT:
326       g_value_set_int (value, shout2send->port);
327       break;
328     case ARG_PASSWORD:
329       g_value_set_string (value, shout2send->password);
330       break;
331
332     case ARG_NAME:              /* Name of the stream */
333       g_value_set_string (value, shout2send->name);
334       break;
335
336     case ARG_DESCRIPTION:       /* Description of the stream */
337       g_value_set_string (value, shout2send->description);
338       break;
339
340     case ARG_GENRE:             /* Genre of the stream */
341       g_value_set_string (value, shout2send->genre);
342       break;
343
344     case ARG_PROTOCOL:          /* protocol to connect with */
345       g_value_set_enum (value, shout2send->protocol);
346       break;
347
348     case ARG_MOUNT:             /* mountpoint of stream (icecast only) */
349       g_value_set_string (value, shout2send->mount);
350       break;
351
352     case ARG_URL:               /* Url of stream (I'm guessing) */
353       g_value_set_string (value, shout2send->url);
354       break;
355
356
357     default:
358       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359       break;
360   }
361 }
362
363 static GstPadLinkReturn
364 gst_shout2send_connect (GstPad * pad, GstCaps * caps)
365 {
366
367   if (!strcmp (gst_caps_get_mime (caps), "audio/mpeg")) {
368     audio_format = SHOUT_FORMAT_MP3;
369     return GST_PAD_LINK_OK;
370   }
371
372   if (!strcmp (gst_caps_get_mime (caps), "application/ogg")) {
373     audio_format = SHOUT_FORMAT_VORBIS;
374     return GST_PAD_LINK_OK;
375   } else {
376     return GST_PAD_LINK_REFUSED;
377   }
378
379 }
380
381 static GstElementStateReturn
382 gst_shout2send_change_state (GstElement * element)
383 {
384   GstShout2send *shout2send;
385
386   guint major, minor, micro;
387   gshort proto = 3;
388
389   gchar *version_string;
390
391   g_return_val_if_fail (GST_IS_SHOUT2SEND (element), GST_STATE_FAILURE);
392
393   shout2send = GST_SHOUT2SEND (element);
394
395   GST_DEBUG ("state pending %d", GST_STATE_PENDING (element));
396
397   /* if going down into NULL state, close the file if it's open */
398   switch (GST_STATE_TRANSITION (element)) {
399     case GST_STATE_NULL_TO_READY:
400       shout2send->conn = shout_new ();
401
402       switch (shout2send->protocol) {
403         case SHOUT2SEND_PROTOCOL_ICE:
404           proto = SHOUT_PROTOCOL_ICE;
405           break;
406         case SHOUT2SEND_PROTOCOL_XAUDIOCAST:
407           proto = SHOUT_PROTOCOL_XAUDIOCAST;
408           break;
409         case SHOUT2SEND_PROTOCOL_ICY:
410           proto = SHOUT_PROTOCOL_ICY;
411           break;
412         case SHOUT2SEND_PROTOCOL_HTTP:
413           proto = SHOUT_PROTOCOL_HTTP;
414           break;
415       }
416
417       if (shout_set_protocol (shout2send->conn, proto) != SHOUTERR_SUCCESS) {
418         g_error ("Error setting protocol: %s\n",
419             shout_get_error (shout2send->conn));
420       }
421
422       /* --- FIXME: shout requires an ip, and fails if it is given a host. */
423       /* may want to put convert_to_ip(shout2send->ip) here */
424
425
426       if (shout_set_host (shout2send->conn, shout2send->ip) != SHOUTERR_SUCCESS) {
427         g_error ("Error setting host: %s\n",
428             shout_get_error (shout2send->conn));
429       }
430       /* --- */
431
432       if (shout_set_port (shout2send->conn,
433               shout2send->port) != SHOUTERR_SUCCESS) {
434         g_error ("Error setting port: %s\n",
435             shout_get_error (shout2send->conn));
436       }
437
438       if (shout_set_password (shout2send->conn,
439               shout2send->password) != SHOUTERR_SUCCESS) {
440         g_error ("Error setting password: %s\n",
441             shout_get_error (shout2send->conn));
442       }
443
444       if (shout_set_name (shout2send->conn,
445               shout2send->name) != SHOUTERR_SUCCESS) {
446         g_error ("Error setting name: %s\n",
447             shout_get_error (shout2send->conn));
448       }
449
450       if (shout_set_description (shout2send->conn,
451               shout2send->description) != SHOUTERR_SUCCESS) {
452         g_error ("Error setting name: %s\n",
453             shout_get_error (shout2send->conn));
454       }
455
456       if (shout_set_genre (shout2send->conn,
457               shout2send->genre) != SHOUTERR_SUCCESS) {
458         g_error ("Error setting name: %s\n",
459             shout_get_error (shout2send->conn));
460       }
461
462       if (shout_set_mount (shout2send->conn,
463               shout2send->mount) != SHOUTERR_SUCCESS) {
464         g_error ("Error setting mount point: %s\n",
465             shout_get_error (shout2send->conn));
466       }
467
468       if (shout_set_user (shout2send->conn, "source") != SHOUTERR_SUCCESS) {
469         g_error ("Error setting user: %s\n",
470             shout_get_error (shout2send->conn));
471       }
472
473       gst_version (&major, &minor, &micro);
474
475       version_string =
476           g_strdup_printf ("GStreamer %d.%d.%d", major, minor, micro);
477
478       if (shout_set_agent (shout2send->conn,
479               version_string) != SHOUTERR_SUCCESS) {
480         g_error ("Error setting agent: %s\n",
481             shout_get_error (shout2send->conn));
482       }
483
484       g_free (version_string);
485
486
487
488       break;
489     case GST_STATE_READY_TO_PAUSED:
490
491       /* This sets the format acording to the capabilities of what
492          we are being given as input. */
493
494       if (shout_set_format (shout2send->conn, audio_format) != SHOUTERR_SUCCESS) {
495         g_error ("Error setting connection format: %s\n",
496             shout_get_error (shout2send->conn));
497       }
498
499       if (shout_open (shout2send->conn) == SHOUTERR_SUCCESS) {
500         g_print ("connected to server...\n");
501       } else {
502         g_warning ("Couldn't connect to server: %s",
503             shout_get_error (shout2send->conn));
504         shout_close (shout2send->conn);
505         shout_free (shout2send->conn);
506         return GST_STATE_FAILURE;
507       }
508       break;
509     case GST_STATE_PAUSED_TO_READY:
510       shout_close (shout2send->conn);
511       shout_free (shout2send->conn);
512       break;
513     default:
514       break;
515   }
516
517   /* if we haven't failed already, give the parent class a chance to ;-) */
518   if (GST_ELEMENT_CLASS (parent_class)->change_state)
519     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
520
521   return GST_STATE_SUCCESS;
522 }
523
524 static gboolean
525 plugin_init (GstPlugin * plugin)
526 {
527   return gst_element_register (plugin, "shout2send", GST_RANK_NONE,
528       GST_TYPE_SHOUT2SEND);
529 }
530
531 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
532     GST_VERSION_MINOR,
533     "shout2send",
534     "Sends data to an icecast server using libshout2",
535     plugin_init,
536     VERSION, "LGPL", "libshout2", "http://www.icecast.org/download.html")