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