Remove unused variables in _class_init
[platform/upstream/gst-plugins-good.git] / sys / oss / gstosssrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *               2000,2005 Wim Taymans <wim@fluendo.com>
4  *
5  * gstosssrc.c: 
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /**
24  * SECTION:element-osssrc
25  *
26  * This element lets you record sound using the Open Sound System (OSS).
27  *
28  * <refsect2>
29  * <title>Example pipelines</title>
30  * |[
31  * gst-launch -v osssrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg
32  * ]| will record sound from your sound card using OSS and encode it to an
33  * Ogg/Vorbis file (this will only work if your mixer settings are right
34  * and the right inputs enabled etc.)
35  * </refsect2>
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <sys/ioctl.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <string.h>
47
48 #ifdef HAVE_OSS_INCLUDE_IN_SYS
49 # include <sys/soundcard.h>
50 #else
51 # ifdef HAVE_OSS_INCLUDE_IN_ROOT
52 #  include <soundcard.h>
53 # else
54 #  ifdef HAVE_OSS_INCLUDE_IN_MACHINE
55 #   include <machine/soundcard.h>
56 #  else
57 #   error "What to include?"
58 #  endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
59 # endif /* HAVE_OSS_INCLUDE_IN_ROOT */
60 #endif /* HAVE_OSS_INCLUDE_IN_SYS */
61
62 #include "gstosssrc.h"
63 #include "common.h"
64
65 #include <gst/gst-i18n-plugin.h>
66
67 GST_DEBUG_CATEGORY_EXTERN (oss_debug);
68 #define GST_CAT_DEFAULT oss_debug
69
70 static const GstElementDetails gst_oss_src_details =
71 GST_ELEMENT_DETAILS ("Audio Source (OSS)",
72     "Source/Audio",
73     "Capture from a sound card via OSS",
74     "Erik Walthinsen <omega@cse.ogi.edu>, " "Wim Taymans <wim@fluendo.com>");
75
76 #define DEFAULT_DEVICE          "/dev/dsp"
77 #define DEFAULT_DEVICE_NAME     ""
78
79 enum
80 {
81   PROP_0,
82   PROP_DEVICE,
83   PROP_DEVICE_NAME,
84 };
85
86 GST_BOILERPLATE_WITH_INTERFACE (GstOssSrc, gst_oss_src, GstAudioSrc,
87     GST_TYPE_AUDIO_SRC, GstMixer, GST_TYPE_MIXER, gst_oss_src_mixer);
88
89 GST_IMPLEMENT_OSS_MIXER_METHODS (GstOssSrc, gst_oss_src_mixer);
90
91 static void gst_oss_src_get_property (GObject * object, guint prop_id,
92     GValue * value, GParamSpec * pspec);
93 static void gst_oss_src_set_property (GObject * object, guint prop_id,
94     const GValue * value, GParamSpec * pspec);
95
96 static void gst_oss_src_dispose (GObject * object);
97 static void gst_oss_src_finalize (GstOssSrc * osssrc);
98
99 static GstCaps *gst_oss_src_getcaps (GstBaseSrc * bsrc);
100
101 static gboolean gst_oss_src_open (GstAudioSrc * asrc);
102 static gboolean gst_oss_src_close (GstAudioSrc * asrc);
103 static gboolean gst_oss_src_prepare (GstAudioSrc * asrc,
104     GstRingBufferSpec * spec);
105 static gboolean gst_oss_src_unprepare (GstAudioSrc * asrc);
106 static guint gst_oss_src_read (GstAudioSrc * asrc, gpointer data, guint length);
107 static guint gst_oss_src_delay (GstAudioSrc * asrc);
108 static void gst_oss_src_reset (GstAudioSrc * asrc);
109
110
111
112 static GstStaticPadTemplate osssrc_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
113     GST_PAD_SRC,
114     GST_PAD_ALWAYS,
115     GST_STATIC_CAPS ("audio/x-raw-int, "
116         "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, "
117         "signed = (boolean) { TRUE, FALSE }, "
118         "width = (int) 16, "
119         "depth = (int) 16, "
120         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
121         "audio/x-raw-int, "
122         "signed = (boolean) { TRUE, FALSE }, "
123         "width = (int) 8, "
124         "depth = (int) 8, "
125         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
126     );
127
128
129 static void
130 gst_oss_src_dispose (GObject * object)
131 {
132   G_OBJECT_CLASS (parent_class)->dispose (object);
133 }
134
135 static void
136 gst_oss_src_base_init (gpointer g_class)
137 {
138   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
139
140   gst_element_class_set_details (element_class, &gst_oss_src_details);
141
142   gst_element_class_add_pad_template (element_class,
143       gst_static_pad_template_get (&osssrc_src_factory));
144 }
145
146 static void
147 gst_oss_src_class_init (GstOssSrcClass * klass)
148 {
149   GObjectClass *gobject_class;
150   GstBaseSrcClass *gstbasesrc_class;
151   GstAudioSrcClass *gstaudiosrc_class;
152
153   gobject_class = (GObjectClass *) klass;
154   gstbasesrc_class = (GstBaseSrcClass *) klass;
155   gstaudiosrc_class = (GstAudioSrcClass *) klass;
156
157   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_oss_src_dispose);
158   gobject_class->finalize =
159       (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_oss_src_finalize);
160   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_oss_src_get_property);
161   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_oss_src_set_property);
162
163   gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss_src_getcaps);
164
165   gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_oss_src_open);
166   gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_oss_src_prepare);
167   gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss_src_unprepare);
168   gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_oss_src_close);
169   gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_oss_src_read);
170   gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_oss_src_delay);
171   gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_oss_src_reset);
172
173   g_object_class_install_property (gobject_class, PROP_DEVICE,
174       g_param_spec_string ("device", "Device",
175           "OSS device (usually /dev/dspN)", DEFAULT_DEVICE, G_PARAM_READWRITE));
176
177   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
178       g_param_spec_string ("device-name", "Device name",
179           "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
180           G_PARAM_READABLE));
181 }
182
183 static void
184 gst_oss_src_set_property (GObject * object, guint prop_id,
185     const GValue * value, GParamSpec * pspec)
186 {
187   GstOssSrc *src;
188
189   src = GST_OSS_SRC (object);
190
191   switch (prop_id) {
192     case PROP_DEVICE:
193       if (src->device)
194         g_free (src->device);
195       src->device = g_value_dup_string (value);
196       break;
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199       break;
200   }
201 }
202
203 static void
204 gst_oss_src_get_property (GObject * object, guint prop_id,
205     GValue * value, GParamSpec * pspec)
206 {
207   GstOssSrc *src;
208
209   src = GST_OSS_SRC (object);
210
211   switch (prop_id) {
212     case PROP_DEVICE:
213       g_value_set_string (value, src->device);
214       break;
215     case PROP_DEVICE_NAME:
216       g_value_set_string (value, src->device_name);
217       break;
218     default:
219       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
220       break;
221   }
222 }
223
224 static void
225 gst_oss_src_init (GstOssSrc * osssrc, GstOssSrcClass * g_class)
226 {
227   const gchar *device;
228
229   GST_DEBUG ("initializing osssrc");
230
231   device = g_getenv ("AUDIODEV");
232   if (device == NULL)
233     device = DEFAULT_DEVICE;
234
235   osssrc->fd = -1;
236   osssrc->device = g_strdup (device);
237   osssrc->device_name = g_strdup (DEFAULT_DEVICE_NAME);
238   osssrc->probed_caps = NULL;
239 }
240
241 static void
242 gst_oss_src_finalize (GstOssSrc * osssrc)
243 {
244   g_free (osssrc->device);
245   g_free (osssrc->device_name);
246
247   G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (osssrc));
248 }
249
250 static GstCaps *
251 gst_oss_src_getcaps (GstBaseSrc * bsrc)
252 {
253   GstOssSrc *osssrc;
254   GstCaps *caps;
255
256   osssrc = GST_OSS_SRC (bsrc);
257
258   if (osssrc->fd == -1) {
259     GST_DEBUG_OBJECT (osssrc, "device not open, using template caps");
260     return NULL;                /* base class will get template caps for us */
261   }
262
263   if (osssrc->probed_caps) {
264     GST_LOG_OBJECT (osssrc, "Returning cached caps");
265     return gst_caps_ref (osssrc->probed_caps);
266   }
267
268   caps = gst_oss_helper_probe_caps (osssrc->fd);
269
270   if (caps) {
271     osssrc->probed_caps = gst_caps_ref (caps);
272   }
273
274   GST_INFO_OBJECT (osssrc, "returning caps %" GST_PTR_FORMAT, caps);
275
276   return caps;
277 }
278
279 static gint
280 ilog2 (gint x)
281 {
282   /* well... hacker's delight explains... */
283   x = x | (x >> 1);
284   x = x | (x >> 2);
285   x = x | (x >> 4);
286   x = x | (x >> 8);
287   x = x | (x >> 16);
288   x = x - ((x >> 1) & 0x55555555);
289   x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
290   x = (x + (x >> 4)) & 0x0f0f0f0f;
291   x = x + (x >> 8);
292   x = x + (x >> 16);
293   return (x & 0x0000003f) - 1;
294 }
295
296 static gint
297 gst_oss_src_get_format (GstBufferFormat fmt)
298 {
299   gint result;
300
301   switch (fmt) {
302     case GST_MU_LAW:
303       result = AFMT_MU_LAW;
304       break;
305     case GST_A_LAW:
306       result = AFMT_A_LAW;
307       break;
308     case GST_IMA_ADPCM:
309       result = AFMT_IMA_ADPCM;
310       break;
311     case GST_U8:
312       result = AFMT_U8;
313       break;
314     case GST_S16_LE:
315       result = AFMT_S16_LE;
316       break;
317     case GST_S16_BE:
318       result = AFMT_S16_BE;
319       break;
320     case GST_S8:
321       result = AFMT_S8;
322       break;
323     case GST_U16_LE:
324       result = AFMT_U16_LE;
325       break;
326     case GST_U16_BE:
327       result = AFMT_U16_BE;
328       break;
329     case GST_MPEG:
330       result = AFMT_MPEG;
331       break;
332     default:
333       result = 0;
334       break;
335   }
336   return result;
337 }
338
339 static gboolean
340 gst_oss_src_open (GstAudioSrc * asrc)
341 {
342   GstOssSrc *oss;
343   int mode;
344
345   oss = GST_OSS_SRC (asrc);
346
347   mode = O_RDONLY;
348   mode |= O_NONBLOCK;
349
350   oss->fd = open (oss->device, mode, 0);
351   if (oss->fd == -1) {
352     switch (errno) {
353       case EACCES:
354         goto no_permission;
355       default:
356         goto open_failed;
357     }
358   }
359
360   if (!oss->mixer) {
361     oss->mixer = gst_ossmixer_new ("/dev/mixer", GST_OSS_MIXER_CAPTURE);
362
363     if (oss->mixer) {
364       g_free (oss->device_name);
365       oss->device_name = g_strdup (oss->mixer->cardname);
366     }
367   }
368   return TRUE;
369
370 no_permission:
371   {
372     GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
373         (_("Could not open audio device for recording. "
374                 "You don't have permission to open the device.")),
375         GST_ERROR_SYSTEM);
376     return FALSE;
377   }
378 open_failed:
379   {
380     GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
381         (_("Could not open audio device for recording.")),
382         ("Unable to open device %s for recording: %s",
383             oss->device, g_strerror (errno)));
384     return FALSE;
385   }
386 }
387
388 static gboolean
389 gst_oss_src_close (GstAudioSrc * asrc)
390 {
391   GstOssSrc *oss;
392
393   oss = GST_OSS_SRC (asrc);
394
395   close (oss->fd);
396
397   if (oss->mixer) {
398     gst_ossmixer_free (oss->mixer);
399     oss->mixer = NULL;
400   }
401
402   gst_caps_replace (&oss->probed_caps, NULL);
403
404   return TRUE;
405 }
406
407 static gboolean
408 gst_oss_src_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
409 {
410   GstOssSrc *oss;
411   struct audio_buf_info info;
412   int mode;
413   int fmt, tmp;
414
415   oss = GST_OSS_SRC (asrc);
416
417   mode = fcntl (oss->fd, F_GETFL);
418   mode &= ~O_NONBLOCK;
419   if (fcntl (oss->fd, F_SETFL, mode) == -1)
420     goto non_block;
421
422   fmt = gst_oss_src_get_format (spec->format);
423   if (fmt == 0)
424     goto wrong_format;
425
426   tmp = ilog2 (spec->segsize);
427   tmp = ((spec->segtotal & 0x7fff) << 16) | tmp;
428   GST_DEBUG_OBJECT (oss, "set segsize: %d, segtotal: %d, value: %08x",
429       spec->segsize, spec->segtotal, tmp);
430
431   SET_PARAM (oss, SNDCTL_DSP_SETFRAGMENT, tmp, "SETFRAGMENT");
432
433   SET_PARAM (oss, SNDCTL_DSP_RESET, 0, "RESET");
434
435   SET_PARAM (oss, SNDCTL_DSP_SETFMT, fmt, "SETFMT");
436   if (spec->channels == 2)
437     SET_PARAM (oss, SNDCTL_DSP_STEREO, 1, "STEREO");
438   SET_PARAM (oss, SNDCTL_DSP_CHANNELS, spec->channels, "CHANNELS");
439   SET_PARAM (oss, SNDCTL_DSP_SPEED, spec->rate, "SPEED");
440
441   GET_PARAM (oss, SNDCTL_DSP_GETISPACE, &info, "GETISPACE");
442
443   spec->segsize = info.fragsize;
444   spec->segtotal = info.fragstotal;
445
446   if (spec->width != 16 && spec->width != 8)
447     goto dodgy_width;
448
449   spec->bytes_per_sample = (spec->width / 8) * spec->channels;
450   oss->bytes_per_sample = (spec->width / 8) * spec->channels;
451   memset (spec->silence_sample, 0, spec->bytes_per_sample);
452
453   GST_DEBUG_OBJECT (oss, "got segsize: %d, segtotal: %d, value: %08x",
454       spec->segsize, spec->segtotal, tmp);
455
456   return TRUE;
457
458 non_block:
459   {
460     GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
461         ("Unable to set device %s in non blocking mode: %s",
462             oss->device, g_strerror (errno)), (NULL));
463     return FALSE;
464   }
465 wrong_format:
466   {
467     GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
468         ("Unable to get format %d", spec->format), (NULL));
469     return FALSE;
470   }
471 dodgy_width:
472   {
473     GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
474         ("Unexpected width %d", spec->width), (NULL));
475     return FALSE;
476   }
477 }
478
479 static gboolean
480 gst_oss_src_unprepare (GstAudioSrc * asrc)
481 {
482   /* could do a SNDCTL_DSP_RESET, but the OSS manual recommends a close/open */
483
484   if (!gst_oss_src_close (asrc))
485     goto couldnt_close;
486
487   if (!gst_oss_src_open (asrc))
488     goto couldnt_reopen;
489
490   return TRUE;
491
492 couldnt_close:
493   {
494     GST_DEBUG_OBJECT (asrc, "Could not close the audio device");
495     return FALSE;
496   }
497 couldnt_reopen:
498   {
499     GST_DEBUG_OBJECT (asrc, "Could not reopen the audio device");
500     return FALSE;
501   }
502 }
503
504 static guint
505 gst_oss_src_read (GstAudioSrc * asrc, gpointer data, guint length)
506 {
507   return read (GST_OSS_SRC (asrc)->fd, data, length);
508 }
509
510 static guint
511 gst_oss_src_delay (GstAudioSrc * asrc)
512 {
513   GstOssSrc *oss;
514   gint delay = 0;
515   gint ret;
516
517   oss = GST_OSS_SRC (asrc);
518
519 #ifdef SNDCTL_DSP_GETODELAY
520   ret = ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay);
521 #else
522   ret = -1;
523 #endif
524   if (ret < 0) {
525     audio_buf_info info;
526
527     ret = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &info);
528
529     delay = (ret < 0 ? 0 : (info.fragstotal * info.fragsize) - info.bytes);
530   }
531   return delay / oss->bytes_per_sample;
532 }
533
534 static void
535 gst_oss_src_reset (GstAudioSrc * asrc)
536 {
537   /* There's nothing we can do here really: OSS can't handle access to the
538    * same device/fd from multiple threads and might deadlock or blow up in
539    * other ways if we try an ioctl SNDCTL_DSP_RESET or similar */
540 }