filter newlines out of GST_DEBUG statements to reflect new core behavior fixes to...
[platform/upstream/gstreamer.git] / sys / oss / gstosssrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
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 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <sys/soundcard.h>
27 #include <sys/ioctl.h>
28 #include <unistd.h>
29
30 #include <gstosssrc.h>
31
32 static GstElementDetails gst_osssrc_details = {
33   "Audio Source (OSS)",
34   "Source/Audio",
35   "Read from the sound card",
36   VERSION,
37   "Erik Walthinsen <omega@cse.ogi.edu>",
38   "(C) 1999",
39 };
40
41
42 /* OssSrc signals and args */
43 enum {
44   /* FILL ME */
45   LAST_SIGNAL
46 };
47
48 enum {
49   ARG_0,
50   ARG_DEVICE,
51   ARG_BYTESPERREAD,
52   ARG_CUROFFSET,
53   ARG_FORMAT,
54   ARG_CHANNELS,
55   ARG_FREQUENCY
56 };
57
58 GST_PADTEMPLATE_FACTORY (osssrc_src_factory,
59   "src",
60   GST_PAD_SRC,
61   GST_PAD_ALWAYS,
62   GST_CAPS_NEW (
63     "osssrc_src",
64     "audio/raw",
65       "format",         GST_PROPS_STRING ("int"),
66       "law",            GST_PROPS_INT (0),
67       "endianness",     GST_PROPS_INT (G_BYTE_ORDER),
68       "signed",         GST_PROPS_LIST (
69                           GST_PROPS_BOOLEAN (TRUE),
70                           GST_PROPS_BOOLEAN (FALSE)
71                         ),
72       "width",          GST_PROPS_LIST (
73                           GST_PROPS_INT (8),
74                           GST_PROPS_INT (16)
75                         ),
76       "depth",          GST_PROPS_LIST (
77                           GST_PROPS_INT (8),
78                           GST_PROPS_INT (16)
79                         ),
80       "rate",           GST_PROPS_INT_RANGE (1000, 48000),
81       "channels",       GST_PROPS_INT_RANGE (1, 2)
82   )
83 )
84
85 static void                     gst_osssrc_class_init   (GstOssSrcClass *klass);
86 static void                     gst_osssrc_init         (GstOssSrc *osssrc);
87
88 static void                     gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
89 static void                     gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
90 static GstElementStateReturn    gst_osssrc_change_state (GstElement *element);
91
92 static void                     gst_osssrc_close_audio  (GstOssSrc *src);
93 static gboolean                 gst_osssrc_open_audio   (GstOssSrc *src);
94 static void                     gst_osssrc_sync_parms   (GstOssSrc *osssrc);
95
96 static GstBuffer *              gst_osssrc_get          (GstPad *pad);
97
98 static GstElementClass *parent_class = NULL;
99 /*static guint gst_osssrc_signals[LAST_SIGNAL] = { 0 }; */
100
101 GType
102 gst_osssrc_get_type (void) 
103 {
104   static GType osssrc_type = 0;
105
106   if (!osssrc_type) {
107     static const GTypeInfo osssrc_info = {
108       sizeof(GstOssSrcClass),
109       NULL,
110       NULL,
111       (GClassInitFunc)gst_osssrc_class_init,
112       NULL,
113       NULL,
114       sizeof(GstOssSrc),
115       0,
116       (GInstanceInitFunc)gst_osssrc_init,
117     };
118     osssrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSrc", &osssrc_info, 0);
119   }
120   return osssrc_type;
121 }
122
123 static void
124 gst_osssrc_class_init (GstOssSrcClass *klass) 
125 {
126   GObjectClass *gobject_class;
127   GstElementClass *gstelement_class;
128
129   gobject_class = (GObjectClass*)klass;
130   gstelement_class = (GstElementClass*)klass;
131
132   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
133
134   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BYTESPERREAD,
135     g_param_spec_ulong("bytes_per_read","bytes_per_read","bytes_per_read",
136                        0,G_MAXULONG,0,G_PARAM_READWRITE)); /* CHECKME */
137   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CUROFFSET,
138     g_param_spec_ulong("curoffset","curoffset","curoffset",
139                        0,G_MAXULONG,0,G_PARAM_READABLE)); /* CHECKME */
140   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FORMAT,
141     g_param_spec_int("format","format","format",
142                      G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
143   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNELS,
144     g_param_spec_int("channels","channels","channels",
145                      G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
146   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY,
147     g_param_spec_int("frequency","frequency","frequency",
148                      G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
149   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
150     g_param_spec_string("device","device","oss device (/dev/dspN usually)",
151                         "default",G_PARAM_READWRITE));
152   
153   gobject_class->set_property = gst_osssrc_set_property;
154   gobject_class->get_property = gst_osssrc_get_property;
155
156   gstelement_class->change_state = gst_osssrc_change_state;
157 }
158
159 static void 
160 gst_osssrc_init (GstOssSrc *osssrc) 
161 {
162   osssrc->srcpad = gst_pad_new_from_template (
163                   GST_PADTEMPLATE_GET (osssrc_src_factory), "src");
164   gst_pad_set_get_function(osssrc->srcpad,gst_osssrc_get);
165   gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad);
166
167   osssrc->device = g_strdup ("/dev/dsp");
168   osssrc->fd = -1;
169
170   /* adding some default values */
171   osssrc->format = AFMT_S16_LE;
172   osssrc->channels = 2;
173   osssrc->frequency = 44100;
174   
175   osssrc->bytes_per_read = 4096;
176   osssrc->curoffset = 0;
177   osssrc->basetime = 0;
178   osssrc->samples_since_basetime = 0;
179 }
180
181 static GstBuffer *
182 gst_osssrc_get (GstPad *pad)
183 {
184   GstOssSrc *src;
185   GstBuffer *buf;
186   glong readbytes;
187   glong readsamples;
188
189   g_return_val_if_fail (pad != NULL, NULL);
190   src = GST_OSSSRC(gst_pad_get_parent (pad));
191
192   GST_DEBUG (GST_CAT_PLUGIN_INFO, "attempting to read something from soundcard");
193
194   buf = gst_buffer_new ();
195   g_return_val_if_fail (buf, NULL);
196   
197   GST_BUFFER_DATA (buf) = (gpointer)g_malloc (src->bytes_per_read);
198
199   readbytes = read (src->fd,GST_BUFFER_DATA (buf),
200                     src->bytes_per_read);
201
202   if (readbytes == 0) {
203     gst_element_set_eos (GST_ELEMENT (src));
204     return NULL;
205   }
206   if (!GST_PAD_CAPS (pad)) {
207     /* set caps on src pad */
208     if (!gst_pad_try_set_caps (src->srcpad, 
209                     GST_CAPS_NEW (
210                       "oss_src",
211                       "audio/raw",
212                         "format",       GST_PROPS_STRING ("int"),
213                           "law",        GST_PROPS_INT (0),              /*FIXME */
214                           "endianness", GST_PROPS_INT (G_BYTE_ORDER),   /*FIXME */
215                           "signed",     GST_PROPS_BOOLEAN (TRUE),       /*FIXME */
216                           "width",      GST_PROPS_INT (src->format),
217                           "depth",      GST_PROPS_INT (src->format),
218                           "rate",       GST_PROPS_INT (src->frequency),
219                           "channels",   GST_PROPS_INT (src->channels)
220                    ))) 
221     {
222       gst_element_error (GST_ELEMENT (src), "could not set caps");
223       return NULL;
224     }
225   }
226
227   GST_BUFFER_SIZE (buf) = readbytes;
228   GST_BUFFER_OFFSET (buf) = src->curoffset;
229   GST_BUFFER_TIMESTAMP (buf) = src->basetime +
230           src->samples_since_basetime * 1000000LL / src->frequency;
231
232   src->curoffset += readbytes;
233   readsamples = readbytes / src->channels;
234   if (src->format == 16) readsamples /= 2;
235   src->samples_since_basetime += readsamples;
236
237   GST_DEBUG (GST_CAT_PLUGIN_INFO, "pushed buffer from soundcard of %ld bytes, timestamp %lld", readbytes, GST_BUFFER_TIMESTAMP (buf));
238   return buf;
239 }
240
241 static void 
242 gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) 
243 {
244   GstOssSrc *src;
245
246   /* it's not null if we got it, but it might not be ours */
247   g_return_if_fail (GST_IS_OSSSRC (object));
248   
249   src = GST_OSSSRC (object);
250
251   switch (prop_id) {
252     case ARG_BYTESPERREAD:
253       src->bytes_per_read = g_value_get_ulong (value);
254       break;
255     case ARG_FORMAT:
256       src->format = g_value_get_int (value);
257       break;
258     case ARG_CHANNELS:
259       src->channels = g_value_get_int (value);
260       break;
261     case ARG_FREQUENCY:
262       /* Preserve the timestamps */
263       src->basetime = src->samples_since_basetime * 1000000LL / src->frequency;
264       src->samples_since_basetime = 0;
265
266       src->frequency = g_value_get_int (value);
267       break;
268     case ARG_CUROFFSET:
269       src->curoffset = g_value_get_int (value);
270       break;
271     case ARG_DEVICE:
272       g_free(src->device);
273       src->device = g_strdup (g_value_get_string (value));
274       break;
275     default:
276       break;
277   }
278 }
279
280 static void 
281 gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) 
282 {
283   GstOssSrc *src;
284
285   /* it's not null if we got it, but it might not be ours */
286   g_return_if_fail (GST_IS_OSSSRC (object));
287   
288   src = GST_OSSSRC (object);
289
290   switch (prop_id) {
291     case ARG_BYTESPERREAD:
292       g_value_set_ulong (value, src->bytes_per_read);
293       break;
294     case ARG_FORMAT:
295       g_value_set_int (value, src->format);
296       break;
297     case ARG_CHANNELS:
298       g_value_set_int (value, src->channels);
299       break;
300     case ARG_FREQUENCY:
301       g_value_set_int (value, src->frequency);
302       break;
303     case ARG_CUROFFSET:
304       g_value_set_ulong (value, src->curoffset);
305       break;
306     case ARG_DEVICE:
307       g_value_set_string (value, src->device);
308       break;
309     default:
310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311       break;
312   }
313 }
314
315 static GstElementStateReturn 
316 gst_osssrc_change_state (GstElement *element) 
317 {
318   /* GstOssSrc *src = GST_OSSSRC (element); */
319   
320   g_return_val_if_fail (GST_IS_OSSSRC (element), FALSE);
321   GST_DEBUG (GST_CAT_PLUGIN_INFO, "osssrc: state change");
322   /* if going down into NULL state, close the file if it's open */
323   if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
324     if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN))
325       gst_osssrc_close_audio (GST_OSSSRC (element));
326   /* otherwise (READY or higher) we need to open the sound card */
327   } else {
328     GST_DEBUG (GST_CAT_PLUGIN_INFO, "DEBUG: osssrc: ready or higher");
329
330     if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) { 
331       if (!gst_osssrc_open_audio (GST_OSSSRC (element)))
332         return GST_STATE_FAILURE;
333       else
334       {
335         GST_DEBUG (GST_CAT_PLUGIN_INFO, "osssrc: device opened successfully");
336         /* thomas: we can't set caps here because the element is
337          * not actually ready yet */
338       }
339     }
340   }
341
342   if (GST_ELEMENT_CLASS (parent_class)->change_state)
343     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
344   
345   return GST_STATE_SUCCESS;
346 }
347
348 static gboolean 
349 gst_osssrc_open_audio (GstOssSrc *src) 
350 {
351   g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN), FALSE);
352
353   /* first try to open the sound card */
354   src->fd = open(src->device, O_RDONLY);
355
356   /* if we have it, set the default parameters and go have fun */ 
357   if (src->fd > 0) {
358
359     /* set card state */
360     gst_osssrc_sync_parms (src);
361     GST_DEBUG (GST_CAT_PLUGIN_INFO,"opened audio: %s",src->device);
362     
363     GST_FLAG_SET (src, GST_OSSSRC_OPEN);
364     return TRUE;
365   }
366
367   return FALSE;
368 }
369
370 static void 
371 gst_osssrc_close_audio (GstOssSrc *src) 
372 {
373   g_return_if_fail (GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN));
374
375   close(src->fd);
376   src->fd = -1;
377
378   GST_FLAG_UNSET (src, GST_OSSSRC_OPEN);
379 }
380
381 static void 
382 gst_osssrc_sync_parms (GstOssSrc *osssrc) 
383 {
384   audio_buf_info ispace;
385   gint frag;
386   /* remember : ioctl on samplerate returns the sample rate the card
387    * is actually set to ! Setting it to 44101 KHz could cause it to
388    * be set to 44101, for example
389    */
390
391   guint frequency;
392
393   g_return_if_fail (osssrc != NULL);
394   g_return_if_fail (GST_IS_OSSSRC (osssrc));
395   g_return_if_fail (osssrc->fd > 0);
396  
397   frequency = osssrc->frequency;
398
399   frag = 0x7fff0006;
400
401   ioctl(osssrc->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
402   ioctl(osssrc->fd, SNDCTL_DSP_RESET, 0);
403  
404   ioctl(osssrc->fd, SNDCTL_DSP_SETFMT, &osssrc->format);
405   ioctl(osssrc->fd, SNDCTL_DSP_CHANNELS, &osssrc->channels);
406   ioctl(osssrc->fd, SNDCTL_DSP_SPEED, &osssrc->frequency);
407   osssrc->frequency = frequency;
408   ioctl(osssrc->fd, SNDCTL_DSP_SPEED, &frequency);
409   ioctl(osssrc->fd, SNDCTL_DSP_GETISPACE, &ispace);
410   ioctl(osssrc->fd, SNDCTL_DSP_GETBLKSIZE, &frag);
411  
412   g_print("setting sound card to %dKHz %d bit %s (%d bytes buffer, %d fragment)\n",
413           osssrc->frequency, osssrc->format,
414           (osssrc->channels == 2) ? "stereo" : "mono", ispace.bytes, frag);
415
416 }
417
418 gboolean
419 gst_osssrc_factory_init (GstPlugin *plugin)
420 {
421   GstElementFactory *factory;
422
423   factory = gst_elementfactory_new ("osssrc", GST_TYPE_OSSSRC, &gst_osssrc_details);
424   g_return_val_if_fail (factory != NULL, FALSE);
425
426   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (osssrc_src_factory));
427
428   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
429
430   return TRUE;
431 }
432