2 * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
25 #include <sys/ioctl.h>
31 #include <alsa/asoundlib.h>
34 #include "gstalsasink.h"
36 /* elementfactory information */
37 static GstElementDetails gst_alsasink_details =
38 GST_ELEMENT_DETAILS ("Audio Sink (ALSA)",
40 "Output to a sound card via ALSA",
41 "Wim Taymans <wim@fluendo.com>");
50 static void gst_alsasink_base_init (gpointer g_class);
51 static void gst_alsasink_class_init (GstAlsaSinkClass * klass);
52 static void gst_alsasink_init (GstAlsaSink * alsasink);
53 static void gst_alsasink_dispose (GObject * object);
54 static void gst_alsasink_set_property (GObject * object,
55 guint prop_id, const GValue * value, GParamSpec * pspec);
56 static void gst_alsasink_get_property (GObject * object,
57 guint prop_id, GValue * value, GParamSpec * pspec);
59 static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink);
61 static gboolean gst_alsasink_open (GstAudioSink * asink);
62 static gboolean gst_alsasink_prepare (GstAudioSink * asink,
63 GstRingBufferSpec * spec);
64 static gboolean gst_alsasink_unprepare (GstAudioSink * asink);
65 static gboolean gst_alsasink_close (GstAudioSink * asink);
66 static guint gst_alsasink_write (GstAudioSink * asink, gpointer data,
68 static guint gst_alsasink_delay (GstAudioSink * asink);
69 static void gst_alsasink_reset (GstAudioSink * asink);
71 /* AlsaSink signals and args */
77 static GstStaticPadTemplate alsasink_sink_factory =
78 GST_STATIC_PAD_TEMPLATE ("sink",
81 GST_STATIC_CAPS ("audio/x-raw-int, "
82 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
83 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
85 "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
87 "signed = (boolean) { TRUE, FALSE }, "
90 "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
92 "signed = (boolean) { TRUE, FALSE }, "
95 "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
98 static GstElementClass *parent_class = NULL;
100 /* static guint gst_alsasink_signals[LAST_SIGNAL] = { 0 }; */
103 gst_alsasink_get_type (void)
105 static GType alsasink_type = 0;
107 if (!alsasink_type) {
108 static const GTypeInfo alsasink_info = {
109 sizeof (GstAlsaSinkClass),
110 gst_alsasink_base_init,
112 (GClassInitFunc) gst_alsasink_class_init,
115 sizeof (GstAlsaSink),
117 (GInstanceInitFunc) gst_alsasink_init,
121 g_type_register_static (GST_TYPE_AUDIO_SINK, "GstAlsaSink",
125 return alsasink_type;
129 gst_alsasink_dispose (GObject * object)
131 G_OBJECT_CLASS (parent_class)->dispose (object);
135 gst_alsasink_base_init (gpointer g_class)
137 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
139 gst_element_class_set_details (element_class, &gst_alsasink_details);
141 gst_element_class_add_pad_template (element_class,
142 gst_static_pad_template_get (&alsasink_sink_factory));
145 gst_alsasink_class_init (GstAlsaSinkClass * klass)
147 GObjectClass *gobject_class;
148 GstElementClass *gstelement_class;
149 GstBaseSinkClass *gstbasesink_class;
150 GstBaseAudioSinkClass *gstbaseaudiosink_class;
151 GstAudioSinkClass *gstaudiosink_class;
153 gobject_class = (GObjectClass *) klass;
154 gstelement_class = (GstElementClass *) klass;
155 gstbasesink_class = (GstBaseSinkClass *) klass;
156 gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
157 gstaudiosink_class = (GstAudioSinkClass *) klass;
159 parent_class = g_type_class_ref (GST_TYPE_BASE_AUDIO_SINK);
161 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_alsasink_dispose);
162 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_alsasink_get_property);
163 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_alsasink_set_property);
165 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps);
167 gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink_open);
168 gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasink_prepare);
169 gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasink_unprepare);
170 gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink_close);
171 gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink_write);
172 gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink_delay);
173 gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_alsasink_reset);
175 g_object_class_install_property (gobject_class, PROP_DEVICE,
176 g_param_spec_string ("device", "Device",
177 "ALSA device, as defined in an asound configuration file",
178 "default", G_PARAM_READWRITE));
180 g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
181 g_param_spec_string ("device-name", "Device name",
182 "Human-readable name of the sound device", "", G_PARAM_READABLE));
186 gst_alsasink_set_property (GObject * object, guint prop_id,
187 const GValue * value, GParamSpec * pspec)
191 sink = GST_ALSA_SINK (object);
196 g_free (sink->device);
197 sink->device = g_strdup (g_value_get_string (value));
200 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
206 gst_alsasink_get_property (GObject * object, guint prop_id,
207 GValue * value, GParamSpec * pspec)
211 sink = GST_ALSA_SINK (object);
215 g_value_set_string (value, sink->device);
217 case PROP_DEVICE_NAME:
219 snd_pcm_info_t *info;
221 snd_pcm_info_malloc (&info);
222 snd_pcm_info (sink->handle, info);
223 g_value_set_string (value, snd_pcm_info_get_name (info));
224 snd_pcm_info_free (info);
226 g_value_set_string (value, NULL);
230 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
236 gst_alsasink_init (GstAlsaSink * alsasink)
238 GST_DEBUG ("initializing alsasink");
240 alsasink->device = g_strdup ("default");
241 alsasink->handle = NULL;
245 gst_alsasink_getcaps (GstBaseSink * bsink)
250 #define CHECK(call, error) \
252 if ((err = call) < 0) \
257 set_hwparams (GstAlsaSink * alsa)
261 snd_pcm_hw_params_t *params;
263 snd_pcm_hw_params_alloca (¶ms);
265 GST_DEBUG ("Negotiating to %d channels @ %d Hz", alsa->channels, alsa->rate);
267 /* choose all parameters */
268 CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config);
269 /* set the interleaved read/write format */
270 CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access),
272 /* set the sample format */
273 CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format),
275 /* set the count of channels */
276 CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels),
278 /* set the stream rate */
280 CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, 0),
282 if (rrate != alsa->rate)
285 if (alsa->buffer_time != -1) {
286 /* set the buffer time */
287 CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
288 &alsa->buffer_time, &dir), buffer_time);
290 if (alsa->period_time != -1) {
291 /* set the period time */
292 CHECK (snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
293 &alsa->period_time, &dir), period_time);
296 /* write the parameters to device */
297 CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);
299 CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
302 CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir),
310 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
311 ("Broken configuration for playback: no configurations available: %s",
312 snd_strerror (err)), (NULL));
317 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
318 ("Access type not available for playback: %s", snd_strerror (err)),
324 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
325 ("Sample format not available for playback: %s", snd_strerror (err)),
331 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
332 ("Channels count (%i) not available for playbacks: %s",
333 alsa->channels, snd_strerror (err)), (NULL));
338 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
339 ("Rate %iHz not available for playback: %s",
340 alsa->rate, snd_strerror (err)), (NULL));
345 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
346 ("Rate doesn't match (requested %iHz, get %iHz)",
347 alsa->rate, err), (NULL));
352 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
353 ("Unable to set buffer time %i for playback: %s",
354 alsa->buffer_time, snd_strerror (err)), (NULL));
359 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
360 ("Unable to get buffer size for playback: %s", snd_strerror (err)),
366 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
367 ("Unable to set period time %i for playback: %s", alsa->period_time,
368 snd_strerror (err)), (NULL));
373 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
374 ("Unable to get period size for playback: %s", snd_strerror (err)),
380 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
381 ("Unable to set hw params for playback: %s", snd_strerror (err)),
388 set_swparams (GstAlsaSink * alsa)
391 snd_pcm_sw_params_t *params;
393 snd_pcm_sw_params_alloca (¶ms);
395 /* get the current swparams */
396 CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
397 /* start the transfer when the buffer is almost full: */
398 /* (buffer_size / avail_min) * avail_min */
399 CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
400 (alsa->buffer_size / alsa->period_size) * alsa->period_size),
403 /* allow the transfer when at least period_size samples can be processed */
404 CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
405 alsa->period_size), set_avail);
406 /* align all transfers to 1 sample */
407 CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
409 /* write the parameters to the playback device */
410 CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);
417 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
418 ("Unable to determine current swparams for playback: %s",
419 snd_strerror (err)), (NULL));
424 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
425 ("Unable to set start threshold mode for playback: %s",
426 snd_strerror (err)), (NULL));
431 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
432 ("Unable to set avail min for playback: %s", snd_strerror (err)),
438 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
439 ("Unable to set transfer align for playback: %s", snd_strerror (err)),
445 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
446 ("Unable to set sw params for playback: %s", snd_strerror (err)),
453 alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec)
455 switch (spec->type) {
456 case GST_BUFTYPE_LINEAR:
457 alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
458 spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
460 case GST_BUFTYPE_FLOAT:
461 switch (spec->format) {
463 alsa->format = SND_PCM_FORMAT_FLOAT_LE;
466 alsa->format = SND_PCM_FORMAT_FLOAT_BE;
469 alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
472 alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
478 case GST_BUFTYPE_A_LAW:
479 alsa->format = SND_PCM_FORMAT_A_LAW;
481 case GST_BUFTYPE_MU_LAW:
482 alsa->format = SND_PCM_FORMAT_MU_LAW;
488 alsa->rate = spec->rate;
489 alsa->channels = spec->channels;
490 alsa->buffer_time = spec->buffer_time;
491 alsa->period_time = spec->latency_time;
492 alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
504 gst_alsasink_open (GstAudioSink * asink)
509 alsa = GST_ALSA_SINK (asink);
511 CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK,
512 SND_PCM_NONBLOCK), open_error);
520 GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY, (NULL), (NULL));
522 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE,
523 (NULL), ("Playback open error: %s", snd_strerror (err)));
530 gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
535 alsa = GST_ALSA_SINK (asink);
537 if (!alsasink_parse_spec (alsa, spec))
540 CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);
542 CHECK (set_hwparams (alsa), hw_params_failed);
543 CHECK (set_swparams (alsa), sw_params_failed);
545 alsa->bytes_per_sample = spec->bytes_per_sample;
546 spec->segsize = alsa->period_size * spec->bytes_per_sample;
547 spec->segtotal = alsa->buffer_size / alsa->period_size;
548 spec->silence_sample[0] = 0;
549 spec->silence_sample[1] = 0;
550 spec->silence_sample[2] = 0;
551 spec->silence_sample[3] = 0;
558 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
559 ("Error parsing spec"), (NULL));
564 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
565 ("Could not set device to blocking: %s", snd_strerror (err)), (NULL));
570 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
571 ("Setting of hwparams failed: %s", snd_strerror (err)), (NULL));
576 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
577 ("Setting of swparams failed: %s", snd_strerror (err)), (NULL));
583 gst_alsasink_unprepare (GstAudioSink * asink)
588 alsa = GST_ALSA_SINK (asink);
590 CHECK (snd_pcm_drop (alsa->handle), drop);
592 CHECK (snd_pcm_hw_free (alsa->handle), hw_free);
594 CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block);
601 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
602 ("Could not drop samples: %s", snd_strerror (err)), (NULL));
607 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
608 ("Could not free hw params: %s", snd_strerror (err)), (NULL));
613 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
614 ("Could not set device to nonblocking: %s", snd_strerror (err)),
621 gst_alsasink_close (GstAudioSink * asink)
623 GstAlsaSink *alsa = GST_ALSA_SINK (asink);
626 CHECK (snd_pcm_close (alsa->handle), close_error);
634 GST_ELEMENT_ERROR (alsa, RESOURCE, CLOSE,
635 ("Playback close error: %s", snd_strerror (err)), (NULL));
642 * Underrun and suspend recovery
645 xrun_recovery (snd_pcm_t * handle, gint err)
647 GST_DEBUG ("xrun recovery %d", err);
649 if (err == -EPIPE) { /* under-run */
650 err = snd_pcm_prepare (handle);
652 GST_WARNING ("Can't recovery from underrun, prepare failed: %s",
655 } else if (err == -ESTRPIPE) {
656 while ((err = snd_pcm_resume (handle)) == -EAGAIN)
657 g_usleep (100); /* wait until the suspend flag is released */
660 err = snd_pcm_prepare (handle);
662 GST_WARNING ("Can't recovery from suspend, prepare failed: %s",
671 gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
678 alsa = GST_ALSA_SINK (asink);
680 cptr = length / alsa->bytes_per_sample;
684 err = snd_pcm_writei (alsa->handle, ptr, cptr);
687 if (err == -EAGAIN) {
688 GST_DEBUG ("Write error: %s", snd_strerror (err));
690 } else if (xrun_recovery (alsa->handle, err) < 0) {
696 ptr += err * alsa->channels;
700 return length - cptr;
704 return length; /* skip one period */
709 gst_alsasink_delay (GstAudioSink * asink)
712 snd_pcm_sframes_t delay;
714 alsa = GST_ALSA_SINK (asink);
716 snd_pcm_delay (alsa->handle, &delay);
722 gst_alsasink_reset (GstAudioSink * asink)
728 alsa = GST_ALSA_SINK (asink);
730 CHECK (snd_pcm_drop (alsa->handle), drop_error);
731 CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
738 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
739 ("alsa-reset: pcm drop error: %s", snd_strerror (err)), (NULL));
744 GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
745 ("alsa-reset: pcm prepare error: %s", snd_strerror (err)), (NULL));