Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / sys / sunaudio / gstsunaudiosrc.c
1 /*
2  * GStreamer - SunAudio source
3  * Copyright (C) 2005,2006 Sun Microsystems, Inc.,
4  *               Brian Cameron <brian.cameron@sun.com>
5  *
6  * gstsunaudiosrc.c: 
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:element-sunaudiosrc
26  *
27  * sunaudiosrc is an audio source designed to work with the Sun Audio
28  * interface available in Solaris.
29  *
30  * <refsect2>
31  * <title>Example launch line</title>
32  * |[
33  * gst-launch sunaudiosrc ! wavenc ! filesink location=audio.wav
34  * ]|
35  * </refsect2>
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <fcntl.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <stropts.h>
46 #include <sys/mixer.h>
47
48 #include "gstsunaudiosrc.h"
49
50 GST_DEBUG_CATEGORY_EXTERN (sunaudio_debug);
51 #define GST_CAT_DEFAULT sunaudio_debug
52
53 static void gst_sunaudiosrc_base_init (gpointer g_class);
54 static void gst_sunaudiosrc_class_init (GstSunAudioSrcClass * klass);
55 static void gst_sunaudiosrc_init (GstSunAudioSrc * sunaudiosrc,
56     GstSunAudioSrcClass * g_class);
57 static void gst_sunaudiosrc_dispose (GObject * object);
58
59 static void gst_sunaudiosrc_set_property (GObject * object, guint prop_id,
60     const GValue * value, GParamSpec * pspec);
61 static void gst_sunaudiosrc_get_property (GObject * object, guint prop_id,
62     GValue * value, GParamSpec * pspec);
63
64 static GstCaps *gst_sunaudiosrc_getcaps (GstBaseSrc * bsrc);
65
66 static gboolean gst_sunaudiosrc_open (GstAudioSrc * asrc);
67 static gboolean gst_sunaudiosrc_close (GstAudioSrc * asrc);
68 static gboolean gst_sunaudiosrc_prepare (GstAudioSrc * asrc,
69     GstRingBufferSpec * spec);
70 static gboolean gst_sunaudiosrc_unprepare (GstAudioSrc * asrc);
71 static guint gst_sunaudiosrc_read (GstAudioSrc * asrc, gpointer data,
72     guint length);
73 static guint gst_sunaudiosrc_delay (GstAudioSrc * asrc);
74 static void gst_sunaudiosrc_reset (GstAudioSrc * asrc);
75
76 #define DEFAULT_DEVICE          "/dev/audio"
77
78 enum
79 {
80   PROP_0,
81   PROP_DEVICE
82 };
83
84 GST_BOILERPLATE_WITH_INTERFACE (GstSunAudioSrc, gst_sunaudiosrc,
85     GstAudioSrc, GST_TYPE_AUDIO_SRC, GstMixer, GST_TYPE_MIXER, gst_sunaudiosrc);
86
87 GST_IMPLEMENT_SUNAUDIO_MIXER_CTRL_METHODS (GstSunAudioSrc, gst_sunaudiosrc);
88
89 static GstStaticPadTemplate gst_sunaudiosrc_factory =
90 GST_STATIC_PAD_TEMPLATE ("src",
91     GST_PAD_SRC,
92     GST_PAD_ALWAYS,
93     GST_STATIC_CAPS ("audio/x-raw-int, "
94         "endianness = (int) BYTE_ORDER, "
95         "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16, "
96         /* [5510,48000] seems to be a Solaris limit */
97         "rate = (int) [ 5510, 48000 ], " "channels = (int) [ 1, 2 ]")
98     );
99
100 static void
101 gst_sunaudiosrc_dispose (GObject * object)
102 {
103   G_OBJECT_CLASS (parent_class)->dispose (object);
104 }
105
106 static void
107 gst_sunaudiosrc_base_init (gpointer g_class)
108 {
109   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
110
111   gst_element_class_add_static_pad_template (element_class,
112       &gst_sunaudiosrc_factory);
113   gst_element_class_set_details_simple (element_class, "Sun Audio Source",
114       "Source/Audio",
115       "Audio source for Sun Audio devices",
116       "Brian Cameron <brian.cameron@sun.com>");
117 }
118
119 static void
120 gst_sunaudiosrc_class_init (GstSunAudioSrcClass * klass)
121 {
122   GObjectClass *gobject_class;
123   GstElementClass *gstelement_class;
124   GstBaseSrcClass *gstbasesrc_class;
125   GstBaseAudioSrcClass *gstbaseaudiosrc_class;
126   GstAudioSrcClass *gstaudiosrc_class;
127
128   gobject_class = (GObjectClass *) klass;
129   gstelement_class = (GstElementClass *) klass;
130   gstbasesrc_class = (GstBaseSrcClass *) klass;
131   gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
132   gstaudiosrc_class = (GstAudioSrcClass *) klass;
133
134   gobject_class->dispose = gst_sunaudiosrc_dispose;
135   gobject_class->get_property = gst_sunaudiosrc_get_property;
136   gobject_class->set_property = gst_sunaudiosrc_set_property;
137
138   gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_getcaps);
139
140   gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_open);
141   gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_prepare);
142   gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_unprepare);
143   gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_close);
144   gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_read);
145   gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_delay);
146   gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_sunaudiosrc_reset);
147
148   g_object_class_install_property (gobject_class, PROP_DEVICE,
149       g_param_spec_string ("device", "Device",
150           "SunAudio device (usually /dev/audio)", DEFAULT_DEVICE,
151           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152 }
153
154 static void
155 gst_sunaudiosrc_init (GstSunAudioSrc * sunaudiosrc,
156     GstSunAudioSrcClass * g_class)
157 {
158   const char *audiodev;
159
160   GST_DEBUG_OBJECT (sunaudiosrc, "initializing sunaudiosrc");
161
162   sunaudiosrc->fd = -1;
163
164   audiodev = g_getenv ("AUDIODEV");
165   if (audiodev == NULL)
166     audiodev = DEFAULT_DEVICE;
167   sunaudiosrc->device = g_strdup (audiodev);
168 }
169
170 static void
171 gst_sunaudiosrc_set_property (GObject * object, guint prop_id,
172     const GValue * value, GParamSpec * pspec)
173 {
174   GstSunAudioSrc *sunaudiosrc;
175
176   sunaudiosrc = GST_SUNAUDIO_SRC (object);
177
178   switch (prop_id) {
179     case PROP_DEVICE:
180       if (sunaudiosrc->device)
181         g_free (sunaudiosrc->device);
182       sunaudiosrc->device = g_value_dup_string (value);
183       break;
184     default:
185       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
186       break;
187   }
188 }
189
190 static void
191 gst_sunaudiosrc_get_property (GObject * object, guint prop_id,
192     GValue * value, GParamSpec * pspec)
193 {
194   GstSunAudioSrc *sunaudiosrc;
195
196   sunaudiosrc = GST_SUNAUDIO_SRC (object);
197
198   switch (prop_id) {
199     case PROP_DEVICE:
200       g_value_set_string (value, sunaudiosrc->device);
201       break;
202     default:
203       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
204       break;
205   }
206 }
207
208 static GstCaps *
209 gst_sunaudiosrc_getcaps (GstBaseSrc * bsrc)
210 {
211   GstPadTemplate *pad_template;
212   GstCaps *caps = NULL;
213   GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (bsrc);
214
215   GST_DEBUG_OBJECT (sunaudiosrc, "getcaps called");
216
217   pad_template = gst_static_pad_template_get (&gst_sunaudiosrc_factory);
218   caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
219
220   gst_object_unref (pad_template);
221
222   return caps;
223 }
224
225 static gboolean
226 gst_sunaudiosrc_open (GstAudioSrc * asrc)
227 {
228   GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc);
229   int fd, ret;
230
231   fd = open (sunaudiosrc->device, O_RDONLY);
232
233   if (fd == -1) {
234     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, OPEN_READ, (NULL),
235         ("can't open connection to Sun Audio device %s", sunaudiosrc->device));
236
237     return FALSE;
238   }
239
240   sunaudiosrc->fd = fd;
241
242   ret = ioctl (fd, AUDIO_GETDEV, &sunaudiosrc->dev);
243   if (ret == -1) {
244     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
245             strerror (errno)));
246     return FALSE;
247   }
248
249   GST_DEBUG_OBJECT (sunaudiosrc, "name %s", sunaudiosrc->dev.name);
250   GST_DEBUG_OBJECT (sunaudiosrc, "version %s", sunaudiosrc->dev.version);
251   GST_DEBUG_OBJECT (sunaudiosrc, "config %s", sunaudiosrc->dev.config);
252
253   ret = ioctl (fd, AUDIO_GETINFO, &sunaudiosrc->info);
254   if (ret == -1) {
255     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
256             strerror (errno)));
257     return FALSE;
258   }
259
260   GST_DEBUG_OBJECT (sunaudiosrc, "monitor_gain %d",
261       sunaudiosrc->info.monitor_gain);
262   GST_DEBUG_OBJECT (sunaudiosrc, "output_muted %d",
263       sunaudiosrc->info.output_muted);
264   GST_DEBUG_OBJECT (sunaudiosrc, "hw_features %08x",
265       sunaudiosrc->info.hw_features);
266   GST_DEBUG_OBJECT (sunaudiosrc, "sw_features %08x",
267       sunaudiosrc->info.sw_features);
268   GST_DEBUG_OBJECT (sunaudiosrc, "sw_features_enabled %08x",
269       sunaudiosrc->info.sw_features_enabled);
270
271   if (!sunaudiosrc->mixer) {
272     const char *audiodev;
273
274     audiodev = g_getenv ("AUDIODEV");
275     if (audiodev == NULL) {
276       sunaudiosrc->mixer = gst_sunaudiomixer_ctrl_new ("/dev/audioctl");
277     } else {
278       gchar *device = g_strdup_printf ("%sctl", audiodev);
279
280       sunaudiosrc->mixer = gst_sunaudiomixer_ctrl_new (device);
281       g_free (device);
282     }
283   }
284
285   return TRUE;
286 }
287
288 static gboolean
289 gst_sunaudiosrc_close (GstAudioSrc * asrc)
290 {
291   GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc);
292
293   close (sunaudiosrc->fd);
294   sunaudiosrc->fd = -1;
295
296   if (sunaudiosrc->mixer) {
297     gst_sunaudiomixer_ctrl_free (sunaudiosrc->mixer);
298     sunaudiosrc->mixer = NULL;
299   }
300
301   return TRUE;
302 }
303
304 static gboolean
305 gst_sunaudiosrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
306 {
307   GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc);
308   audio_info_t ainfo;
309   int ret;
310   GstSunAudioMixerCtrl *mixer;
311   struct audio_info audioinfo;
312
313   ret = ioctl (sunaudiosrc->fd, AUDIO_GETINFO, &ainfo);
314   if (ret == -1) {
315     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
316             strerror (errno)));
317     return FALSE;
318   }
319
320   if (spec->width != 16)
321     return FALSE;
322
323   AUDIO_INITINFO (&ainfo);
324
325   ainfo.record.sample_rate = spec->rate;
326   ainfo.record.precision = spec->width;
327   ainfo.record.channels = spec->channels;
328   ainfo.record.encoding = AUDIO_ENCODING_LINEAR;
329   ainfo.record.buffer_size = spec->buffer_time;
330
331   mixer = sunaudiosrc->mixer;
332
333   if (ioctl (mixer->mixer_fd, AUDIO_GETINFO, &audioinfo) < 0) {
334     g_warning ("Error getting audio device volume");
335   }
336   ainfo.record.port = audioinfo.record.port;
337   ainfo.record.gain = audioinfo.record.gain;
338   ainfo.record.balance = audioinfo.record.balance;
339
340   spec->segsize = 128;
341   spec->segtotal = spec->buffer_time / 128;
342
343   spec->silence_sample[0] = 0;
344   spec->silence_sample[1] = 0;
345   spec->silence_sample[2] = 0;
346   spec->silence_sample[3] = 0;
347
348   ret = ioctl (sunaudiosrc->fd, AUDIO_SETINFO, &ainfo);
349   if (ret == -1) {
350     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
351             strerror (errno)));
352     return FALSE;
353   }
354
355
356   ioctl (sunaudiosrc->fd, I_FLUSH, FLUSHR);
357
358   return TRUE;
359 }
360
361 static gboolean
362 gst_sunaudiosrc_unprepare (GstAudioSrc * asrc)
363 {
364   return TRUE;
365 }
366
367 static guint
368 gst_sunaudiosrc_read (GstAudioSrc * asrc, gpointer data, guint length)
369 {
370   return read (GST_SUNAUDIO_SRC (asrc)->fd, data, length);
371 }
372
373 static guint
374 gst_sunaudiosrc_delay (GstAudioSrc * asrc)
375 {
376   return 0;
377 }
378
379 static void
380 gst_sunaudiosrc_reset (GstAudioSrc * asrc)
381 {
382   /* Get current values */
383   GstSunAudioSrc *sunaudiosrc = GST_SUNAUDIO_SRC (asrc);
384   audio_info_t ainfo;
385   int ret;
386
387   ret = ioctl (sunaudiosrc->fd, AUDIO_GETINFO, &ainfo);
388   if (ret == -1) {
389     /*
390      * Should never happen, but if we couldn't getinfo, then no point
391      * trying to setinfo
392      */
393     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
394             strerror (errno)));
395     return;
396   }
397
398   /*
399    * Pause the audio - so audio stops playing immediately rather than
400    * waiting for the ringbuffer to empty.
401    */
402   ainfo.record.pause = !NULL;
403   ret = ioctl (sunaudiosrc->fd, AUDIO_SETINFO, &ainfo);
404   if (ret == -1) {
405     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
406             strerror (errno)));
407   }
408
409   /* Flush the audio */
410   ret = ioctl (sunaudiosrc->fd, I_FLUSH, FLUSHR);
411   if (ret == -1) {
412     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
413             strerror (errno)));
414   }
415
416   /* unpause the audio */
417   ainfo.record.pause = NULL;
418   ret = ioctl (sunaudiosrc->fd, AUDIO_SETINFO, &ainfo);
419   if (ret == -1) {
420     GST_ELEMENT_ERROR (sunaudiosrc, RESOURCE, SETTINGS, (NULL), ("%s",
421             strerror (errno)));
422   }
423 }