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