expand tabs
[platform/upstream/gstreamer.git] / ext / alsa / gstalsasink.c
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  *
4  * gstalsasink.c:
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <sys/ioctl.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <getopt.h>
31 #include <alsa/asoundlib.h>
32
33 #include "gstalsa.h"
34 #include "gstalsasink.h"
35
36 /* elementfactory information */
37 static GstElementDetails gst_alsasink_details =
38 GST_ELEMENT_DETAILS ("Audio Sink (ALSA)",
39     "Sink/Audio",
40     "Output to a sound card via ALSA",
41     "Wim Taymans <wim@fluendo.com>");
42
43 enum
44 {
45   PROP_0,
46   PROP_DEVICE,
47   PROP_DEVICE_NAME
48 };
49
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);
58
59 static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink);
60
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,
67     guint length);
68 static guint gst_alsasink_delay (GstAudioSink * asink);
69 static void gst_alsasink_reset (GstAudioSink * asink);
70
71 /* AlsaSink signals and args */
72 enum
73 {
74   LAST_SIGNAL
75 };
76
77 static GstStaticPadTemplate alsasink_sink_factory =
78     GST_STATIC_PAD_TEMPLATE ("sink",
79     GST_PAD_SINK,
80     GST_PAD_ALWAYS,
81     GST_STATIC_CAPS ("audio/x-raw-int, "
82 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
83         "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
84 #else
85         "endianness = (int) { BIG_ENDIAN, LITTLE_ENDIAN }, "
86 #endif
87         "signed = (boolean) { TRUE, FALSE }, "
88         "width = (int) 16, "
89         "depth = (int) 16, "
90         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
91         "audio/x-raw-int, "
92         "signed = (boolean) { TRUE, FALSE }, "
93         "width = (int) 8, "
94         "depth = (int) 8, "
95         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
96     );
97
98 static GstElementClass *parent_class = NULL;
99
100 /* static guint gst_alsasink_signals[LAST_SIGNAL] = { 0 }; */
101
102 GType
103 gst_alsasink_get_type (void)
104 {
105   static GType alsasink_type = 0;
106
107   if (!alsasink_type) {
108     static const GTypeInfo alsasink_info = {
109       sizeof (GstAlsaSinkClass),
110       gst_alsasink_base_init,
111       NULL,
112       (GClassInitFunc) gst_alsasink_class_init,
113       NULL,
114       NULL,
115       sizeof (GstAlsaSink),
116       0,
117       (GInstanceInitFunc) gst_alsasink_init,
118     };
119
120     alsasink_type =
121         g_type_register_static (GST_TYPE_AUDIO_SINK, "GstAlsaSink",
122         &alsasink_info, 0);
123   }
124
125   return alsasink_type;
126 }
127
128 static void
129 gst_alsasink_dispose (GObject * object)
130 {
131   G_OBJECT_CLASS (parent_class)->dispose (object);
132 }
133
134 static void
135 gst_alsasink_base_init (gpointer g_class)
136 {
137   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
138
139   gst_element_class_set_details (element_class, &gst_alsasink_details);
140
141   gst_element_class_add_pad_template (element_class,
142       gst_static_pad_template_get (&alsasink_sink_factory));
143 }
144 static void
145 gst_alsasink_class_init (GstAlsaSinkClass * klass)
146 {
147   GObjectClass *gobject_class;
148   GstElementClass *gstelement_class;
149   GstBaseSinkClass *gstbasesink_class;
150   GstBaseAudioSinkClass *gstbaseaudiosink_class;
151   GstAudioSinkClass *gstaudiosink_class;
152
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;
158
159   parent_class = g_type_class_ref (GST_TYPE_BASE_AUDIO_SINK);
160
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);
164
165   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps);
166
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);
174
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));
179
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));
183 }
184
185 static void
186 gst_alsasink_set_property (GObject * object, guint prop_id,
187     const GValue * value, GParamSpec * pspec)
188 {
189   GstAlsaSink *sink;
190
191   sink = GST_ALSA_SINK (object);
192
193   switch (prop_id) {
194     case PROP_DEVICE:
195       if (sink->device)
196         g_free (sink->device);
197       sink->device = g_strdup (g_value_get_string (value));
198       break;
199     default:
200       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201       break;
202   }
203 }
204
205 static void
206 gst_alsasink_get_property (GObject * object, guint prop_id,
207     GValue * value, GParamSpec * pspec)
208 {
209   GstAlsaSink *sink;
210
211   sink = GST_ALSA_SINK (object);
212
213   switch (prop_id) {
214     case PROP_DEVICE:
215       g_value_set_string (value, sink->device);
216       break;
217     case PROP_DEVICE_NAME:
218       if (sink->handle) {
219         snd_pcm_info_t *info;
220
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);
225       } else {
226         g_value_set_string (value, NULL);
227       }
228       break;
229     default:
230       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231       break;
232   }
233 }
234
235 static void
236 gst_alsasink_init (GstAlsaSink * alsasink)
237 {
238   GST_DEBUG ("initializing alsasink");
239
240   alsasink->device = g_strdup ("default");
241   alsasink->handle = NULL;
242 }
243
244 static GstCaps *
245 gst_alsasink_getcaps (GstBaseSink * bsink)
246 {
247   return NULL;
248 }
249
250 #define CHECK(call, error) \
251 G_STMT_START {                  \
252 if ((err = call) < 0)           \
253   goto error;                   \
254 } G_STMT_END;
255
256 static int
257 set_hwparams (GstAlsaSink * alsa)
258 {
259   guint rrate;
260   gint err, dir;
261   snd_pcm_hw_params_t *params;
262
263   snd_pcm_hw_params_alloca (&params);
264
265   GST_DEBUG ("Negotiating to %d channels @ %d Hz", alsa->channels, alsa->rate);
266
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),
271       wrong_access);
272   /* set the sample format */
273   CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format),
274       no_sample_format);
275   /* set the count of channels */
276   CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels),
277       no_channels);
278   /* set the stream rate */
279   rrate = alsa->rate;
280   CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, 0),
281       no_rate);
282   if (rrate != alsa->rate)
283     goto rate_match;
284
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);
289   }
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);
294   }
295
296   /* write the parameters to device */
297   CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);
298
299   CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
300       buffer_size);
301
302   CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir),
303       period_size);
304
305   return 0;
306
307   /* ERRORS */
308 no_config:
309   {
310     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
311         ("Broken configuration for playback: no configurations available: %s",
312             snd_strerror (err)), (NULL));
313     return err;
314   }
315 wrong_access:
316   {
317     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
318         ("Access type not available for playback: %s", snd_strerror (err)),
319         (NULL));
320     return err;
321   }
322 no_sample_format:
323   {
324     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
325         ("Sample format not available for playback: %s", snd_strerror (err)),
326         (NULL));
327     return err;
328   }
329 no_channels:
330   {
331     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
332         ("Channels count (%i) not available for playbacks: %s",
333             alsa->channels, snd_strerror (err)), (NULL));
334     return err;
335   }
336 no_rate:
337   {
338     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
339         ("Rate %iHz not available for playback: %s",
340             alsa->rate, snd_strerror (err)), (NULL));
341     return err;
342   }
343 rate_match:
344   {
345     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
346         ("Rate doesn't match (requested %iHz, get %iHz)",
347             alsa->rate, err), (NULL));
348     return -EINVAL;
349   }
350 buffer_time:
351   {
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));
355     return err;
356   }
357 buffer_size:
358   {
359     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
360         ("Unable to get buffer size for playback: %s", snd_strerror (err)),
361         (NULL));
362     return err;
363   }
364 period_time:
365   {
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));
369     return err;
370   }
371 period_size:
372   {
373     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
374         ("Unable to get period size for playback: %s", snd_strerror (err)),
375         (NULL));
376     return err;
377   }
378 set_hw_params:
379   {
380     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
381         ("Unable to set hw params for playback: %s", snd_strerror (err)),
382         (NULL));
383     return err;
384   }
385 }
386
387 static int
388 set_swparams (GstAlsaSink * alsa)
389 {
390   int err;
391   snd_pcm_sw_params_t *params;
392
393   snd_pcm_sw_params_alloca (&params);
394
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),
401       start_threshold);
402
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);
408
409   /* write the parameters to the playback device */
410   CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);
411
412   return 0;
413
414   /* ERRORS */
415 no_config:
416   {
417     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
418         ("Unable to determine current swparams for playback: %s",
419             snd_strerror (err)), (NULL));
420     return err;
421   }
422 start_threshold:
423   {
424     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
425         ("Unable to set start threshold mode for playback: %s",
426             snd_strerror (err)), (NULL));
427     return err;
428   }
429 set_avail:
430   {
431     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
432         ("Unable to set avail min for playback: %s", snd_strerror (err)),
433         (NULL));
434     return err;
435   }
436 set_align:
437   {
438     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
439         ("Unable to set transfer align for playback: %s", snd_strerror (err)),
440         (NULL));
441     return err;
442   }
443 set_sw_params:
444   {
445     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
446         ("Unable to set sw params for playback: %s", snd_strerror (err)),
447         (NULL));
448     return err;
449   }
450 }
451
452 static gboolean
453 alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec)
454 {
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);
459       break;
460     case GST_BUFTYPE_FLOAT:
461       switch (spec->format) {
462         case GST_FLOAT32_LE:
463           alsa->format = SND_PCM_FORMAT_FLOAT_LE;
464           break;
465         case GST_FLOAT32_BE:
466           alsa->format = SND_PCM_FORMAT_FLOAT_BE;
467           break;
468         case GST_FLOAT64_LE:
469           alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
470           break;
471         case GST_FLOAT64_BE:
472           alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
473           break;
474         default:
475           goto error;
476       }
477       break;
478     case GST_BUFTYPE_A_LAW:
479       alsa->format = SND_PCM_FORMAT_A_LAW;
480       break;
481     case GST_BUFTYPE_MU_LAW:
482       alsa->format = SND_PCM_FORMAT_MU_LAW;
483       break;
484     default:
485       goto error;
486
487   }
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;
493
494   return TRUE;
495
496   /* ERRORS */
497 error:
498   {
499     return FALSE;
500   }
501 }
502
503 static gboolean
504 gst_alsasink_open (GstAudioSink * asink)
505 {
506   GstAlsaSink *alsa;
507   gint err;
508
509   alsa = GST_ALSA_SINK (asink);
510
511   CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK,
512           SND_PCM_NONBLOCK), open_error);
513
514   return TRUE;
515
516   /* ERRORS */
517 open_error:
518   {
519     if (err == -EBUSY) {
520       GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY, (NULL), (NULL));
521     } else {
522       GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE,
523           (NULL), ("Playback open error: %s", snd_strerror (err)));
524     }
525     return FALSE;
526   }
527 }
528
529 static gboolean
530 gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
531 {
532   GstAlsaSink *alsa;
533   gint err;
534
535   alsa = GST_ALSA_SINK (asink);
536
537   if (!alsasink_parse_spec (alsa, spec))
538     goto spec_parse;
539
540   CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);
541
542   CHECK (set_hwparams (alsa), hw_params_failed);
543   CHECK (set_swparams (alsa), sw_params_failed);
544
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;
552
553   return TRUE;
554
555   /* ERRORS */
556 spec_parse:
557   {
558     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
559         ("Error parsing spec"), (NULL));
560     return FALSE;
561   }
562 non_block:
563   {
564     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
565         ("Could not set device to blocking: %s", snd_strerror (err)), (NULL));
566     return FALSE;
567   }
568 hw_params_failed:
569   {
570     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
571         ("Setting of hwparams failed: %s", snd_strerror (err)), (NULL));
572     return FALSE;
573   }
574 sw_params_failed:
575   {
576     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
577         ("Setting of swparams failed: %s", snd_strerror (err)), (NULL));
578     return FALSE;
579   }
580 }
581
582 static gboolean
583 gst_alsasink_unprepare (GstAudioSink * asink)
584 {
585   GstAlsaSink *alsa;
586   gint err;
587
588   alsa = GST_ALSA_SINK (asink);
589
590   CHECK (snd_pcm_drop (alsa->handle), drop);
591
592   CHECK (snd_pcm_hw_free (alsa->handle), hw_free);
593
594   CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block);
595
596   return TRUE;
597
598   /* ERRORS */
599 drop:
600   {
601     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
602         ("Could not drop samples: %s", snd_strerror (err)), (NULL));
603     return FALSE;
604   }
605 hw_free:
606   {
607     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
608         ("Could not free hw params: %s", snd_strerror (err)), (NULL));
609     return FALSE;
610   }
611 non_block:
612   {
613     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
614         ("Could not set device to nonblocking: %s", snd_strerror (err)),
615         (NULL));
616     return FALSE;
617   }
618 }
619
620 static gboolean
621 gst_alsasink_close (GstAudioSink * asink)
622 {
623   GstAlsaSink *alsa = GST_ALSA_SINK (asink);
624   gint err;
625
626   CHECK (snd_pcm_close (alsa->handle), close_error);
627   alsa->handle = NULL;
628
629   return TRUE;
630
631   /* ERRORS */
632 close_error:
633   {
634     GST_ELEMENT_ERROR (alsa, RESOURCE, CLOSE,
635         ("Playback close error: %s", snd_strerror (err)), (NULL));
636     return FALSE;
637   }
638 }
639
640
641 /*
642  *   Underrun and suspend recovery
643  */
644 static gint
645 xrun_recovery (snd_pcm_t * handle, gint err)
646 {
647   GST_DEBUG ("xrun recovery %d", err);
648
649   if (err == -EPIPE) {          /* under-run */
650     err = snd_pcm_prepare (handle);
651     if (err < 0)
652       GST_WARNING ("Can't recovery from underrun, prepare failed: %s",
653           snd_strerror (err));
654     return 0;
655   } else if (err == -ESTRPIPE) {
656     while ((err = snd_pcm_resume (handle)) == -EAGAIN)
657       g_usleep (100);           /* wait until the suspend flag is released */
658
659     if (err < 0) {
660       err = snd_pcm_prepare (handle);
661       if (err < 0)
662         GST_WARNING ("Can't recovery from suspend, prepare failed: %s",
663             snd_strerror (err));
664     }
665     return 0;
666   }
667   return err;
668 }
669
670 static guint
671 gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
672 {
673   GstAlsaSink *alsa;
674   gint err;
675   gint cptr;
676   gint16 *ptr;
677
678   alsa = GST_ALSA_SINK (asink);
679
680   cptr = length / alsa->bytes_per_sample;
681   ptr = data;
682
683   while (cptr > 0) {
684     err = snd_pcm_writei (alsa->handle, ptr, cptr);
685
686     if (err < 0) {
687       if (err == -EAGAIN) {
688         GST_DEBUG ("Write error: %s", snd_strerror (err));
689         continue;
690       } else if (xrun_recovery (alsa->handle, err) < 0) {
691         goto write_error;
692       }
693       continue;
694     }
695
696     ptr += err * alsa->channels;
697     cptr -= err;
698   }
699
700   return length - cptr;
701
702 write_error:
703   {
704     return length;              /* skip one period */
705   }
706 }
707
708 static guint
709 gst_alsasink_delay (GstAudioSink * asink)
710 {
711   GstAlsaSink *alsa;
712   snd_pcm_sframes_t delay;
713
714   alsa = GST_ALSA_SINK (asink);
715
716   snd_pcm_delay (alsa->handle, &delay);
717
718   return delay;
719 }
720
721 static void
722 gst_alsasink_reset (GstAudioSink * asink)
723 {
724 #if 0
725   GstAlsaSink *alsa;
726   gint err;
727
728   alsa = GST_ALSA_SINK (asink);
729
730   CHECK (snd_pcm_drop (alsa->handle), drop_error);
731   CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
732
733   return;
734
735   /* ERRORS */
736 drop_error:
737   {
738     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
739         ("alsa-reset: pcm drop error: %s", snd_strerror (err)), (NULL));
740     return;
741   }
742 prepare_error:
743   {
744     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
745         ("alsa-reset: pcm prepare error: %s", snd_strerror (err)), (NULL));
746     return;
747   }
748 #endif
749 }