~oah-dev/oah/gst-plugins-bad

« back to all changes in this revision

Viewing changes to ext/xine/xineaudiosink.c

  • Committer: Haakon Sporsheim
  • Date: 2009-03-12 13:52:03 UTC
  • Revision ID: haakon.sporsheim@tandberg.com-20090312135203-i5k294hgkushb0mt
Initial import of git repository: git://anongit.freedesktop.org/gstreamer/gst-plugins-bad (tag: RELEASE-0_10_10)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer
 
2
 * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
 
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
#include <gst/gst.h>
 
21
#include "gstxine.h"
 
22
#include <xine/audio_out.h>
 
23
#include <xine/xine_internal.h>
 
24
#include <xine/plugin_catalog.h>
 
25
 
 
26
#define GST_TYPE_XINE_AUDIO_SINK \
 
27
  (gst_xine_audio_sink_get_type())
 
28
#define GST_XINE_AUDIO_SINK(obj) \
 
29
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XINE_AUDIO_SINK,GstXineAudioSink))
 
30
#define GST_XINE_AUDIO_SINK_GET_CLASS(obj) \
 
31
  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XINE_AUDIO_SINK, GstXineAudioSinkClass))
 
32
#define GST_XINE_AUDIO_SINK_CLASS(klass) \
 
33
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XINE_AUDIO_SINK,GstXineAudioSinkClass))
 
34
#define GST_IS_XINE_AUDIO_SINK(obj) \
 
35
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XINE_AUDIO_SINK))
 
36
#define GST_IS_XINE_AUDIO_SINK_CLASS(klass) \
 
37
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XINE_AUDIO_SINK))
 
38
 
 
39
GType gst_xine_audio_sink_get_type (void);
 
40
 
 
41
typedef struct _GstXineAudioSink GstXineAudioSink;
 
42
typedef struct _GstXineAudioSinkClass GstXineAudioSinkClass;
 
43
 
 
44
struct _GstXineAudioSink
 
45
{
 
46
  GstXine parent;
 
47
 
 
48
  GstPad *sinkpad;
 
49
 
 
50
  ao_driver_t *driver;
 
51
  guint open;                   /* number of bytes per sample or 0 if driver not open */
 
52
};
 
53
 
 
54
struct _GstXineAudioSinkClass
 
55
{
 
56
  GstXineClass parent_class;
 
57
 
 
58
  plugin_node_t *plugin_node;
 
59
};
 
60
 
 
61
/** GstXineAudioSink ***********************************************************/
 
62
 
 
63
GST_BOILERPLATE (GstXineAudioSink, gst_xine_audio_sink, GstXine, GST_TYPE_XINE);
 
64
 
 
65
static GstStateChangeReturn
 
66
gst_xine_audio_sink_change_state (GstElement * element,
 
67
    GstStateChange transition);
 
68
 
 
69
static void
 
70
gst_xine_audio_sink_base_init (gpointer g_class)
 
71
{
 
72
}
 
73
 
 
74
static void
 
75
gst_xine_audio_sink_class_init (GstXineAudioSinkClass * klass)
 
76
{
 
77
  GstElementClass *element = GST_ELEMENT_CLASS (klass);
 
78
 
 
79
  element->change_state = gst_xine_audio_sink_change_state;
 
80
}
 
81
 
 
82
static void
 
83
gst_xine_audio_sink_init (GstXineAudioSink * xine,
 
84
    GstXineAudioSinkClass * g_class)
 
85
{
 
86
}
 
87
 
 
88
static void
 
89
gst_xine_audio_sink_chain (GstPad * pad, GstData * data)
 
90
{
 
91
  GstXineAudioSink *xine =
 
92
      GST_XINE_AUDIO_SINK (gst_object_get_parent (GST_OBJECT (pad)));
 
93
 
 
94
  while (xine->driver->write (xine->driver, (guint16 *) GST_BUFFER_DATA (data),
 
95
          GST_BUFFER_SIZE (data) / xine->open) == 0);
 
96
  gst_data_unref (GST_DATA (data));
 
97
}
 
98
 
 
99
static GstStateChangeReturn
 
100
gst_xine_audio_sink_change_state (GstElement * element,
 
101
    GstStateChange transition)
 
102
{
 
103
  GstXineAudioSink *xine = GST_XINE_AUDIO_SINK (element);
 
104
  audio_driver_class_t *driver =
 
105
      (audio_driver_class_t *) GST_XINE_AUDIO_SINK_GET_CLASS (xine)->
 
106
      plugin_node->plugin_class;
 
107
 
 
108
  switch (transition) {
 
109
    case GST_STATE_CHANGE_NULL_TO_READY:
 
110
      if (driver == NULL) {
 
111
        xine_audio_port_t *port =
 
112
            xine_open_audio_driver (GST_XINE_GET_CLASS (xine)->xine,
 
113
            GST_XINE_AUDIO_SINK_GET_CLASS (xine)->plugin_node->info->id, NULL);
 
114
 
 
115
        if (!port)
 
116
          return GST_STATE_CHANGE_FAILURE;
 
117
        port->exit (port);
 
118
        driver =
 
119
            (audio_driver_class_t *) GST_XINE_AUDIO_SINK_GET_CLASS (xine)->
 
120
            plugin_node->plugin_class;
 
121
        if (driver == NULL)
 
122
          return GST_STATE_CHANGE_FAILURE;
 
123
      }
 
124
      xine->driver = driver->open_plugin (driver, NULL);
 
125
      if (!xine->driver)
 
126
        return GST_STATE_CHANGE_FAILURE;
 
127
      break;
 
128
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 
129
      break;
 
130
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
 
131
      break;
 
132
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
 
133
      break;
 
134
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 
135
      if (xine->open != 0)
 
136
        xine->driver->close (xine->driver);
 
137
      xine->open = 0;
 
138
      break;
 
139
    case GST_STATE_CHANGE_READY_TO_NULL:
 
140
      xine->driver->exit (xine->driver);
 
141
      xine->driver = NULL;
 
142
      break;
 
143
    default:
 
144
      GST_ERROR_OBJECT (element, "invalid state change");
 
145
      break;
 
146
  }
 
147
 
 
148
  return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
 
149
      (element), GST_STATE_CHANGE_SUCCESS);
 
150
}
 
151
 
 
152
static GstCaps *
 
153
_xine_audio_sink_get_caps (GstPad * pad)
 
154
{
 
155
  GstXineAudioSink *xine =
 
156
      GST_XINE_AUDIO_SINK (gst_object_get_parent (GST_OBJECT (pad)));
 
157
  GstCaps *caps, *ret = gst_caps_new_empty ();
 
158
  guint32 capa, channels;
 
159
 
 
160
  if (!xine->driver)
 
161
    return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
 
162
 
 
163
  capa = xine->driver->get_capabilities (xine->driver);
 
164
  channels = capa & (AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO);
 
165
 
 
166
  if (channels == 0) {
 
167
    /* neither mono nor stereo supported, die */
 
168
    return ret;
 
169
  }
 
170
 
 
171
  /* this loop is messy */
 
172
  capa &= AO_CAP_8BITS;
 
173
  do {
 
174
    if (capa & AO_CAP_8BITS) {
 
175
      caps = gst_caps_from_string ("audio/x-raw-int, "
 
176
          "signed = (boolean) FALSE, "
 
177
          "width = (int) 8, "
 
178
          "depth = (int) 8, " "rate = (int) [ 8000, 192000 ]");
 
179
      capa &= ~AO_CAP_8BITS;
 
180
    } else {
 
181
      caps = gst_caps_from_string ("audio/x-raw-int, "
 
182
          "endianness = (int) BYTE_ORDER, "
 
183
          "signed = (boolean) TRUE, "
 
184
          "width = (int) 16, "
 
185
          "depth = (int) 16, " "rate = (int) [ 8000, 192000 ]");
 
186
      capa = -1;
 
187
    }
 
188
    switch (channels) {
 
189
      case AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO:
 
190
        gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
 
191
        break;
 
192
      case AO_CAP_MODE_MONO:
 
193
        gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
 
194
        break;
 
195
      case AO_CAP_MODE_STEREO:
 
196
        gst_caps_set_simple (caps, "channels", G_TYPE_INT, 2, NULL);
 
197
        break;
 
198
      default:
 
199
        g_assert_not_reached ();
 
200
        break;
 
201
    }
 
202
    gst_caps_append (ret, caps);
 
203
  } while (capa != -1);
 
204
 
 
205
  return ret;
 
206
}
 
207
 
 
208
static GstPadLinkReturn
 
209
_xine_audio_sink_link (GstPad * pad, const GstCaps * caps)
 
210
{
 
211
  GstStructure *structure = gst_caps_get_structure (caps, 0);
 
212
  GstXineAudioSink *xine =
 
213
      GST_XINE_AUDIO_SINK (gst_object_get_parent (GST_OBJECT (pad)));
 
214
  guint channels, temp, rate, width;
 
215
  int mode;
 
216
 
 
217
  if (!gst_structure_get_int (structure, "channels", &channels))
 
218
    return GST_PAD_LINK_REFUSED;
 
219
  mode = (channels == 1) ? AO_CAP_MODE_MONO : AO_CAP_MODE_STEREO;
 
220
  if (!gst_structure_get_int (structure, "rate", &rate))
 
221
    return GST_PAD_LINK_REFUSED;
 
222
  if (!gst_structure_get_int (structure, "width", &width))
 
223
    return GST_PAD_LINK_REFUSED;
 
224
 
 
225
  if (xine->open != 0)
 
226
    xine->driver->close (xine->driver);
 
227
  xine->open = 0;
 
228
  temp = xine->driver->open (xine->driver, width, rate, mode);
 
229
  if (temp == 0)
 
230
    return GST_PAD_LINK_REFUSED;
 
231
 
 
232
  xine->open = channels * width / 8;
 
233
  if (temp != rate) {
 
234
    /* FIXME? */
 
235
    GST_WARNING_OBJECT (xine, "rates don't match (requested: %u, got %u)", rate,
 
236
        temp);
 
237
  }
 
238
 
 
239
  return GST_PAD_LINK_OK;
 
240
}
 
241
 
 
242
/** GstXineAudioSink subclasses ************************************************/
 
243
 
 
244
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
 
245
    GST_PAD_SINK,
 
246
    GST_PAD_ALWAYS,
 
247
    GST_STATIC_CAPS ("audio/x-raw-int, "
 
248
        "signed = (boolean) FALSE, "
 
249
        "width = (int) 8, "
 
250
        "depth = (int) 8, "
 
251
        "rate = (int) [ 8000, 192000 ], "
 
252
        "channels = (int) [1, 2]; "
 
253
        "audio/x-raw-int, "
 
254
        "endianness = (int) BYTE_ORDER, "
 
255
        "signed = (boolean) TRUE, "
 
256
        "width = (int) 16, "
 
257
        "depth = (int) 16, "
 
258
        "rate = (int) [ 8000, 192000 ], " "channels = (int) [1, 2]")
 
259
    );
 
260
 
 
261
static void
 
262
gst_xine_audio_sink_subclass_init (gpointer g_class, gpointer class_data)
 
263
{
 
264
  GstXineAudioSinkClass *xine_class = GST_XINE_AUDIO_SINK_CLASS (g_class);
 
265
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
266
  GstElementDetails details = GST_ELEMENT_DETAILS (NULL,
 
267
      "Source",
 
268
      NULL,
 
269
      "Benjamin Otte <otte@gnome.org>");
 
270
 
 
271
  xine_class->plugin_node = class_data;
 
272
  details.longname =
 
273
      g_strdup_printf ("%s xine audio sink", xine_class->plugin_node->info->id);
 
274
  details.description =
 
275
      g_strdup_printf ("%s audio output using Xine",
 
276
      xine_class->plugin_node->info->id);
 
277
  gst_element_class_set_details (element_class, &details);
 
278
  g_free (details.longname);
 
279
  g_free (details.description);
 
280
 
 
281
  gst_element_class_add_pad_template (element_class,
 
282
      gst_static_pad_template_get (&sink_template));
 
283
}
 
284
 
 
285
static void
 
286
gst_xine_audio_sink_sub_init (GTypeInstance * instance, gpointer g_class)
 
287
{
 
288
  GstElementClass *klass = GST_ELEMENT_GET_CLASS (instance);
 
289
  GstXineAudioSink *xine = GST_XINE_AUDIO_SINK (instance);
 
290
 
 
291
  xine->sinkpad =
 
292
      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
 
293
          "sink"), "sink");
 
294
  gst_pad_set_chain_function (xine->sinkpad, gst_xine_audio_sink_chain);
 
295
  gst_pad_set_getcaps_function (xine->sinkpad, _xine_audio_sink_get_caps);
 
296
  gst_pad_set_link_function (xine->sinkpad, _xine_audio_sink_link);
 
297
  gst_element_add_pad (GST_ELEMENT (xine), xine->sinkpad);
 
298
}
 
299
 
 
300
gboolean
 
301
gst_xine_audio_sink_init_plugin (GstPlugin * plugin)
 
302
{
 
303
  GTypeInfo plugin_info = {
 
304
    sizeof (GstXineAudioSinkClass),
 
305
    NULL,
 
306
    NULL,
 
307
    gst_xine_audio_sink_subclass_init,
 
308
    NULL,
 
309
    NULL,
 
310
    sizeof (GstXineAudioSink),
 
311
    0,
 
312
    gst_xine_audio_sink_sub_init,
 
313
  };
 
314
  plugin_node_t *node;
 
315
  GstXineClass *klass;
 
316
 
 
317
  klass = g_type_class_ref (GST_TYPE_XINE);
 
318
 
 
319
  node = xine_list_first_content (klass->xine->plugin_catalog->aout);
 
320
  while (node) {
 
321
    gchar *plugin_name = g_strdup_printf ("xineaudiosink_%s", node->info->id);
 
322
    gchar *type_name = g_strdup_printf ("GstXineAudioSink%s", node->info->id);
 
323
    GType type;
 
324
 
 
325
    plugin_info.class_data = node;
 
326
    type =
 
327
        g_type_register_static (GST_TYPE_XINE_AUDIO_SINK, type_name,
 
328
        &plugin_info, 0);
 
329
    g_free (type_name);
 
330
    if (!gst_element_register (plugin, plugin_name, GST_RANK_MARGINAL, type)) {
 
331
      g_free (plugin_name);
 
332
      return FALSE;
 
333
    }
 
334
    g_free (plugin_name);
 
335
 
 
336
    node = xine_list_next_content (klass->xine->plugin_catalog->aout);
 
337
  }
 
338
 
 
339
  g_type_class_unref (klass);
 
340
  return TRUE;
 
341
}