1 /* GStreamer OSS4 audio sink
2 * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
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.
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.
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.
20 * SECTION:element-oss4sink
22 * This element lets you output sound using the Open Sound System (OSS)
25 * Note that you should almost always use generic audio conversion elements
26 * like audioconvert and audioresample in front of an audiosink to make sure
27 * your pipeline works under all circumstances (those conversion elements will
28 * act in passthrough-mode if no conversion is necessary).
31 * <title>Example pipelines</title>
33 * gst-launch-1.0 -v audiotestsrc ! audioconvert ! volume volume=0.1 ! oss4sink
34 * ]| will output a sine wave (continuous beep sound) to your sound card (with
35 * a very low volume as precaution).
37 * gst-launch-1.0 -v filesrc location=music.ogg ! decodebin ! audioconvert ! audioresample ! oss4sink
38 * ]| will play an Ogg/Vorbis audio file and output it using the Open Sound System
47 #include <sys/types.h>
49 #include <sys/ioctl.h>
55 #include <gst/gst-i18n-plugin.h>
56 #include <gst/audio/streamvolume.h>
58 #define NO_LEGACY_MIXER
59 #include "oss4-audio.h"
60 #include "oss4-sink.h"
61 #include "oss4-property-probe.h"
62 #include "oss4-soundcard.h"
64 GST_DEBUG_CATEGORY_EXTERN (oss4sink_debug);
65 #define GST_CAT_DEFAULT oss4sink_debug
67 static void gst_oss4_sink_dispose (GObject * object);
68 static void gst_oss4_sink_finalize (GObject * object);
70 static void gst_oss4_sink_get_property (GObject * object, guint prop_id,
71 GValue * value, GParamSpec * pspec);
72 static void gst_oss4_sink_set_property (GObject * object, guint prop_id,
73 const GValue * value, GParamSpec * pspec);
75 static GstCaps *gst_oss4_sink_getcaps (GstBaseSink * bsink, GstCaps * filter);
76 static gboolean gst_oss4_sink_open (GstAudioSink * asink,
77 gboolean silent_errors);
78 static gboolean gst_oss4_sink_open_func (GstAudioSink * asink);
79 static gboolean gst_oss4_sink_close (GstAudioSink * asink);
80 static gboolean gst_oss4_sink_prepare (GstAudioSink * asink,
81 GstAudioRingBufferSpec * spec);
82 static gboolean gst_oss4_sink_unprepare (GstAudioSink * asink);
83 static gint gst_oss4_sink_write (GstAudioSink * asink, gpointer data,
85 static guint gst_oss4_sink_delay (GstAudioSink * asink);
86 static void gst_oss4_sink_reset (GstAudioSink * asink);
88 #define DEFAULT_DEVICE NULL
89 #define DEFAULT_DEVICE_NAME NULL
90 #define DEFAULT_MUTE FALSE
91 #define DEFAULT_VOLUME 1.0
92 #define MAX_VOLUME 10.0
104 #define gst_oss4_sink_parent_class parent_class
105 G_DEFINE_TYPE_WITH_CODE (GstOss4Sink, gst_oss4_sink,
106 GST_TYPE_AUDIO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
109 gst_oss4_sink_dispose (GObject * object)
111 GstOss4Sink *osssink = GST_OSS4_SINK (object);
113 if (osssink->probed_caps) {
114 gst_caps_unref (osssink->probed_caps);
115 osssink->probed_caps = NULL;
118 G_OBJECT_CLASS (parent_class)->dispose (object);
122 gst_oss4_sink_class_init (GstOss4SinkClass * klass)
124 GstAudioSinkClass *audiosink_class = (GstAudioSinkClass *) klass;
125 GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
126 GstElementClass *gstelement_class = (GstElementClass *) klass;
127 GObjectClass *gobject_class = (GObjectClass *) klass;
128 GstPadTemplate *templ;
130 gobject_class->dispose = gst_oss4_sink_dispose;
131 gobject_class->finalize = gst_oss4_sink_finalize;
132 gobject_class->get_property = gst_oss4_sink_get_property;
133 gobject_class->set_property = gst_oss4_sink_set_property;
135 g_object_class_install_property (gobject_class, PROP_DEVICE,
136 g_param_spec_string ("device", "Device",
137 "OSS4 device (e.g. /dev/oss/hdaudio0/pcm0 or /dev/dspN) "
138 "(NULL = use first available playback device)",
139 DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
141 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
142 g_param_spec_string ("device-name", "Device name",
143 "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
144 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
146 g_object_class_install_property (gobject_class,
148 g_param_spec_double ("volume", "Volume",
149 "Linear volume of this stream, 1.0=100%", 0.0, MAX_VOLUME,
150 DEFAULT_VOLUME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152 g_object_class_install_property (gobject_class,
154 g_param_spec_boolean ("mute", "Mute",
155 "Mute state of this stream", DEFAULT_MUTE,
156 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
158 basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_oss4_sink_getcaps);
160 audiosink_class->open = GST_DEBUG_FUNCPTR (gst_oss4_sink_open_func);
161 audiosink_class->close = GST_DEBUG_FUNCPTR (gst_oss4_sink_close);
162 audiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_oss4_sink_prepare);
163 audiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_oss4_sink_unprepare);
164 audiosink_class->write = GST_DEBUG_FUNCPTR (gst_oss4_sink_write);
165 audiosink_class->delay = GST_DEBUG_FUNCPTR (gst_oss4_sink_delay);
166 audiosink_class->reset = GST_DEBUG_FUNCPTR (gst_oss4_sink_reset);
168 gst_element_class_set_static_metadata (gstelement_class,
169 "OSS v4 Audio Sink", "Sink/Audio",
170 "Output to a sound card via OSS version 4",
171 "Tim-Philipp Müller <tim centricular net>");
173 templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
174 gst_oss4_audio_get_template_caps ());
175 gst_element_class_add_pad_template (gstelement_class, templ);
179 gst_oss4_sink_init (GstOss4Sink * osssink)
183 device = g_getenv ("AUDIODEV");
185 device = DEFAULT_DEVICE;
186 osssink->device = g_strdup (device);
188 osssink->bytes_per_sample = 0;
189 osssink->probed_caps = NULL;
190 osssink->device_name = NULL;
191 osssink->mute_volume = 100 | (100 << 8);
195 gst_oss4_sink_finalize (GObject * object)
197 GstOss4Sink *osssink = GST_OSS4_SINK (object);
199 g_free (osssink->device);
200 osssink->device = NULL;
202 G_OBJECT_CLASS (parent_class)->finalize (object);
206 gst_oss4_sink_set_volume (GstOss4Sink * oss, gdouble volume)
210 volume = volume * 100.0;
211 ivol = (int) volume | ((int) volume << 8);
212 GST_OBJECT_LOCK (oss);
213 if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &ivol) < 0) {
214 GST_LOG_OBJECT (oss, "SETPLAYVOL failed");
216 GST_OBJECT_UNLOCK (oss);
220 gst_oss4_sink_get_volume (GstOss4Sink * oss)
222 int ivol, lvol, rvol;
223 gdouble dvol = DEFAULT_VOLUME;
225 GST_OBJECT_LOCK (oss);
226 if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &ivol) < 0) {
227 GST_LOG_OBJECT (oss, "GETPLAYVOL failed");
229 /* Return the higher of the two volume channels, if different */
231 rvol = (ivol >> 8) & 0xff;
232 dvol = MAX (lvol, rvol) / 100.0;
234 GST_OBJECT_UNLOCK (oss);
240 gst_oss4_sink_set_mute (GstOss4Sink * oss, gboolean mute)
246 * OSSv4 does not have a per-channel mute, so simulate by setting
247 * the value to 0. Save the volume before doing a mute so we can
248 * reset the value when the user un-mutes.
252 GST_OBJECT_LOCK (oss);
253 if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &oss->mute_volume) < 0) {
254 GST_LOG_OBJECT (oss, "GETPLAYVOL failed");
256 if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &ivol) < 0) {
257 GST_LOG_OBJECT (oss, "SETPLAYVOL failed");
259 GST_OBJECT_UNLOCK (oss);
262 * If the saved volume is 0, then reset it to 100. Otherwise the mute
263 * can get stuck. This can happen, for example, due to rounding
264 * errors in converting from the float to an integer.
266 if (oss->mute_volume == 0) {
267 oss->mute_volume = 100 | (100 << 8);
269 GST_OBJECT_LOCK (oss);
270 if (ioctl (oss->fd, SNDCTL_DSP_SETPLAYVOL, &oss->mute_volume) < 0) {
271 GST_LOG_OBJECT (oss, "SETPLAYVOL failed");
273 GST_OBJECT_UNLOCK (oss);
278 gst_oss4_sink_get_mute (GstOss4Sink * oss)
280 int ivol, lvol, rvol;
282 GST_OBJECT_LOCK (oss);
283 if (ioctl (oss->fd, SNDCTL_DSP_GETPLAYVOL, &ivol) < 0) {
284 GST_LOG_OBJECT (oss, "GETPLAYVOL failed");
288 rvol = (ivol >> 8) & 0xff;
290 GST_OBJECT_UNLOCK (oss);
292 return (lvol == 0 && rvol == 0);
296 gst_oss4_sink_set_property (GObject * object, guint prop_id,
297 const GValue * value, GParamSpec * pspec)
299 GstOss4Sink *oss = GST_OSS4_SINK (object);
303 GST_OBJECT_LOCK (oss);
305 g_free (oss->device);
306 oss->device = g_value_dup_string (value);
307 if (oss->probed_caps) {
308 gst_caps_unref (oss->probed_caps);
309 oss->probed_caps = NULL;
311 g_free (oss->device_name);
312 oss->device_name = NULL;
314 g_warning ("%s: can't change \"device\" property while audio sink "
315 "is open", GST_OBJECT_NAME (oss));
317 GST_OBJECT_UNLOCK (oss);
320 gst_oss4_sink_set_volume (oss, g_value_get_double (value));
323 gst_oss4_sink_set_mute (oss, g_value_get_boolean (value));
326 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
332 gst_oss4_sink_get_property (GObject * object, guint prop_id,
333 GValue * value, GParamSpec * pspec)
335 GstOss4Sink *oss = GST_OSS4_SINK (object);
339 GST_OBJECT_LOCK (oss);
340 g_value_set_string (value, oss->device);
341 GST_OBJECT_UNLOCK (oss);
343 case PROP_DEVICE_NAME:
344 GST_OBJECT_LOCK (oss);
345 if (oss->fd == -1 && oss->device != NULL) {
346 /* If device is set, try to retrieve the name even if we're not open */
347 if (gst_oss4_sink_open (GST_AUDIO_SINK (oss), TRUE)) {
348 g_value_set_string (value, oss->device_name);
349 gst_oss4_sink_close (GST_AUDIO_SINK (oss));
353 gst_oss4_property_probe_find_device_name_nofd (GST_OBJECT (oss),
355 g_value_set_string (value, name);
359 g_value_set_string (value, oss->device_name);
361 GST_OBJECT_UNLOCK (oss);
364 g_value_set_double (value, gst_oss4_sink_get_volume (oss));
367 g_value_set_boolean (value, gst_oss4_sink_get_mute (oss));
370 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
376 gst_oss4_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
381 oss = GST_OSS4_SINK (bsink);
384 caps = gst_oss4_audio_get_template_caps ();
385 } else if (oss->probed_caps) {
386 caps = gst_caps_copy (oss->probed_caps);
388 caps = gst_oss4_audio_probe_caps (GST_OBJECT (oss), oss->fd);
389 if (caps != NULL && !gst_caps_is_empty (caps)) {
390 oss->probed_caps = gst_caps_copy (caps);
394 if (filter && caps) {
395 GstCaps *intersection;
398 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
399 gst_caps_unref (caps);
406 /* note: we must not take the object lock here unless we fix up get_property */
408 gst_oss4_sink_open (GstAudioSink * asink, gboolean silent_errors)
414 oss = GST_OSS4_SINK (asink);
417 device = g_strdup (oss->device);
419 device = gst_oss4_audio_find_device (GST_OBJECT_CAST (oss));
421 /* desperate times, desperate measures */
423 device = g_strdup ("/dev/dsp0");
425 GST_INFO_OBJECT (oss, "Trying to open OSS4 device '%s'", device);
427 /* we open in non-blocking mode even if we don't really want to do writes
428 * non-blocking because we can't be sure that this is really a genuine
429 * OSS4 device with well-behaved drivers etc. We really don't want to
430 * hang forever under any circumstances. */
431 oss->fd = open (device, O_WRONLY | O_NONBLOCK, 0);
443 GST_INFO_OBJECT (oss, "Opened device '%s'", device);
445 /* Make sure it's OSS4. If it's old OSS, let osssink handle it */
446 if (!gst_oss4_audio_check_version (GST_OBJECT_CAST (oss), oss->fd))
449 /* now remove the non-blocking flag. */
450 mode = fcntl (oss->fd, F_GETFL);
452 if (fcntl (oss->fd, F_SETFL, mode) < 0) {
453 /* some drivers do no support unsetting the non-blocking flag, try to
454 * close/open the device then. This is racy but we error out properly. */
455 GST_WARNING_OBJECT (oss, "failed to unset O_NONBLOCK (buggy driver?), "
456 "will try to re-open device now");
457 gst_oss4_sink_close (asink);
458 if ((oss->fd = open (device, O_WRONLY, 0)) == -1)
462 oss->open_device = device;
464 /* not using ENGINEINFO here because it sometimes returns a different and
465 * less useful name than AUDIOINFO for the same device */
466 if (!gst_oss4_property_probe_find_device_name (GST_OBJECT (oss), oss->fd,
467 oss->open_device, &oss->device_name)) {
468 oss->device_name = NULL;
471 /* list output routings, for informational purposes only so far */
473 oss_mixer_enuminfo routings = { 0, };
476 if (ioctl (oss->fd, SNDCTL_DSP_GET_PLAYTGT_NAMES, &routings) != -1) {
477 GST_LOG_OBJECT (oss, "%u output routings (static list: %d)",
478 routings.nvalues, ! !(routings.version == 0));
479 for (i = 0; i < routings.nvalues; ++i) {
480 GST_LOG_OBJECT (oss, " output routing %d: %s", i,
481 &routings.strings[routings.strindex[i]]);
491 if (!silent_errors) {
492 GST_ELEMENT_ERROR (oss, RESOURCE, BUSY,
493 (_("Could not open audio device for playback. "
494 "Device is being used by another application.")), (NULL));
501 if (!silent_errors) {
502 GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
503 (_("Could not open audio device for playback. "
504 "You don't have permission to open the device.")),
512 if (!silent_errors) {
513 GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
514 (_("Could not open audio device for playback.")), GST_ERROR_SYSTEM);
521 if (!silent_errors) {
522 GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
523 (_("Could not open audio device for playback. "
524 "This version of the Open Sound System is not supported by this "
525 "element.")), ("Try the 'osssink' element instead"));
527 gst_oss4_sink_close (asink);
533 if (!silent_errors) {
534 GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, (NULL),
535 ("Unable to set device %s into non-blocking mode: %s",
536 oss->device, g_strerror (errno)));
544 gst_oss4_sink_open_func (GstAudioSink * asink)
546 if (!gst_oss4_sink_open (asink, FALSE))
549 /* the initial volume might not be the property default, so notify
550 * application to make it get a reading of the current volume */
551 g_object_notify (G_OBJECT (asink), "volume");
556 gst_oss4_sink_close (GstAudioSink * asink)
558 GstOss4Sink *oss = GST_OSS4_SINK (asink);
561 GST_DEBUG_OBJECT (oss, "closing device");
566 oss->bytes_per_sample = 0;
567 /* we keep the probed caps cached, at least until the device changes */
569 g_free (oss->open_device);
570 oss->open_device = NULL;
572 g_free (oss->device_name);
573 oss->device_name = NULL;
575 if (oss->probed_caps) {
576 gst_caps_unref (oss->probed_caps);
577 oss->probed_caps = NULL;
584 gst_oss4_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
588 oss = GST_OSS4_SINK (asink);
590 if (!gst_oss4_audio_set_format (GST_OBJECT_CAST (oss), oss->fd, spec)) {
591 GST_WARNING_OBJECT (oss, "Couldn't set requested format %" GST_PTR_FORMAT,
596 oss->bytes_per_sample = GST_AUDIO_INFO_BPF (&spec->info);
602 gst_oss4_sink_unprepare (GstAudioSink * asink)
604 /* could do a SNDCTL_DSP_HALT, but the OSS manual recommends a close/open,
605 * since HALT won't properly reset some devices, apparently */
607 if (!gst_oss4_sink_close (asink))
610 if (!gst_oss4_sink_open_func (asink))
618 GST_DEBUG_OBJECT (asink, "Couldn't close the audio device");
623 GST_DEBUG_OBJECT (asink, "Couldn't reopen the audio device");
629 gst_oss4_sink_write (GstAudioSink * asink, gpointer data, guint length)
634 oss = GST_OSS4_SINK_CAST (asink);
636 n = write (oss->fd, data, length);
637 GST_LOG_OBJECT (asink, "wrote %d/%d samples, %d bytes",
638 n / oss->bytes_per_sample, length / oss->bytes_per_sample, n);
640 if (G_UNLIKELY (n < 0)) {
644 /* This is the most likely cause, I think */
645 GST_ELEMENT_ERROR (asink, RESOURCE, WRITE,
646 (_("Playback is not supported by this audio device.")),
647 ("write: %s (device: %s) (maybe this is an input-only device?)",
648 g_strerror (errno), oss->open_device));
652 GST_ELEMENT_ERROR (asink, RESOURCE, WRITE,
653 (_("Audio playback error.")),
654 ("write: %s (device: %s)", g_strerror (errno), oss->open_device));
664 gst_oss4_sink_delay (GstAudioSink * asink)
669 oss = GST_OSS4_SINK_CAST (asink);
671 GST_OBJECT_LOCK (oss);
672 if (ioctl (oss->fd, SNDCTL_DSP_GETODELAY, &delay) < 0 || delay < 0) {
673 GST_LOG_OBJECT (oss, "GETODELAY failed");
675 GST_OBJECT_UNLOCK (oss);
677 if (G_UNLIKELY (delay < 0)) /* error case */
680 return delay / oss->bytes_per_sample;
684 gst_oss4_sink_reset (GstAudioSink * asink)
686 /* There's nothing we can do here really: OSS can't handle access to the
687 * same device/fd from multiple threads and might deadlock or blow up in
688 * other ways if we try an ioctl SNDCTL_DSP_HALT or similar */