2 * Copyright (C) <2001> Richard Boulton <richard-gst@tartarus.org>
5 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
26 #include "gstartsdsink.h"
28 /* elementfactory information */
29 static GstElementDetails artsdsink_details = {
33 "Plays audio to an aRts server",
35 "Richard Boulton <richard-gst@tartarus.org>",
39 /* Signals and args */
54 GST_PAD_TEMPLATE_FACTORY (sink_factory,
55 "sink", /* the name of the pads */
56 GST_PAD_SINK, /* type of the pad */
57 GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */
59 "artsdsink_sink", /* the name of the caps */
60 "audio/raw", /* the mime type of the caps */
61 "format", GST_PROPS_STRING ("int"),
62 "law", GST_PROPS_INT (0),
63 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
64 "signed", GST_PROPS_BOOLEAN (FALSE),
65 "width", GST_PROPS_INT (8),
66 "depth", GST_PROPS_INT (8),
67 "rate", GST_PROPS_INT_RANGE (8000, 96000),
68 "channels", GST_PROPS_LIST (GST_PROPS_INT (1), GST_PROPS_INT (2))
71 "artsdsink_sink", /* the name of the caps */
72 "audio/raw", /* the mime type of the caps */
73 "format", GST_PROPS_STRING ("int"),
74 "law", GST_PROPS_INT (0),
75 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
76 "signed", GST_PROPS_BOOLEAN (TRUE),
77 "width", GST_PROPS_INT (16),
78 "depth", GST_PROPS_INT (16),
79 "rate", GST_PROPS_INT_RANGE (8000, 96000),
80 "channels", GST_PROPS_LIST (GST_PROPS_INT (1), GST_PROPS_INT (2))
84 static void gst_artsdsink_class_init (GstArtsdsinkClass *klass);
85 static void gst_artsdsink_init (GstArtsdsink *artsdsink);
87 static gboolean gst_artsdsink_open_audio (GstArtsdsink *sink);
88 static void gst_artsdsink_close_audio (GstArtsdsink *sink);
89 static GstElementStateReturn gst_artsdsink_change_state (GstElement *element);
90 static gboolean gst_artsdsink_sync_parms (GstArtsdsink *artsdsink);
92 static void gst_artsdsink_chain (GstPad *pad, GstBuffer *buf);
94 static void gst_artsdsink_set_property (GObject *object, guint prop_id,
95 const GValue *value, GParamSpec *pspec);
96 static void gst_artsdsink_get_property (GObject *object, guint prop_id,
97 GValue *value, GParamSpec *pspec);
99 #define GST_TYPE_ARTSDSINK_DEPTHS (gst_artsdsink_depths_get_type())
101 gst_artsdsink_depths_get_type (void)
103 static GType artsdsink_depths_type = 0;
104 static GEnumValue artsdsink_depths[] = {
106 {16, "16", "16 Bits"},
109 if (!artsdsink_depths_type) {
110 artsdsink_depths_type = g_enum_register_static("GstArtsdsinkDepths", artsdsink_depths);
112 return artsdsink_depths_type;
115 #define GST_TYPE_ARTSDSINK_CHANNELS (gst_artsdsink_channels_get_type())
117 gst_artsdsink_channels_get_type (void)
119 static GType artsdsink_channels_type = 0;
120 static GEnumValue artsdsink_channels[] = {
125 if (!artsdsink_channels_type) {
126 artsdsink_channels_type = g_enum_register_static("GstArtsdsinkChannels", artsdsink_channels);
128 return artsdsink_channels_type;
132 static GstElementClass *parent_class = NULL;
133 /*static guint gst_artsdsink_signals[LAST_SIGNAL] = { 0 }; */
136 gst_artsdsink_get_type (void)
138 static GType artsdsink_type = 0;
140 if (!artsdsink_type) {
141 static const GTypeInfo artsdsink_info = {
142 sizeof(GstArtsdsinkClass), NULL,
144 (GClassInitFunc)gst_artsdsink_class_init,
147 sizeof(GstArtsdsink),
149 (GInstanceInitFunc)gst_artsdsink_init,
151 artsdsink_type = g_type_register_static(GST_TYPE_ELEMENT, "GstArtsdsink", &artsdsink_info, 0);
153 return artsdsink_type;
157 gst_artsdsink_class_init (GstArtsdsinkClass *klass)
159 GObjectClass *gobject_class;
160 GstElementClass *gstelement_class;
162 gobject_class = (GObjectClass*)klass;
163 gstelement_class = (GstElementClass*)klass;
165 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
167 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
168 g_param_spec_boolean("mute","mute","mute",
169 TRUE,G_PARAM_READWRITE)); /* CHECKME */
170 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEPTH,
171 g_param_spec_enum("depth","depth","depth",
172 GST_TYPE_ARTSDSINK_DEPTHS,16,G_PARAM_READWRITE)); /* CHECKME! */
173 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNELS,
174 g_param_spec_enum("channels","channels","channels",
175 GST_TYPE_ARTSDSINK_CHANNELS,2,G_PARAM_READWRITE)); /* CHECKME! */
176 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_RATE,
177 g_param_spec_int("frequency","frequency","frequency",
178 G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
179 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NAME,
180 g_param_spec_string("name","name","name",
181 NULL, G_PARAM_READWRITE)); /* CHECKME */
183 gobject_class->set_property = gst_artsdsink_set_property;
184 gobject_class->get_property = gst_artsdsink_get_property;
186 gstelement_class->change_state = gst_artsdsink_change_state;
190 gst_artsdsink_init(GstArtsdsink *artsdsink)
192 artsdsink->sinkpad = gst_pad_new_from_template (
193 GST_PAD_TEMPLATE_GET (sink_factory), "sink");
194 gst_element_add_pad(GST_ELEMENT(artsdsink), artsdsink->sinkpad);
195 gst_pad_set_chain_function(artsdsink->sinkpad, gst_artsdsink_chain);
197 artsdsink->connected = FALSE;
198 artsdsink->mute = FALSE;
200 /* FIXME: get default from somewhere better than just putting them inline. */
201 artsdsink->signd = TRUE;
202 artsdsink->depth = 16;
203 artsdsink->channels = 2;
204 artsdsink->frequency = 44100;
205 artsdsink->connect_name = NULL;
209 gst_artsdsink_sync_parms (GstArtsdsink *artsdsink)
211 g_return_val_if_fail (artsdsink != NULL, FALSE);
212 g_return_val_if_fail (GST_IS_ARTSDSINK (artsdsink), FALSE);
214 if (!artsdsink->connected) return TRUE;
216 /* Need to set stream to use new parameters: only way to do this is to reopen. */
217 gst_artsdsink_close_audio (artsdsink);
218 return gst_artsdsink_open_audio (artsdsink);
223 gst_artsdsink_chain (GstPad *pad, GstBuffer *buf)
225 GstArtsdsink *artsdsink;
227 g_return_if_fail(pad != NULL);
228 g_return_if_fail(GST_IS_PAD(pad));
229 g_return_if_fail(buf != NULL);
231 artsdsink = GST_ARTSDSINK (gst_pad_get_parent (pad));
233 if (GST_BUFFER_DATA (buf) != NULL) {
234 gst_trace_add_entry(NULL, 0, GPOINTER_TO_INT(buf), "artsdsink: writing to server");
235 if (!artsdsink->mute && artsdsink->connected) {
237 void * bufptr = GST_BUFFER_DATA (buf);
238 int bufsize = GST_BUFFER_SIZE (buf);
239 GST_DEBUG ("artsdsink: stream=%p data=%p size=%d",
240 artsdsink->stream, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
243 bytes = arts_write (artsdsink->stream, bufptr, bufsize);
245 fprintf(stderr,"arts_write error: %s\n", arts_error_text(bytes));
246 gst_buffer_unref (buf);
251 } while (bufsize > 0);
254 gst_buffer_unref (buf);
258 gst_artsdsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
260 GstArtsdsink *artsdsink;
262 /* it's not null if we got it, but it might not be ours */
263 g_return_if_fail(GST_IS_ARTSDSINK(object));
264 artsdsink = GST_ARTSDSINK(object);
268 artsdsink->mute = g_value_get_boolean (value);
271 artsdsink->depth = g_value_get_enum (value);
272 gst_artsdsink_sync_parms (artsdsink);
275 artsdsink->channels = g_value_get_enum (value);
276 gst_artsdsink_sync_parms (artsdsink);
279 artsdsink->frequency = g_value_get_int (value);
280 gst_artsdsink_sync_parms (artsdsink);
283 if (artsdsink->connect_name != NULL) g_free(artsdsink->connect_name);
284 if (g_value_get_string (value) == NULL)
285 artsdsink->connect_name = NULL;
287 artsdsink->connect_name = g_strdup (g_value_get_string (value));
295 gst_artsdsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
297 GstArtsdsink *artsdsink;
299 /* it's not null if we got it, but it might not be ours */
300 g_return_if_fail(GST_IS_ARTSDSINK(object));
301 artsdsink = GST_ARTSDSINK(object);
305 g_value_set_boolean (value, artsdsink->mute);
308 g_value_set_enum (value, artsdsink->depth);
311 g_value_set_enum (value, artsdsink->channels);
314 g_value_set_int (value, artsdsink->frequency);
317 g_value_set_string (value, artsdsink->connect_name);
320 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326 plugin_init (GModule *module, GstPlugin *plugin)
328 GstElementFactory *factory;
330 factory = gst_element_factory_new("artsdsink", GST_TYPE_ARTSDSINK,
332 g_return_val_if_fail(factory != NULL, FALSE);
334 gst_element_factory_add_pad_template(factory, GST_PAD_TEMPLATE_GET (sink_factory));
336 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
341 GstPluginDesc plugin_desc = {
349 gst_artsdsink_open_audio (GstArtsdsink *sink)
351 const char * connname = "gstreamer";
354 /* Name used by aRtsd for this connection. */
355 if (sink->connect_name != NULL) connname = sink->connect_name;
357 /* FIXME: this should only ever happen once per process. */
358 /* Really, artsc needs to be made thread safe to fix this (and other related */
360 errcode = arts_init();
362 fprintf(stderr,"arts_init error: %s\n", arts_error_text(errcode));
366 GST_DEBUG ("artsdsink: attempting to open connection to aRtsd server");
367 sink->stream = arts_play_stream(sink->frequency, sink->depth,
368 sink->channels, connname);
369 /* FIXME: check connection */
370 /* GST_DEBUG ("artsdsink: can't open connection to aRtsd server"); */
372 GST_FLAG_SET (sink, GST_ARTSDSINK_OPEN);
373 sink->connected = TRUE;
379 gst_artsdsink_close_audio (GstArtsdsink *sink)
381 if (!sink->connected) return;
383 arts_close_stream(sink->stream);
385 GST_FLAG_UNSET (sink, GST_ARTSDSINK_OPEN);
386 sink->connected = FALSE;
388 g_print("artsdsink: closed connection\n");
391 static GstElementStateReturn
392 gst_artsdsink_change_state (GstElement *element)
394 g_return_val_if_fail (GST_IS_ARTSDSINK (element), FALSE);
396 /* if going down into NULL state, close the stream if it's open */
397 if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
398 if (GST_FLAG_IS_SET (element, GST_ARTSDSINK_OPEN))
399 gst_artsdsink_close_audio (GST_ARTSDSINK (element));
400 /* otherwise (READY or higher) we need to open the stream */
402 if (!GST_FLAG_IS_SET (element, GST_ARTSDSINK_OPEN)) {
403 if (!gst_artsdsink_open_audio (GST_ARTSDSINK (element)))
404 return GST_STATE_FAILURE;
408 if (GST_ELEMENT_CLASS (parent_class)->change_state)
409 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
410 return GST_STATE_SUCCESS;