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