4b994a0700fce2adb1ec26c93deb071ba4188e7f
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / sys / oss4 / oss4-source.c
1 /* GStreamer OSS4 audio source
2  * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * SECTION:element-oss4src
22  * @title: oss4src
23  *
24  * This element lets you record sound using the Open Sound System (OSS)
25  * version 4.
26  *
27  * ## Example pipelines
28  * |[
29  * gst-launch-1.0 -v oss4src ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=mymusic.ogg
30  * ]| will record sound from your sound card using OSS4 and encode it to an
31  * Ogg/Vorbis file (this will only work if your mixer settings are right
32  * and the right inputs areenabled etc.)
33  *
34  */
35
36 /* FIXME: make sure we're not doing ioctls from the app thread (e.g. via the
37  * mixer interface) while recording */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/ioctl.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <string.h>
50
51 #include <gst/gst-i18n-plugin.h>
52
53 #define NO_LEGACY_MIXER
54 #include "oss4-audio.h"
55 #include "oss4-source.h"
56 #include "oss4-property-probe.h"
57 #include "oss4-soundcard.h"
58
59 #define GST_OSS4_SOURCE_IS_OPEN(src)  (GST_OSS4_SOURCE(src)->fd != -1)
60
61 GST_DEBUG_CATEGORY_EXTERN (oss4src_debug);
62 #define GST_CAT_DEFAULT oss4src_debug
63
64 #define DEFAULT_DEVICE       NULL
65 #define DEFAULT_DEVICE_NAME  NULL
66
67 enum
68 {
69   PROP_0,
70   PROP_DEVICE,
71   PROP_DEVICE_NAME
72 };
73
74 #define gst_oss4_source_parent_class parent_class
75 G_DEFINE_TYPE (GstOss4Source, gst_oss4_source, GST_TYPE_AUDIO_SRC);
76 GST_ELEMENT_REGISTER_DEFINE (oss4src, "oss4src", GST_RANK_SECONDARY + 1,
77     GST_TYPE_OSS4_SOURCE);
78
79 static void gst_oss4_source_get_property (GObject * object, guint prop_id,
80     GValue * value, GParamSpec * pspec);
81 static void gst_oss4_source_set_property (GObject * object, guint prop_id,
82     const GValue * value, GParamSpec * pspec);
83
84 static void gst_oss4_source_dispose (GObject * object);
85 static void gst_oss4_source_finalize (GstOss4Source * osssrc);
86
87 static GstCaps *gst_oss4_source_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
88
89 static gboolean gst_oss4_source_open (GstAudioSrc * asrc,
90     gboolean silent_errors);
91 static gboolean gst_oss4_source_open_func (GstAudioSrc * asrc);
92 static gboolean gst_oss4_source_close (GstAudioSrc * asrc);
93 static gboolean gst_oss4_source_prepare (GstAudioSrc * asrc,
94     GstAudioRingBufferSpec * spec);
95 static gboolean gst_oss4_source_unprepare (GstAudioSrc * asrc);
96 static guint gst_oss4_source_read (GstAudioSrc * asrc, gpointer data,
97     guint length, GstClockTime * timestamp);
98 static guint gst_oss4_source_delay (GstAudioSrc * asrc);
99 static void gst_oss4_source_reset (GstAudioSrc * asrc);
100
101 static void
102 gst_oss4_source_class_init (GstOss4SourceClass * klass)
103 {
104   GObjectClass *gobject_class;
105   GstElementClass *gstelement_class;
106   GstBaseSrcClass *gstbasesrc_class;
107   GstAudioSrcClass *gstaudiosrc_class;
108   GstPadTemplate *templ;
109
110   gobject_class = (GObjectClass *) klass;
111   gstelement_class = (GstElementClass *) klass;
112   gstbasesrc_class = (GstBaseSrcClass *) klass;
113   gstaudiosrc_class = (GstAudioSrcClass *) klass;
114
115   gobject_class->dispose = gst_oss4_source_dispose;
116   gobject_class->finalize = (GObjectFinalizeFunc) gst_oss4_source_finalize;
117   gobject_class->get_property = gst_oss4_source_get_property;
118   gobject_class->set_property = gst_oss4_source_set_property;
119
120   gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss4_source_getcaps);
121
122   gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_oss4_source_open_func);
123   gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_oss4_source_prepare);
124   gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss4_source_unprepare);
125   gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_oss4_source_close);
126   gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_oss4_source_read);
127   gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_oss4_source_delay);
128   gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_oss4_source_reset);
129
130   g_object_class_install_property (gobject_class, PROP_DEVICE,
131       g_param_spec_string ("device", "Device",
132           "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) "
133           "(NULL = use first available device)",
134           DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
135
136   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
137       g_param_spec_string ("device-name", "Device name",
138           "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
139           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
140
141   gst_element_class_set_static_metadata (gstelement_class,
142       "OSS v4 Audio Source", "Source/Audio",
143       "Capture from a sound card via OSS version 4",
144       "Tim-Philipp Müller <tim centricular net>");
145
146   templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
147       gst_oss4_audio_get_template_caps ());
148   gst_element_class_add_pad_template (gstelement_class, templ);
149 }
150
151 static void
152 gst_oss4_source_init (GstOss4Source * osssrc)
153 {
154   const gchar *device;
155
156   device = g_getenv ("AUDIODEV");
157   if (device == NULL)
158     device = DEFAULT_DEVICE;
159
160   osssrc->fd = -1;
161   osssrc->device = g_strdup (device);
162   osssrc->device_name = g_strdup (DEFAULT_DEVICE_NAME);
163   osssrc->device_name = NULL;
164 }
165
166 static void
167 gst_oss4_source_finalize (GstOss4Source * oss)
168 {
169   g_free (oss->device);
170   oss->device = NULL;
171
172   G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (oss));
173 }
174
175 static void
176 gst_oss4_source_dispose (GObject * object)
177 {
178   GstOss4Source *oss = GST_OSS4_SOURCE (object);
179
180   if (oss->probed_caps) {
181     gst_caps_unref (oss->probed_caps);
182     oss->probed_caps = NULL;
183   }
184
185   G_OBJECT_CLASS (parent_class)->dispose (object);
186 }
187
188 static void
189 gst_oss4_source_set_property (GObject * object, guint prop_id,
190     const GValue * value, GParamSpec * pspec)
191 {
192   GstOss4Source *oss;
193
194   oss = GST_OSS4_SOURCE (object);
195
196   switch (prop_id) {
197     case PROP_DEVICE:
198       GST_OBJECT_LOCK (oss);
199       if (oss->fd == -1) {
200         g_free (oss->device);
201         oss->device = g_value_dup_string (value);
202         g_free (oss->device_name);
203         oss->device_name = NULL;
204       } else {
205         g_warning ("%s: can't change \"device\" property while audio source "
206             "is open", GST_OBJECT_NAME (oss));
207       }
208       GST_OBJECT_UNLOCK (oss);
209       break;
210     default:
211       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
212       break;
213   }
214 }
215
216 static void
217 gst_oss4_source_get_property (GObject * object, guint prop_id,
218     GValue * value, GParamSpec * pspec)
219 {
220   GstOss4Source *oss;
221
222   oss = GST_OSS4_SOURCE (object);
223
224   switch (prop_id) {
225     case PROP_DEVICE:
226       GST_OBJECT_LOCK (oss);
227       g_value_set_string (value, oss->device);
228       GST_OBJECT_UNLOCK (oss);
229       break;
230     case PROP_DEVICE_NAME:
231       GST_OBJECT_LOCK (oss);
232       /* If device is set, try to retrieve the name even if we're not open */
233       if (oss->fd == -1 && oss->device != NULL) {
234         if (gst_oss4_source_open (GST_AUDIO_SRC (oss), TRUE)) {
235           g_value_set_string (value, oss->device_name);
236           gst_oss4_source_close (GST_AUDIO_SRC (oss));
237         } else {
238           gchar *name = NULL;
239
240           gst_oss4_property_probe_find_device_name_nofd (GST_OBJECT (oss),
241               oss->device, &name);
242           g_value_set_string (value, name);
243           g_free (name);
244         }
245       } else {
246         g_value_set_string (value, oss->device_name);
247       }
248
249       GST_OBJECT_UNLOCK (oss);
250       break;
251     default:
252       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
253       break;
254   }
255 }
256
257 static GstCaps *
258 gst_oss4_source_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
259 {
260   GstOss4Source *oss;
261   GstCaps *caps;
262
263   oss = GST_OSS4_SOURCE (bsrc);
264
265   if (oss->fd == -1) {
266     caps = gst_oss4_audio_get_template_caps ();
267   } else if (oss->probed_caps) {
268     caps = gst_caps_copy (oss->probed_caps);
269   } else {
270     caps = gst_oss4_audio_probe_caps (GST_OBJECT (oss), oss->fd);
271     if (caps != NULL && !gst_caps_is_empty (caps)) {
272       oss->probed_caps = gst_caps_copy (caps);
273     }
274   }
275
276   if (filter && caps) {
277     GstCaps *intersection;
278
279     intersection =
280         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
281     gst_caps_unref (caps);
282     return intersection;
283   } else {
284     return caps;
285   }
286 }
287
288 /* note: we must not take the object lock here unless we fix up get_property */
289 static gboolean
290 gst_oss4_source_open (GstAudioSrc * asrc, gboolean silent_errors)
291 {
292   GstOss4Source *oss;
293   gchar *device;
294   int mode;
295
296   oss = GST_OSS4_SOURCE (asrc);
297
298   if (oss->device)
299     device = g_strdup (oss->device);
300   else
301     device = gst_oss4_audio_find_device (GST_OBJECT_CAST (oss));
302
303   /* desperate times, desperate measures */
304   if (device == NULL)
305     device = g_strdup ("/dev/dsp0");
306
307   GST_INFO_OBJECT (oss, "Trying to open OSS4 device '%s'", device);
308
309   /* we open in non-blocking mode even if we don't really want to do writes
310    * non-blocking because we can't be sure that this is really a genuine
311    * OSS4 device with well-behaved drivers etc. We really don't want to
312    * hang forever under any circumstances. */
313   oss->fd = open (device, O_RDONLY | O_NONBLOCK, 0);
314   if (oss->fd == -1) {
315     switch (errno) {
316       case EBUSY:
317         goto busy;
318       case EACCES:
319         goto no_permission;
320       default:
321         goto open_failed;
322     }
323   }
324
325   GST_INFO_OBJECT (oss, "Opened device");
326
327   /* Make sure it's OSS4. If it's old OSS, let osssink handle it */
328   if (!gst_oss4_audio_check_version (GST_OBJECT_CAST (oss), oss->fd))
329     goto legacy_oss;
330
331   /* now remove the non-blocking flag. */
332   mode = fcntl (oss->fd, F_GETFL);
333   mode &= ~O_NONBLOCK;
334   if (fcntl (oss->fd, F_SETFL, mode) < 0) {
335     /* some drivers do no support unsetting the non-blocking flag, try to
336      * close/open the device then. This is racy but we error out properly. */
337     GST_WARNING_OBJECT (oss, "failed to unset O_NONBLOCK (buggy driver?), "
338         "will try to re-open device now");
339     gst_oss4_source_close (asrc);
340     if ((oss->fd = open (device, O_RDONLY, 0)) == -1)
341       goto non_block;
342   }
343
344   oss->open_device = device;
345
346   /* not using ENGINEINFO here because it sometimes returns a different and
347    * less useful name than AUDIOINFO for the same device */
348   if (!gst_oss4_property_probe_find_device_name (GST_OBJECT (oss), oss->fd,
349           oss->open_device, &oss->device_name)) {
350     oss->device_name = NULL;
351   }
352
353   return TRUE;
354
355   /* ERRORS */
356 busy:
357   {
358     if (!silent_errors) {
359       GST_ELEMENT_ERROR (oss, RESOURCE, BUSY,
360           (_("Could not open audio device for playback. "
361                   "Device is being used by another application.")), (NULL));
362     }
363     g_free (device);
364     return FALSE;
365   }
366 no_permission:
367   {
368     if (!silent_errors) {
369       GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
370           (_("Could not open audio device for playback. "
371                   "You don't have permission to open the device.")),
372           GST_ERROR_SYSTEM);
373     }
374     g_free (device);
375     return FALSE;
376   }
377 open_failed:
378   {
379     if (!silent_errors) {
380       GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
381           (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM);
382     }
383     g_free (device);
384     return FALSE;
385   }
386 legacy_oss:
387   {
388     gst_oss4_source_close (asrc);
389     if (!silent_errors) {
390       GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
391           (_("Could not open audio device for playback. "
392                   "This version of the Open Sound System is not supported by this "
393                   "element.")), ("Try the 'osssink' element instead"));
394     }
395     g_free (device);
396     return FALSE;
397   }
398 non_block:
399   {
400     if (!silent_errors) {
401       GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
402           ("Unable to set device %s into non-blocking mode: %s",
403               oss->device, g_strerror (errno)));
404     }
405     g_free (device);
406     return FALSE;
407   }
408 }
409
410 static gboolean
411 gst_oss4_source_open_func (GstAudioSrc * asrc)
412 {
413   return gst_oss4_source_open (asrc, FALSE);
414 }
415
416 static gboolean
417 gst_oss4_source_close (GstAudioSrc * asrc)
418 {
419   GstOss4Source *oss;
420
421   oss = GST_OSS4_SOURCE (asrc);
422
423   if (oss->fd != -1) {
424     GST_DEBUG_OBJECT (oss, "closing device");
425     close (oss->fd);
426     oss->fd = -1;
427   }
428
429   oss->bytes_per_sample = 0;
430
431   gst_caps_replace (&oss->probed_caps, NULL);
432
433   g_free (oss->open_device);
434   oss->open_device = NULL;
435
436   g_free (oss->device_name);
437   oss->device_name = NULL;
438
439   return TRUE;
440 }
441
442 static gboolean
443 gst_oss4_source_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
444 {
445   GstOss4Source *oss;
446
447   oss = GST_OSS4_SOURCE (asrc);
448
449   if (!gst_oss4_audio_set_format (GST_OBJECT_CAST (oss), oss->fd, spec)) {
450     GST_WARNING_OBJECT (oss, "Couldn't set requested format %" GST_PTR_FORMAT,
451         spec->caps);
452     return FALSE;
453   }
454
455   oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
456
457   return TRUE;
458 }
459
460 static gboolean
461 gst_oss4_source_unprepare (GstAudioSrc * asrc)
462 {
463   /* could do a SNDCTL_DSP_HALT, but the OSS manual recommends a close/open,
464    * since HALT won't properly reset some devices, apparently */
465
466   if (!gst_oss4_source_close (asrc))
467     goto couldnt_close;
468
469   if (!gst_oss4_source_open_func (asrc))
470     goto couldnt_reopen;
471
472   return TRUE;
473
474   /* ERRORS */
475 couldnt_close:
476   {
477     GST_DEBUG_OBJECT (asrc, "Couldn't close the audio device");
478     return FALSE;
479   }
480 couldnt_reopen:
481   {
482     GST_DEBUG_OBJECT (asrc, "Couldn't reopen the audio device");
483     return FALSE;
484   }
485 }
486
487 static guint
488 gst_oss4_source_read (GstAudioSrc * asrc, gpointer data, guint length,
489     GstClockTime * timestamp)
490 {
491   GstOss4Source *oss;
492   int n;
493
494   oss = GST_OSS4_SOURCE_CAST (asrc);
495
496   n = read (oss->fd, data, length);
497   GST_LOG_OBJECT (asrc, "%u bytes, %u samples", n, n / oss->bytes_per_sample);
498
499   if (G_UNLIKELY (n < 0)) {
500     switch (errno) {
501       case ENOTSUP:
502       case EACCES:{
503         /* This is the most likely cause, I think */
504         GST_ELEMENT_ERROR (asrc, RESOURCE, READ,
505             (_("Recording is not supported by this audio device.")),
506             ("read: %s (device: %s) (maybe this is an output-only device?)",
507                 g_strerror (errno), oss->open_device));
508         break;
509       }
510       default:{
511         GST_ELEMENT_ERROR (asrc, RESOURCE, READ,
512             (_("Error recording from audio device.")),
513             ("read: %s (device: %s)", g_strerror (errno), oss->open_device));
514         break;
515       }
516     }
517   }
518
519   return (guint) n;
520 }
521
522 static guint
523 gst_oss4_source_delay (GstAudioSrc * asrc)
524 {
525   audio_buf_info info = { 0, };
526   GstOss4Source *oss;
527   guint delay;
528
529   oss = GST_OSS4_SOURCE_CAST (asrc);
530
531   if (ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
532     GST_LOG_OBJECT (oss, "GETISPACE failed: %s", g_strerror (errno));
533     return 0;
534   }
535
536   delay = (info.fragstotal * info.fragsize) - info.bytes;
537   GST_LOG_OBJECT (oss, "fragstotal:%d, fragsize:%d, bytes:%d, delay:%d",
538       info.fragstotal, info.fragsize, info.bytes, delay);
539   return delay;
540 }
541
542 static void
543 gst_oss4_source_reset (GstAudioSrc * asrc)
544 {
545   /* There's nothing we can do here really: OSS can't handle access to the
546    * same device/fd from multiple threads and might deadlock or blow up in
547    * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */
548 }