From a96a74b06e0455fc3b2a819ccfdc78e370064336 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 27 Oct 2002 18:43:29 +0000 Subject: [PATCH] Added the new shout plugin Original commit message from CVS: Added the new shout plugin --- ext/shout2/Makefile.am | 10 + ext/shout2/gstshout2.c | 488 +++++++++++++++++++++++++++++++++++++++++++++++++ ext/shout2/gstshout2.h | 79 ++++++++ 3 files changed, 577 insertions(+) create mode 100644 ext/shout2/Makefile.am create mode 100644 ext/shout2/gstshout2.c create mode 100644 ext/shout2/gstshout2.h diff --git a/ext/shout2/Makefile.am b/ext/shout2/Makefile.am new file mode 100644 index 0000000..258b716 --- /dev/null +++ b/ext/shout2/Makefile.am @@ -0,0 +1,10 @@ +plugindir = $(libdir)/gst + +plugin_LTLIBRARIES = libgstshout2.la + +libgstshout2_la_SOURCES = gstshout2.c +libgstshout2_la_CFLAGS = $(GST_CFLAGS) +libgstshout2_la_LIBADD = $(SHOUT2_LIBS) $(GST_LIBS) +libgstshout2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = gstshout2.h diff --git a/ext/shout2/gstshout2.c b/ext/shout2/gstshout2.c new file mode 100644 index 0000000..1a687e3 --- /dev/null +++ b/ext/shout2/gstshout2.c @@ -0,0 +1,488 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstshout2.h" +#include + +/* elementfactory information */ +static GstElementDetails shout2send_details = { + "An Icecast plugin", + "Shout2send", + "LGPL", + "Sends data to an icecast server", + VERSION, + "Wim Taymans , Pedro Corte-Real ", + "(C) 2000", +}; + +unsigned int audio_format = 100; + +/* Shout2send signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_IP, /* the ip of the server */ + ARG_PORT, /* the encoder port number on the server */ + ARG_PASSWORD, /* the encoder password on the server */ + ARG_PUBLIC, /* is this stream public? */ + ARG_NAME, /* Name of the stream */ + ARG_DESCRIPTION, /* Description of the stream */ + ARG_GENRE, /* Genre of the stream */ + + ARG_MOUNT, /* mountpoint of stream (icecast only) */ + ARG_URL, /* Url of stream (I'm guessing) */ +}; + +static GstPadTemplate* +sink_template_factory (void) +{ + static GstPadTemplate *template = NULL; + + if (!template) { + template = gst_pad_template_new ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + gst_caps_new ( + "shout2send_sink", + "application/x-ogg", + NULL), + gst_caps_new ( + "shout2send_sink", + "audio/mp3", + NULL), + NULL); + } + + return template; +} + +static void gst_shout2send_class_init (GstShout2sendClass *klass); +static void gst_shout2send_init (GstShout2send *shout2send); + +static void gst_shout2send_chain (GstPad *pad, GstBuffer *buf); +static GstPadConnectReturn gst_shout2send_connect (GstPad *pad, GstCaps *caps); + +static void gst_shout2send_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_shout2send_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static GstElementStateReturn gst_shout2send_change_state (GstElement *element); + +static GstElementClass *parent_class = NULL; +/*static guint gst_shout2send_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_shout2send_get_type(void) +{ + static GType shout2send_type = 0; + + if (!shout2send_type) { + static const GTypeInfo shout2send_info = { + sizeof(GstShout2sendClass), NULL, + NULL, + (GClassInitFunc)gst_shout2send_class_init, + NULL, + NULL, + sizeof(GstShout2send), + 0, + (GInstanceInitFunc)gst_shout2send_init, + }; + shout2send_type = g_type_register_static(GST_TYPE_ELEMENT, "GstShout2send", &shout2send_info, 0); + } + return shout2send_type; +} + +static void +gst_shout2send_class_init (GstShout2sendClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_IP, + g_param_spec_string("ip","ip","ip", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + 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 */ + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PASSWORD, + g_param_spec_string("password","password","password", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + + /* metadata */ + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NAME, + g_param_spec_string("name","name","name", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DESCRIPTION, + g_param_spec_string("description","description","description", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_GENRE, + g_param_spec_string("genre","genre","genre", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + + /* icecast only */ + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MOUNT, + g_param_spec_string("mount","mount","mount", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_URL, + g_param_spec_string("url","url","url", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + + + + gobject_class->set_property = gst_shout2send_set_property; + gobject_class->get_property = gst_shout2send_get_property; + + gstelement_class->change_state = gst_shout2send_change_state; +} + +static void +gst_shout2send_init (GstShout2send *shout2send) +{ + shout2send->sinkpad = gst_pad_new_from_template (sink_template_factory (), "sink"); + gst_element_add_pad(GST_ELEMENT(shout2send),shout2send->sinkpad); + gst_pad_set_chain_function(shout2send->sinkpad,gst_shout2send_chain); + + gst_pad_set_connect_function (shout2send->sinkpad, gst_shout2send_connect); + + shout2send->ip = g_strdup ("127.0.0.1"); + shout2send->port = 8000; + shout2send->password = g_strdup ("hackme"); + shout2send->name = g_strdup (""); + shout2send->description = g_strdup (""); + shout2send->genre = g_strdup (""); + shout2send->mount = g_strdup (""); + shout2send->url = g_strdup (""); +} + +static void +gst_shout2send_chain (GstPad *pad, GstBuffer *buf) +{ + GstShout2send *shout2send; + glong ret; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + shout2send = GST_SHOUT2SEND (GST_OBJECT_PARENT (pad)); + + g_return_if_fail (shout2send != NULL); + g_return_if_fail (GST_IS_SHOUT2SEND (shout2send)); + + ret = shout_send (shout2send->conn, GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); + if (ret != SHOUTERR_SUCCESS) { + g_warning ("send error: %s...\n", shout_get_error(shout2send->conn)); + } + + shout_sync (shout2send->conn); + + gst_buffer_unref (buf); +} + +static void +gst_shout2send_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstShout2send *shout2send; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_SHOUT2SEND(object)); + shout2send = GST_SHOUT2SEND(object); + + switch (prop_id) { + + case ARG_IP: + if (shout2send->ip) + g_free (shout2send->ip); + shout2send->ip = g_strdup (g_value_get_string (value)); + break; + + case ARG_PORT: + shout2send->port = g_value_get_int (value); + break; + + case ARG_PASSWORD: + if (shout2send->password) + g_free (shout2send->password); + shout2send->password = g_strdup (g_value_get_string (value)); + break; + + case ARG_NAME: /* Name of the stream */ + if (shout2send->name) + g_free (shout2send->name); + shout2send->name = g_strdup (g_value_get_string (value)); + break; + + case ARG_DESCRIPTION: /* Description of the stream */ + if (shout2send->description) + g_free (shout2send->description); + shout2send->description = g_strdup (g_value_get_string (value)); + break; + + case ARG_GENRE: /* Genre of the stream */ + if (shout2send->genre) + g_free (shout2send->genre); + shout2send->genre = g_strdup (g_value_get_string (value)); + break; + + case ARG_MOUNT: /* mountpoint of stream (icecast only) */ + if (shout2send->mount) + g_free (shout2send->mount); + shout2send->mount = g_strdup (g_value_get_string (value)); + break; + + case ARG_URL: /* Url of the stream (I'm guessing) */ + if (shout2send->url) + g_free (shout2send->url); + shout2send->url = g_strdup (g_value_get_string (value)); + break; + + default: + break; + } +} + +static void +gst_shout2send_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstShout2send *shout2send; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_SHOUT2SEND(object)); + shout2send = GST_SHOUT2SEND(object); + + switch (prop_id) { + + case ARG_IP: + g_value_set_string (value, shout2send->ip); + break; + case ARG_PORT: + g_value_set_int (value, shout2send->port); + break; + case ARG_PASSWORD: + g_value_set_string (value, shout2send->password); + break; + + case ARG_NAME: /* Name of the stream */ + g_value_set_string (value, shout2send->name); + break; + + case ARG_DESCRIPTION: /* Description of the stream */ + g_value_set_string (value, shout2send->description); + break; + + case ARG_GENRE: /* Genre of the stream */ + g_value_set_string (value, shout2send->genre); + break; + + case ARG_MOUNT: /* mountpoint of stream (icecast only) */ + g_value_set_string (value, shout2send->mount); + break; + + case ARG_URL: /* Url of stream (I'm guessing) */ + g_value_set_string (value, shout2send->url); + break; + + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstPadConnectReturn +gst_shout2send_connect (GstPad *pad, GstCaps *caps) + +{ + + if (!strcmp(gst_caps_get_mime (caps), "audio/mp3")) + { + audio_format = SHOUT_FORMAT_MP3; + return GST_PAD_CONNECT_OK; + } + + if (!strcmp(gst_caps_get_mime (caps), "application/x-ogg")) + { + audio_format = SHOUT_FORMAT_VORBIS; + return GST_PAD_CONNECT_OK; + } + else { + return GST_PAD_CONNECT_REFUSED; + } + +} + +static GstElementStateReturn +gst_shout2send_change_state (GstElement *element) +{ + GstShout2send *shout2send; + + guint major, minor, micro; + + gchar *version_string; + + g_return_val_if_fail (GST_IS_SHOUT2SEND (element), GST_STATE_FAILURE); + + shout2send = GST_SHOUT2SEND(element); + + GST_DEBUG (0,"state pending %d", GST_STATE_PENDING (element)); + + /* if going down into NULL state, close the file if it's open */ + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + shout2send->conn = shout_new(); + + /* There are other choices for protocols (_ICE, _XAUDIOCAST and _ICY) + adding a property to set this might be in order */ + + if (shout_set_protocol(shout2send->conn, SHOUT_PROTOCOL_HTTP) != SHOUTERR_SUCCESS) + { + g_error ("Error setting protocol: %s\n", shout_get_error(shout2send->conn)); + } + + /* --- FIXME: shout requires an ip, and fails if it is given a host. */ + /* may want to put convert_to_ip(shout2send->ip) here */ + + + if (shout_set_host(shout2send->conn, shout2send->ip) != SHOUTERR_SUCCESS) + { + g_error ("Error setting host: %s\n", shout_get_error(shout2send->conn)); + } + /* --- */ + + if (shout_set_port(shout2send->conn, shout2send->port) != SHOUTERR_SUCCESS) + { + g_error ("Error setting port: %s\n", shout_get_error(shout2send->conn)); + } + + if(shout_set_password(shout2send->conn, shout2send->password) != SHOUTERR_SUCCESS) + { + g_error ("Error setting password: %s\n", shout_get_error(shout2send->conn)); + } + + if (shout_set_name(shout2send->conn, shout2send->name) != SHOUTERR_SUCCESS) + { + g_error ("Error setting name: %s\n", shout_get_error(shout2send->conn)); + } + + if (shout_set_description(shout2send->conn, shout2send->description) != SHOUTERR_SUCCESS) + { + g_error ("Error setting name: %s\n", shout_get_error(shout2send->conn)); + } + + if (shout_set_genre(shout2send->conn, shout2send->genre) != SHOUTERR_SUCCESS) + { + g_error ("Error setting name: %s\n", shout_get_error(shout2send->conn)); + } + + if (shout_set_mount(shout2send->conn, shout2send->mount) != SHOUTERR_SUCCESS) + { + g_error ("Error setting mount point: %s\n", shout_get_error(shout2send->conn)); + } + + if (shout_set_user(shout2send->conn, "source") != SHOUTERR_SUCCESS) + { + g_error ("Error setting user: %s\n", shout_get_error(shout2send->conn)); + } + + gst_version(&major,&minor,µ); + + version_string = g_strdup_printf("GStreamer %d.%d.%d", major,minor,micro); + + if (shout_set_agent(shout2send->conn, version_string) != SHOUTERR_SUCCESS) + { + g_error ("Error setting agent: %s\n", shout_get_error(shout2send->conn)); + } + + g_free (version_string); + + + + break; + case GST_STATE_READY_TO_PAUSED: + + /* This sets the format acording to the capabilities of what + we are being given as input. */ + + if (shout_set_format(shout2send->conn, audio_format) != SHOUTERR_SUCCESS) + { + g_error ("Error setting connection format: %s\n", shout_get_error(shout2send->conn)); + } + + if (shout_open (shout2send->conn) == SHOUTERR_SUCCESS) { + g_print ("connected to server...\n"); + } + else { + /* changed from g_warning, and included result code lookup. */ + g_error ("couldn't connect to server..."); + shout_close (shout2send->conn); + shout_free (shout2send->conn); + return GST_STATE_FAILURE; + } + break; + case GST_STATE_READY_TO_NULL: + shout_close (shout2send->conn); + shout_free (shout2send->conn); + break; + default: + break; + } + + /* if we haven't failed already, give the parent class a chance to ;-) */ + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_element_factory_new("shout2send", GST_TYPE_SHOUT2SEND, &shout2send_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_element_factory_add_pad_template (factory, sink_template_factory ()); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "shout2send", + plugin_init +}; + diff --git a/ext/shout2/gstshout2.h b/ext/shout2/gstshout2.h new file mode 100644 index 0000000..a5f28b7 --- /dev/null +++ b/ext/shout2/gstshout2.h @@ -0,0 +1,79 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_SHOUT2SEND_H__ +#define __GST_SHOUT2SEND_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Definition of structure storing data for this element. */ +typedef struct _GstShout2send GstShout2send; +struct _GstShout2send { + GstElement element; + + GstPad *sinkpad,*srcpad; + + shout_t *conn; + + gchar *ip; + guint port; + gchar *password; + gchar *name; + gchar *description; + gchar *genre; + gchar *mount; + gchar *url; + +}; + +/* Standard definition defining a class for this element. */ +typedef struct _GstShout2sendClass GstShout2sendClass; +struct _GstShout2sendClass { + GstElementClass parent_class; +}; + +/* Standard macros for defining types for this element. */ +#define GST_TYPE_SHOUT2SEND \ + (gst_shout2send_get_type()) +#define GST_SHOUT2SEND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHOUT2SEND,GstShout2send)) +#define GST_SHOUT2SEND_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHOUT2SEND,GstShout2send)) +#define GST_IS_SHOUT2SEND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHOUT2SEND)) +#define GST_IS_SHOUT2SEND_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHOUT2SEND)) + +/* Standard function returning type information. */ +GType gst_shout2send_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_SHOUT2SEND_H__ */ -- 2.7.4