diff options
author | Zeeshan Ali <zeenix@gmail.com> | 2003-01-30 20:24:26 +0000 |
---|---|---|
committer | Zeeshan Ali <zeenix@gmail.com> | 2003-01-30 20:24:26 +0000 |
commit | 1c6ceb5c0bc0e572a47e0889818d06ea54365355 (patch) | |
tree | b6614304f5c72b05a5654e75ae76a0c476539400 /ext/mas/massink.c | |
parent | 0d1b9d28becf937c3514ad1d79f8736d0741991e (diff) | |
download | gst-plugins-bad-1c6ceb5c0bc0e572a47e0889818d06ea54365355.tar.gz gst-plugins-bad-1c6ceb5c0bc0e572a47e0889818d06ea54365355.tar.bz2 gst-plugins-bad-1c6ceb5c0bc0e572a47e0889818d06ea54365355.zip |
The first attempt to support MAS. Dont expect it to work :)
Original commit message from CVS:
The first attempt to support MAS. Dont expect it to work :)
Diffstat (limited to 'ext/mas/massink.c')
-rw-r--r-- | ext/mas/massink.c | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/ext/mas/massink.c b/ext/mas/massink.c new file mode 100644 index 00000000..1b965beb --- /dev/null +++ b/ext/mas/massink.c @@ -0,0 +1,546 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * Most of the code from maswavplay and esdsink + * 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 "massink.h" + +#define BUFFER_SIZE 640 +#define BUFFER_TIME_NS 3628118 +#define FORCED_STABLE_LOOPS 10 +#define NANOSLEEP_GRANULARITY 100000 + + +/* elementfactory information */ +static GstElementDetails massink_details = { + "Esound audio sink", + "Sink/Audio", + "LGPL", + "Plays audio to a MAS server", + VERSION, + "Zeeshan Ali <zak147@yahoo.com>", + "(C) 2003", +}; + +/* Signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_MUTE, + ARG_DEPTH, + ARG_CHANNELS, + ARG_RATE, + ARG_HOST, +}; + +GST_PAD_TEMPLATE_FACTORY (sink_factory, + "sink", /* the name of the pads */ + GST_PAD_SINK, /* type of the pad */ + GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */ + GST_CAPS_NEW ( + "massink_sink8", /* the name of the caps */ + "audio/x-wav", /* the mime type of the caps */ + NULL + ) +); + +static void gst_massink_class_init (GstMassinkClass *klass); +static void gst_massink_init (GstMassink *massink); +static void gst_massink_set_clock (GstElement *element, GstClock *clock); +static gboolean gst_massink_open_audio (GstMassink *sink); +//static void gst_massink_close_audio (GstMassink *sink); +static GstElementStateReturn gst_massink_change_state (GstElement *element); +static gboolean gst_massink_sync_parms (GstMassink *massink); +static GstPadLinkReturn gst_massink_sinkconnect (GstPad *pad, GstCaps *caps); + +static void gst_massink_chain (GstPad *pad, GstBuffer *buf); + +static void gst_massink_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_massink_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +#define GST_TYPE_MASSINK_DEPTHS (gst_massink_depths_get_type()) +static GType +gst_massink_depths_get_type (void) +{ + static GType massink_depths_type = 0; + static GEnumValue massink_depths[] = { + {8, "8", "8 Bits"}, + {16, "16", "16 Bits"}, + {0, NULL, NULL}, + }; + if (!massink_depths_type) { + massink_depths_type = g_enum_register_static("GstMassinkDepths", massink_depths); + } + return massink_depths_type; +} + +static GstElementClass *parent_class = NULL; +/*static guint gst_massink_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_massink_get_type (void) +{ + static GType massink_type = 0; + + if (!massink_type) { + static const GTypeInfo massink_info = { + sizeof(GstMassinkClass), NULL, + NULL, + (GClassInitFunc)gst_massink_class_init, + NULL, + NULL, + sizeof(GstMassink), + 0, + (GInstanceInitFunc)gst_massink_init, + }; + massink_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMassink", &massink_info, 0); + } + return massink_type; +} + +static void +gst_massink_class_init (GstMassinkClass *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_MUTE, + g_param_spec_boolean("mute","mute","mute", + TRUE,G_PARAM_READWRITE)); /* CHECKME */ + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEPTH, + g_param_spec_enum("depth","depth","depth", + GST_TYPE_MASSINK_DEPTHS,16,G_PARAM_READWRITE)); /* CHECKME! */ + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_RATE, + g_param_spec_int("frequency","frequency","frequency", + G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */ + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HOST, + g_param_spec_string("host","host","host", + NULL, G_PARAM_READWRITE)); /* CHECKME */ + + gobject_class->set_property = gst_massink_set_property; + gobject_class->get_property = gst_massink_get_property; + + gstelement_class->change_state = gst_massink_change_state; + gstelement_class->set_clock = gst_massink_set_clock; +} + +static void +gst_massink_set_clock (GstElement *element, GstClock *clock) +{ + GstMassink *massink; + + massink = GST_MASSINK (element); + + massink->clock = clock; +} + +static void +gst_massink_init(GstMassink *massink) +{ + massink->sinkpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (sink_factory), "sink"); + gst_element_add_pad(GST_ELEMENT(massink), massink->sinkpad); + gst_pad_set_chain_function(massink->sinkpad, GST_DEBUG_FUNCPTR(gst_massink_chain)); + gst_pad_set_link_function(massink->sinkpad, gst_massink_sinkconnect); + + massink->mute = FALSE; + massink->format = 16; + massink->depth = 16; + massink->channels = 2; + massink->frequency = 44100; + massink->host = NULL; +} + +static gboolean +gst_massink_sync_parms (GstMassink *massink) +{ + g_return_val_if_fail (massink != NULL, FALSE); + g_return_val_if_fail (GST_IS_MASSINK (massink), FALSE); + + //gst_massink_close_audio (massink); + //return gst_massink_open_audio (massink); + return 1; +} + +static GstPadLinkReturn +gst_massink_sinkconnect (GstPad *pad, GstCaps *caps) +{ + GstMassink *massink; + + massink = GST_MASSINK (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) + return GST_PAD_LINK_DELAYED; + + if (gst_massink_sync_parms (massink)) + return GST_PAD_LINK_OK; + + return GST_PAD_LINK_REFUSED; +} + +static void +gst_massink_chain (GstPad *pad, GstBuffer *buf) +{ + gint32 err; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + GstMassink *massink = GST_MASSINK (gst_pad_get_parent (pad)); + + if (massink->clock) { + GstClockID id = gst_clock_new_single_shot_id (massink->clock, GST_BUFFER_TIMESTAMP (buf)); + + GST_DEBUG (0, "massink: clock wait: %llu\n", GST_BUFFER_TIMESTAMP (buf)); + gst_element_clock_wait (GST_ELEMENT (massink), id, NULL); + gst_clock_id_free (id); + } + + if (GST_BUFFER_DATA (buf) != NULL) { + if (!massink->mute) { + GST_DEBUG (0, "massink: data=%p size=%d", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + if (GST_BUFFER_SIZE (buf) > BUFFER_SIZE) { + gst_buffer_unref (buf); + return; + } + + massink->data->length = GST_BUFFER_SIZE (buf); + + memcpy (massink->data->segment, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + + err = mas_send (massink->audio_channel, massink->data); + + if (err < 0) { + g_print ("error sending data to MAS server\n"); + gst_buffer_unref (buf); + return; + } + + /* FIXME: Please correct the Timestamping if its wrong */ + massink->data->header.media_timestamp += massink->data->length / 4; + massink->data->header.sequence++; + } + } + + gst_buffer_unref (buf); +} + +static void +gst_massink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstMassink *massink; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MASSINK(object)); + massink = GST_MASSINK(object); + + switch (prop_id) { + case ARG_MUTE: + massink->mute = g_value_get_boolean (value); + break; + case ARG_DEPTH: + massink->depth = g_value_get_enum (value); + gst_massink_sync_parms (massink); + break; + case ARG_CHANNELS: + massink->channels = g_value_get_enum (value); + gst_massink_sync_parms (massink); + break; + case ARG_RATE: + massink->frequency = g_value_get_int (value); + gst_massink_sync_parms (massink); + break; + case ARG_HOST: + if (massink->host != NULL) g_free(massink->host); + if (g_value_get_string (value) == NULL) + massink->host = NULL; + else + massink->host = g_strdup (g_value_get_string (value)); + break; + default: + break; + } +} + +static void +gst_massink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstMassink *massink; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_MASSINK(object)); + massink = GST_MASSINK(object); + + switch (prop_id) { + case ARG_MUTE: + g_value_set_boolean (value, massink->mute); + break; + case ARG_DEPTH: + g_value_set_enum (value, massink->depth); + break; + case ARG_CHANNELS: + g_value_set_enum (value, massink->channels); + break; + case ARG_RATE: + g_value_set_int (value, massink->frequency); + break; + case ARG_HOST: + g_value_set_string (value, massink->host); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_element_factory_new("massink", GST_TYPE_MASSINK, + &massink_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_element_factory_add_pad_template(factory, GST_PAD_TEMPLATE_GET (sink_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "massink", + plugin_init +}; + +static gboolean +gst_massink_open_audio (GstMassink *massink) +{ + gint32 err; + char *ratestring = g_malloc (16); + char *bps = g_malloc (8); + + struct mas_data_characteristic* dc; + + g_print ("Connecting to MAS.\n"); + masc_log_verbosity (MAS_VERBLVL_DEBUG); + err = mas_init(); + + if (err < 0) { + GST_DEBUG(err, "connection with local MAS server failed."); + exit (1); + } + + GST_DEBUG (0, "Establishing audio output channel."); + mas_make_data_channel ("Gstreamer", &massink->audio_channel, &massink->audio_source, &massink->audio_sink); + mas_asm_get_port_by_name (0, "default_mix_sink", &massink->mix_sink); + + GST_DEBUG (0, "Instantiating endian device."); + err = mas_asm_instantiate_device ("endian", 0, 0, &massink->endian); + + if (err < 0) { + GST_DEBUG(0, "Failed to instantiate endian converter device"); + exit(1); + } + + mas_asm_get_port_by_name (massink->endian, "endian_sink", &massink->endian_sink); + mas_asm_get_port_by_name (massink->endian, "endian_source", &massink->endian_source); + + sprintf (bps, "%u", massink->depth); + sprintf (ratestring, "%u", massink->frequency); + + GST_DEBUG (0, "Connecting net -> endian."); + masc_make_dc (&dc, 6); + + /* wav weirdness: 8 bit data is unsigned, >8 data is signed. */ + masc_append_dc_key_value (dc, "format", (massink->depth==8) ? "ulinear":"linear"); + masc_append_dc_key_value (dc, "resolution", bps); + masc_append_dc_key_value (dc, "sampling rate", ratestring); + masc_append_dc_key_value (dc, "channels", "2"); + masc_append_dc_key_value (dc, "endian", "little"); + err = mas_asm_connect_source_sink (massink->audio_source, massink->endian_sink, dc); + + if ( err < 0 ) { + GST_DEBUG(err, "Failed to connect net audio output to endian"); + return -1; + } + + /* The next device is 'if needed' only. After the following if() + statement, open_source will contain the current unconnected + source in the path (will be either endian_source or + squant_source in this case) + */ + + massink->open_source = massink->endian_source; + + if (massink->depth != 16) { + GST_DEBUG (0, "Sample resolution is not 16 bit/sample, instantiating squant device."); + err = mas_asm_instantiate_device ("squant", 0, 0, &massink->squant); + if (err < 0) { + GST_DEBUG(err, "Failed to instantiate squant device"); + return -1; + } + + mas_asm_get_port_by_name (massink->squant, "squant_sink", &massink->squant_sink); + mas_asm_get_port_by_name (massink->squant, "squant_source", &massink->squant_source); + + GST_DEBUG (0, "Connecting endian -> squant."); + + masc_make_dc (&dc, 6); + masc_append_dc_key_value (dc,"format",(massink->depth==8) ? "ulinear":"linear"); + masc_append_dc_key_value (dc, "resolution", bps); + masc_append_dc_key_value (dc, "sampling rate", ratestring); + masc_append_dc_key_value (dc, "channels", "2"); + masc_append_dc_key_value (dc, "endian", "host"); + err = mas_asm_connect_source_sink (massink->endian_source, massink->squant_sink, dc); + + if (err < 0) { + GST_DEBUG(err, "Failed to connect endian output to squant"); + return -1; + } + + /* sneaky: the squant device is optional -> pretend it isn't there */ + massink->open_source = massink->squant_source; + } + + + /* Another 'if necessary' device, as above */ + if (massink->frequency != 44100) { + GST_DEBUG (0, "Sample rate is not 44100, instantiating srate device."); + err = mas_asm_instantiate_device ("srate", 0, 0, &massink->srate); + + if (err < 0) { + GST_DEBUG (err, "Failed to instantiate srate device"); + return -1; + } + + mas_asm_get_port_by_name (massink->srate, "sink", &massink->srate_sink); + mas_asm_get_port_by_name (massink->srate, "source", &massink->srate_source); + + GST_DEBUG (0, "Connecting to srate."); + masc_make_dc (&dc, 6); + masc_append_dc_key_value (dc, "format", "linear"); + masc_append_dc_key_value (dc, "resolution", "16"); + masc_append_dc_key_value (dc, "sampling rate", ratestring); + masc_append_dc_key_value (dc, "channels", "2"); + masc_append_dc_key_value (dc, "endian", "host"); + + err = mas_asm_connect_source_sink (massink->open_source, massink->srate_sink, dc); + + if ( err < 0 ) { + GST_DEBUG(err, "Failed to connect to srate"); + return -1; + } + + + massink->open_source = massink->srate_source; + } + + GST_DEBUG(0, "Connecting to mix."); + masc_make_dc(&dc, 6); + masc_append_dc_key_value (dc, "format", "linear"); + masc_append_dc_key_value (dc, "resolution", "16"); + masc_append_dc_key_value (dc, "sampling rate", "44100"); + masc_append_dc_key_value (dc, "channels", "2"); + masc_append_dc_key_value (dc, "endian", "host"); + + err = mas_asm_connect_source_sink (massink->open_source, massink->mix_sink, dc); + + if ( err < 0 ) { + GST_DEBUG(err, "Failed to connect to mixer"); + return -1; + } + + GST_FLAG_SET (massink, GST_MASSINK_OPEN); + + masc_make_mas_data (&massink->data, BUFFER_SIZE); + + massink->data->header.type = 10; + + massink->data->header.media_timestamp = 0; + massink->data->header.sequence = 0; + + return TRUE; +} + +/*static void +gst_massink_close_audio (GstMassink *massink) +{ + mas_free_device(massink->endian); + mas_free_device(massink->srate); + mas_free_device(massink->squant); + + mas_free_port(massink->mix_sink); + mas_free_port(massink->srate_source); + mas_free_port(massink->srate_sink); + mas_free_port(massink->audio_source); + mas_free_port(massink->audio_sink); + mas_free_port(massink->endian_source); + mas_free_port(massink->endian_sink); + mas_free_port(massink->squant_source); + mas_free_port(massink->squant_sink); + mas_free_port(massink->open_source); + + mas_free_channel (massink->audio_channel); + masc_destroy_mas_data (massink->data); + + g_free (ratestring); + g_free (bps); + + GST_FLAG_UNSET (massink, GST_MASSINK_OPEN); + + GST_DEBUG (0, "massink: closed sound channel"); +}*/ + +static GstElementStateReturn +gst_massink_change_state (GstElement *element) +{ + g_return_val_if_fail (GST_IS_MASSINK (element), FALSE); + + /* if going down into NULL state, close the fd if it's open */ + if (GST_STATE_PENDING (element) == GST_STATE_NULL) { + //if (GST_FLAG_IS_SET (element, GST_MASSINK_OPEN)) + //gst_massink_close_audio (GST_MASSINK (element)); + /* otherwise (READY or higher) we need to open the fd */ + } else { + if (!GST_FLAG_IS_SET (element, GST_MASSINK_OPEN)) { + if (!gst_massink_open_audio (GST_MASSINK (element))) + return GST_STATE_FAILURE; + } + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + return GST_STATE_SUCCESS; +} + |