• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4  *
5  * gstalsasink.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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /**
24  * SECTION:element-alsasink
25  * @title: alsasink
26  * @see_also: alsasrc
27  *
28  * This element renders audio samples using the ALSA audio API.
29  *
30  * ## Example pipelines
31  * |[
32  * gst-launch-1.0 -v uridecodebin uri=file:///path/to/audio.ogg ! audioconvert ! audioresample ! autoaudiosink
33  * ]|
34  *
35  * Play an Ogg/Vorbis file and output audio via ALSA.
36  *
37  */
38 
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 #include <sys/ioctl.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <getopt.h>
48 #include <alsa/asoundlib.h>
49 
50 #include "gstalsaelements.h"
51 #include "gstalsa.h"
52 #include "gstalsasink.h"
53 
54 #include <gst/audio/gstaudioiec61937.h>
55 #include <gst/gst-i18n-plugin.h>
56 
57 #ifndef ESTRPIPE
58 #define ESTRPIPE EPIPE
59 #endif
60 
61 #define DEFAULT_DEVICE		"default"
62 #define DEFAULT_DEVICE_NAME	""
63 #define DEFAULT_CARD_NAME	""
64 #define SPDIF_PERIOD_SIZE 1536
65 #define SPDIF_BUFFER_SIZE 15360
66 
67 enum
68 {
69   PROP_0,
70   PROP_DEVICE,
71   PROP_DEVICE_NAME,
72   PROP_CARD_NAME,
73   PROP_LAST
74 };
75 
76 #define gst_alsasink_parent_class parent_class
77 G_DEFINE_TYPE (GstAlsaSink, gst_alsasink, GST_TYPE_AUDIO_SINK);
78 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (alsasink, "alsasink", GST_RANK_PRIMARY,
79     GST_TYPE_ALSA_SINK, alsa_element_init (plugin));
80 
81 static void gst_alsasink_finalise (GObject * object);
82 static void gst_alsasink_set_property (GObject * object,
83     guint prop_id, const GValue * value, GParamSpec * pspec);
84 static void gst_alsasink_get_property (GObject * object,
85     guint prop_id, GValue * value, GParamSpec * pspec);
86 
87 static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink, GstCaps * filter);
88 static gboolean gst_alsasink_query (GstBaseSink * bsink, GstQuery * query);
89 
90 static gboolean gst_alsasink_open (GstAudioSink * asink);
91 static gboolean gst_alsasink_prepare (GstAudioSink * asink,
92     GstAudioRingBufferSpec * spec);
93 static gboolean gst_alsasink_unprepare (GstAudioSink * asink);
94 static gboolean gst_alsasink_close (GstAudioSink * asink);
95 static gint gst_alsasink_write (GstAudioSink * asink, gpointer data,
96     guint length);
97 static guint gst_alsasink_delay (GstAudioSink * asink);
98 static void gst_alsasink_pause (GstAudioSink * asink);
99 static void gst_alsasink_resume (GstAudioSink * asink);
100 static void gst_alsasink_stop (GstAudioSink * asink);
101 static gboolean gst_alsasink_acceptcaps (GstAlsaSink * alsa, GstCaps * caps);
102 static GstBuffer *gst_alsasink_payload (GstAudioBaseSink * sink,
103     GstBuffer * buf);
104 
105 static gint output_ref;         /* 0    */
106 static snd_output_t *output;    /* NULL */
107 static GMutex output_mutex;
108 
109 static GstStaticPadTemplate alsasink_sink_factory =
110     GST_STATIC_PAD_TEMPLATE ("sink",
111     GST_PAD_SINK,
112     GST_PAD_ALWAYS,
113     GST_STATIC_CAPS ("audio/x-raw, "
114         "format = (string) " GST_AUDIO_FORMATS_ALL ", "
115         "layout = (string) interleaved, "
116         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
117         PASSTHROUGH_CAPS)
118     );
119 
120 static void
gst_alsasink_finalise(GObject * object)121 gst_alsasink_finalise (GObject * object)
122 {
123   GstAlsaSink *sink = GST_ALSA_SINK (object);
124 
125   g_free (sink->device);
126   g_mutex_clear (&sink->alsa_lock);
127   g_mutex_clear (&sink->delay_lock);
128 
129   g_mutex_lock (&output_mutex);
130   --output_ref;
131   if (output_ref == 0) {
132     snd_output_close (output);
133     output = NULL;
134   }
135   g_mutex_unlock (&output_mutex);
136 
137   G_OBJECT_CLASS (parent_class)->finalize (object);
138 }
139 
140 static void
gst_alsasink_class_init(GstAlsaSinkClass * klass)141 gst_alsasink_class_init (GstAlsaSinkClass * klass)
142 {
143   GObjectClass *gobject_class;
144   GstElementClass *gstelement_class;
145   GstBaseSinkClass *gstbasesink_class;
146   GstAudioBaseSinkClass *gstbaseaudiosink_class;
147   GstAudioSinkClass *gstaudiosink_class;
148 
149   gobject_class = (GObjectClass *) klass;
150   gstelement_class = (GstElementClass *) klass;
151   gstbasesink_class = (GstBaseSinkClass *) klass;
152   gstbaseaudiosink_class = (GstAudioBaseSinkClass *) klass;
153   gstaudiosink_class = (GstAudioSinkClass *) klass;
154 
155   parent_class = g_type_class_peek_parent (klass);
156 
157   gobject_class->finalize = gst_alsasink_finalise;
158   gobject_class->get_property = gst_alsasink_get_property;
159   gobject_class->set_property = gst_alsasink_set_property;
160 
161   gst_element_class_set_static_metadata (gstelement_class,
162       "Audio sink (ALSA)", "Sink/Audio",
163       "Output to a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
164 
165   gst_element_class_add_static_pad_template (gstelement_class,
166       &alsasink_sink_factory);
167 
168   gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps);
169   gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_alsasink_query);
170 
171   gstbaseaudiosink_class->payload = GST_DEBUG_FUNCPTR (gst_alsasink_payload);
172 
173   gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink_open);
174   gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasink_prepare);
175   gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasink_unprepare);
176   gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink_close);
177   gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink_write);
178   gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink_delay);
179   gstaudiosink_class->stop = GST_DEBUG_FUNCPTR (gst_alsasink_stop);
180   gstaudiosink_class->pause = GST_DEBUG_FUNCPTR (gst_alsasink_pause);
181   gstaudiosink_class->resume = GST_DEBUG_FUNCPTR (gst_alsasink_resume);
182 
183   g_object_class_install_property (gobject_class, PROP_DEVICE,
184       g_param_spec_string ("device", "Device",
185           "ALSA device, as defined in an asound configuration file",
186           DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187 
188   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
189       g_param_spec_string ("device-name", "Device name",
190           "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
191           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
192 
193   g_object_class_install_property (gobject_class, PROP_CARD_NAME,
194       g_param_spec_string ("card-name", "Card name",
195           "Human-readable name of the sound card", DEFAULT_CARD_NAME,
196           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS |
197           GST_PARAM_DOC_SHOW_DEFAULT));
198 }
199 
200 static void
gst_alsasink_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)201 gst_alsasink_set_property (GObject * object, guint prop_id,
202     const GValue * value, GParamSpec * pspec)
203 {
204   GstAlsaSink *sink;
205 
206   sink = GST_ALSA_SINK (object);
207 
208   switch (prop_id) {
209     case PROP_DEVICE:
210       g_free (sink->device);
211       sink->device = g_value_dup_string (value);
212       /* setting NULL restores the default device */
213       if (sink->device == NULL) {
214         sink->device = g_strdup (DEFAULT_DEVICE);
215       }
216       break;
217     default:
218       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219       break;
220   }
221 }
222 
223 static void
gst_alsasink_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)224 gst_alsasink_get_property (GObject * object, guint prop_id,
225     GValue * value, GParamSpec * pspec)
226 {
227   GstAlsaSink *sink;
228 
229   sink = GST_ALSA_SINK (object);
230 
231   switch (prop_id) {
232     case PROP_DEVICE:
233       g_value_set_string (value, sink->device);
234       break;
235     case PROP_DEVICE_NAME:
236       g_value_take_string (value,
237           gst_alsa_find_device_name (GST_OBJECT_CAST (sink),
238               sink->device, sink->handle, SND_PCM_STREAM_PLAYBACK));
239       break;
240     case PROP_CARD_NAME:
241       g_value_take_string (value,
242           gst_alsa_find_card_name (GST_OBJECT_CAST (sink),
243               sink->device, SND_PCM_STREAM_PLAYBACK));
244       break;
245     default:
246       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247       break;
248   }
249 }
250 
251 static void
gst_alsasink_init(GstAlsaSink * alsasink)252 gst_alsasink_init (GstAlsaSink * alsasink)
253 {
254   GST_DEBUG_OBJECT (alsasink, "initializing alsasink");
255 
256   alsasink->device = g_strdup (DEFAULT_DEVICE);
257   alsasink->handle = NULL;
258   alsasink->cached_caps = NULL;
259   alsasink->is_paused = FALSE;
260   alsasink->after_paused = FALSE;
261   alsasink->hw_support_pause = FALSE;
262   g_mutex_init (&alsasink->alsa_lock);
263   g_mutex_init (&alsasink->delay_lock);
264 
265   g_mutex_lock (&output_mutex);
266   if (output_ref == 0) {
267     snd_output_stdio_attach (&output, stdout, 0);
268     ++output_ref;
269   }
270   g_mutex_unlock (&output_mutex);
271 }
272 
273 #define CHECK(call, error) \
274 G_STMT_START {             \
275   if ((err = call) < 0) {  \
276     GST_WARNING_OBJECT (alsa, "Error %d (%s) calling " #call, err, snd_strerror (err)); \
277     goto error;            \
278   }                        \
279 } G_STMT_END;
280 
281 static GstCaps *
gst_alsasink_getcaps(GstBaseSink * bsink,GstCaps * filter)282 gst_alsasink_getcaps (GstBaseSink * bsink, GstCaps * filter)
283 {
284   GstElementClass *element_class;
285   GstPadTemplate *pad_template;
286   GstAlsaSink *sink = GST_ALSA_SINK (bsink);
287   GstCaps *caps, *templ_caps;
288 
289   GST_OBJECT_LOCK (sink);
290   if (sink->handle == NULL) {
291     GST_OBJECT_UNLOCK (sink);
292     GST_DEBUG_OBJECT (sink, "device not open, using template caps");
293     return NULL;                /* base class will get template caps for us */
294   }
295 
296   if (sink->cached_caps) {
297     if (filter) {
298       caps = gst_caps_intersect_full (filter, sink->cached_caps,
299           GST_CAPS_INTERSECT_FIRST);
300       GST_OBJECT_UNLOCK (sink);
301       GST_LOG_OBJECT (sink, "Returning cached caps %" GST_PTR_FORMAT " with "
302           "filter %" GST_PTR_FORMAT " applied: %" GST_PTR_FORMAT,
303           sink->cached_caps, filter, caps);
304       return caps;
305     } else {
306       caps = gst_caps_ref (sink->cached_caps);
307       GST_OBJECT_UNLOCK (sink);
308       GST_LOG_OBJECT (sink, "Returning cached caps %" GST_PTR_FORMAT, caps);
309       return caps;
310     }
311   }
312 
313   element_class = GST_ELEMENT_GET_CLASS (sink);
314   pad_template = gst_element_class_get_pad_template (element_class, "sink");
315   if (pad_template == NULL) {
316     GST_OBJECT_UNLOCK (sink);
317     g_assert_not_reached ();
318     return NULL;
319   }
320 
321   templ_caps = gst_pad_template_get_caps (pad_template);
322   caps = gst_alsa_probe_supported_formats (GST_OBJECT (sink), sink->device,
323       sink->handle, templ_caps);
324   gst_caps_unref (templ_caps);
325 
326   if (caps) {
327     sink->cached_caps = gst_caps_ref (caps);
328   }
329 
330   GST_OBJECT_UNLOCK (sink);
331 
332   GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, caps);
333 
334   if (filter) {
335     GstCaps *intersection;
336 
337     intersection =
338         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
339     gst_caps_unref (caps);
340     return intersection;
341   } else {
342     return caps;
343   }
344 }
345 
346 static gboolean
gst_alsasink_acceptcaps(GstAlsaSink * alsa,GstCaps * caps)347 gst_alsasink_acceptcaps (GstAlsaSink * alsa, GstCaps * caps)
348 {
349   GstPad *pad = GST_BASE_SINK (alsa)->sinkpad;
350   GstCaps *pad_caps;
351   GstStructure *st;
352   gboolean ret = FALSE;
353   GstAudioRingBufferSpec spec = { 0 };
354 
355   pad_caps = gst_pad_query_caps (pad, caps);
356   if (!pad_caps || gst_caps_is_empty (pad_caps)) {
357     if (pad_caps)
358       gst_caps_unref (pad_caps);
359     ret = FALSE;
360     goto done;
361   }
362   gst_caps_unref (pad_caps);
363 
364   /* If we've not got fixed caps, creating a stream might fail, so let's just
365    * return from here with default acceptcaps behaviour */
366   if (!gst_caps_is_fixed (caps))
367     goto done;
368 
369   /* parse helper expects this set, so avoid nasty warning
370    * will be set properly later on anyway  */
371   spec.latency_time = GST_SECOND;
372   if (!gst_audio_ring_buffer_parse_caps (&spec, caps))
373     goto done;
374 
375   /* Make sure input is framed (one frame per buffer) and can be payloaded */
376   switch (spec.type) {
377     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
378     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
379     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
380     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
381     {
382       gboolean framed = FALSE, parsed = FALSE;
383       st = gst_caps_get_structure (caps, 0);
384 
385       gst_structure_get_boolean (st, "framed", &framed);
386       gst_structure_get_boolean (st, "parsed", &parsed);
387       if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
388         goto done;
389     }
390     default:{
391     }
392   }
393   ret = TRUE;
394 
395 done:
396   gst_caps_replace (&spec.caps, NULL);
397   return ret;
398 }
399 
400 static gboolean
gst_alsasink_query(GstBaseSink * sink,GstQuery * query)401 gst_alsasink_query (GstBaseSink * sink, GstQuery * query)
402 {
403   GstAlsaSink *alsa = GST_ALSA_SINK (sink);
404   gboolean ret;
405 
406   switch (GST_QUERY_TYPE (query)) {
407     case GST_QUERY_ACCEPT_CAPS:
408     {
409       GstCaps *caps;
410 
411       gst_query_parse_accept_caps (query, &caps);
412       ret = gst_alsasink_acceptcaps (alsa, caps);
413       gst_query_set_accept_caps_result (query, ret);
414       ret = TRUE;
415       break;
416     }
417     default:
418       ret = GST_BASE_SINK_CLASS (parent_class)->query (sink, query);
419       break;
420   }
421   return ret;
422 }
423 
424 static int
set_hwparams(GstAlsaSink * alsa)425 set_hwparams (GstAlsaSink * alsa)
426 {
427   guint rrate;
428   gint err = 0;
429   snd_pcm_hw_params_t *params, *params_copy;
430 
431   snd_pcm_hw_params_malloc (&params);
432   snd_pcm_hw_params_malloc (&params_copy);
433 
434   GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) "
435       "SPDIF (%d)", alsa->channels, alsa->rate,
436       snd_pcm_format_name (alsa->format), alsa->iec958);
437 
438   /* choose all parameters */
439   CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config);
440   /* set the interleaved read/write format */
441   CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access),
442       wrong_access);
443   /* set the sample format */
444   if (alsa->iec958) {
445     /* Try to use big endian first else fallback to le and swap bytes */
446     if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) {
447       alsa->format = SND_PCM_FORMAT_S16_LE;
448       alsa->need_swap = TRUE;
449       GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping");
450     } else {
451       alsa->need_swap = FALSE;
452     }
453   }
454   CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format),
455       no_sample_format);
456   /* set the count of channels */
457   CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels),
458       no_channels);
459   /* set the stream rate */
460   rrate = alsa->rate;
461   CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL),
462       no_rate);
463 #ifndef GST_DISABLE_GST_DEBUG
464   /* get and dump some limits */
465   {
466     guint min, max;
467 
468     snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL);
469     snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL);
470 
471     GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u",
472         alsa->buffer_time, min, max);
473 
474     snd_pcm_hw_params_get_period_time_min (params, &min, NULL);
475     snd_pcm_hw_params_get_period_time_max (params, &max, NULL);
476 
477     GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u",
478         alsa->period_time, min, max);
479 
480     snd_pcm_hw_params_get_periods_min (params, &min, NULL);
481     snd_pcm_hw_params_get_periods_max (params, &max, NULL);
482 
483     GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max);
484   }
485 #endif
486   /* Keep a copy of initial params struct that can be used later */
487   snd_pcm_hw_params_copy (params_copy, params);
488   if (!alsa->iec958) {
489     /* Following pulseaudio's approach in
490      * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/commit/557c4295107dc7374c850b0bd5331dd35e8fdd0f
491      * we'll try various configuration to set the period time and buffer time as some
492      * driver can be picky on the order of the calls.
493      */
494     if (alsa->buffer_time != -1 && alsa->period_time != -1) {
495       if (((err = snd_pcm_hw_params_set_period_time_near (alsa->handle,
496                       params, &alsa->period_time, NULL)) >= 0)
497           && ((err =
498                   snd_pcm_hw_params_set_buffer_time_near (alsa->handle,
499                       params, &alsa->buffer_time, NULL)) >= 0)) {
500         GST_DEBUG_OBJECT (alsa, "period time %u buffer time %u set correctly",
501             alsa->period_time, alsa->buffer_time);
502         goto success;
503       }
504       /* Try the new order with previous params struct as current one might
505          have partial settings from the order that was tried unsuccessfully */
506       snd_pcm_hw_params_copy (params, params_copy);
507       if (((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle,
508                       params, &alsa->buffer_time, NULL)) >= 0)
509           && ((err =
510                   snd_pcm_hw_params_set_period_time_near (alsa->handle,
511                       params, &alsa->period_time, NULL)) >= 0)) {
512         GST_DEBUG_OBJECT (alsa, "buffer time %u period time %u set correctly",
513             alsa->buffer_time, alsa->period_time);
514         goto success;
515       }
516     }
517     /* now try to configure the period time and buffer time exclusively
518      * if both fail  we fall back to the defaults */
519     if (alsa->period_time != -1) {
520       snd_pcm_hw_params_copy (params, params_copy);
521       /* set the period time */
522       if ((err =
523               snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
524                   &alsa->period_time, NULL)) < 0) {
525         GST_DEBUG_OBJECT (alsa, "Unable to set period time %i for playback: %s",
526             alsa->period_time, snd_strerror (err));
527       } else {
528         GST_DEBUG_OBJECT (alsa, "period time %u set correctly",
529             alsa->period_time);
530         goto success;
531       }
532     }
533     if (alsa->buffer_time != -1) {
534       snd_pcm_hw_params_copy (params, params_copy);
535       /* set the buffer time */
536       if ((err =
537               snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
538                   &alsa->buffer_time, NULL)) < 0) {
539         GST_DEBUG_OBJECT (alsa, "Unable to set buffer time %i for playback: %s",
540             alsa->buffer_time, snd_strerror (err));
541       } else {
542         GST_DEBUG_OBJECT (alsa, "buffer time %u set correctly",
543             alsa->buffer_time);
544         goto success;
545       }
546     }
547   } else {
548     /* Set buffer size and period size manually for SPDIF */
549     snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE;
550     snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE;
551 
552     CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params,
553             &buffer_size), buffer_size);
554     CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params,
555             &period_size, NULL), period_size);
556     goto success;
557   }
558   /* Set nothing if all above failed */
559   snd_pcm_hw_params_copy (params, params_copy);
560   GST_DEBUG_OBJECT (alsa, "Not setting period time and buffer time");
561 
562 success:
563   /* write the parameters to device */
564   CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);
565   /* now get the configured values */
566   CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
567       buffer_size);
568   CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size,
569           NULL), period_size);
570 
571   GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size,
572       alsa->period_size);
573 
574   /* Check if hardware supports pause */
575   alsa->hw_support_pause = snd_pcm_hw_params_can_pause (params);
576   GST_DEBUG_OBJECT (alsa, "Hw support pause: %s",
577       alsa->hw_support_pause ? "yes" : "no");
578 
579   goto exit;
580   /* ERRORS */
581 no_config:
582   {
583     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
584         ("Broken configuration for playback: no configurations available: %s",
585             snd_strerror (err)));
586     goto exit;
587   }
588 wrong_access:
589   {
590     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
591         ("Access type not available for playback: %s", snd_strerror (err)));
592     goto exit;
593   }
594 no_sample_format:
595   {
596     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
597         ("Sample format not available for playback: %s", snd_strerror (err)));
598     goto exit;
599   }
600 no_channels:
601   {
602     gchar *msg = NULL;
603 
604     if ((alsa->channels) == 1)
605       msg = g_strdup (_("Could not open device for playback in mono mode."));
606     if ((alsa->channels) == 2)
607       msg = g_strdup (_("Could not open device for playback in stereo mode."));
608     if ((alsa->channels) > 2)
609       msg =
610           g_strdup_printf (_
611           ("Could not open device for playback in %d-channel mode."),
612           alsa->channels);
613     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg),
614         ("%s", snd_strerror (err)));
615     g_free (msg);
616     goto exit;
617   }
618 no_rate:
619   {
620     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
621         ("Rate %iHz not available for playback: %s",
622             alsa->rate, snd_strerror (err)));
623     goto exit;
624   }
625 buffer_size:
626   {
627     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
628         ("Unable to get buffer size for playback: %s", snd_strerror (err)));
629     goto exit;
630   }
631 period_size:
632   {
633     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
634         ("Unable to get period size for playback: %s", snd_strerror (err)));
635     goto exit;
636   }
637 set_hw_params:
638   {
639     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
640         ("Unable to set hw params for playback: %s", snd_strerror (err)));
641   }
642 exit:
643   {
644     snd_pcm_hw_params_free (params);
645     snd_pcm_hw_params_free (params_copy);
646     return err;
647   }
648 }
649 
650 static int
set_swparams(GstAlsaSink * alsa)651 set_swparams (GstAlsaSink * alsa)
652 {
653   int err;
654   snd_pcm_sw_params_t *params;
655 
656   snd_pcm_sw_params_malloc (&params);
657 
658   /* get the current swparams */
659   CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
660   /* start the transfer when the buffer is almost full: */
661   /* (buffer_size / avail_min) * avail_min */
662   CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
663           (alsa->buffer_size / alsa->period_size) * alsa->period_size),
664       start_threshold);
665 
666   /* allow the transfer when at least period_size samples can be processed */
667   CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
668           alsa->period_size), set_avail);
669 
670 #if GST_CHECK_ALSA_VERSION(1,0,16)
671   /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
672 #else
673   /* align all transfers to 1 sample */
674   CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
675 #endif
676 
677   /* write the parameters to the playback device */
678   CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);
679 
680   snd_pcm_sw_params_free (params);
681   return 0;
682 
683   /* ERRORS */
684 no_config:
685   {
686     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
687         ("Unable to determine current swparams for playback: %s",
688             snd_strerror (err)));
689     snd_pcm_sw_params_free (params);
690     return err;
691   }
692 start_threshold:
693   {
694     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
695         ("Unable to set start threshold mode for playback: %s",
696             snd_strerror (err)));
697     snd_pcm_sw_params_free (params);
698     return err;
699   }
700 set_avail:
701   {
702     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
703         ("Unable to set avail min for playback: %s", snd_strerror (err)));
704     snd_pcm_sw_params_free (params);
705     return err;
706   }
707 #if !GST_CHECK_ALSA_VERSION(1,0,16)
708 set_align:
709   {
710     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
711         ("Unable to set transfer align for playback: %s", snd_strerror (err)));
712     snd_pcm_sw_params_free (params);
713     return err;
714   }
715 #endif
716 set_sw_params:
717   {
718     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
719         ("Unable to set sw params for playback: %s", snd_strerror (err)));
720     snd_pcm_sw_params_free (params);
721     return err;
722   }
723 }
724 
725 static gboolean
alsasink_parse_spec(GstAlsaSink * alsa,GstAudioRingBufferSpec * spec)726 alsasink_parse_spec (GstAlsaSink * alsa, GstAudioRingBufferSpec * spec)
727 {
728   /* Initialize our boolean */
729   alsa->iec958 = FALSE;
730 
731   switch (spec->type) {
732     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
733       switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
734         case GST_AUDIO_FORMAT_U8:
735           alsa->format = SND_PCM_FORMAT_U8;
736           break;
737         case GST_AUDIO_FORMAT_S8:
738           alsa->format = SND_PCM_FORMAT_S8;
739           break;
740         case GST_AUDIO_FORMAT_S16LE:
741           alsa->format = SND_PCM_FORMAT_S16_LE;
742           break;
743         case GST_AUDIO_FORMAT_S16BE:
744           alsa->format = SND_PCM_FORMAT_S16_BE;
745           break;
746         case GST_AUDIO_FORMAT_U16LE:
747           alsa->format = SND_PCM_FORMAT_U16_LE;
748           break;
749         case GST_AUDIO_FORMAT_U16BE:
750           alsa->format = SND_PCM_FORMAT_U16_BE;
751           break;
752         case GST_AUDIO_FORMAT_S24_32LE:
753           alsa->format = SND_PCM_FORMAT_S24_LE;
754           break;
755         case GST_AUDIO_FORMAT_S24_32BE:
756           alsa->format = SND_PCM_FORMAT_S24_BE;
757           break;
758         case GST_AUDIO_FORMAT_U24_32LE:
759           alsa->format = SND_PCM_FORMAT_U24_LE;
760           break;
761         case GST_AUDIO_FORMAT_U24_32BE:
762           alsa->format = SND_PCM_FORMAT_U24_BE;
763           break;
764         case GST_AUDIO_FORMAT_S32LE:
765           alsa->format = SND_PCM_FORMAT_S32_LE;
766           break;
767         case GST_AUDIO_FORMAT_S32BE:
768           alsa->format = SND_PCM_FORMAT_S32_BE;
769           break;
770         case GST_AUDIO_FORMAT_U32LE:
771           alsa->format = SND_PCM_FORMAT_U32_LE;
772           break;
773         case GST_AUDIO_FORMAT_U32BE:
774           alsa->format = SND_PCM_FORMAT_U32_BE;
775           break;
776         case GST_AUDIO_FORMAT_S24LE:
777           alsa->format = SND_PCM_FORMAT_S24_3LE;
778           break;
779         case GST_AUDIO_FORMAT_S24BE:
780           alsa->format = SND_PCM_FORMAT_S24_3BE;
781           break;
782         case GST_AUDIO_FORMAT_U24LE:
783           alsa->format = SND_PCM_FORMAT_U24_3LE;
784           break;
785         case GST_AUDIO_FORMAT_U24BE:
786           alsa->format = SND_PCM_FORMAT_U24_3BE;
787           break;
788         case GST_AUDIO_FORMAT_S20LE:
789           alsa->format = SND_PCM_FORMAT_S20_3LE;
790           break;
791         case GST_AUDIO_FORMAT_S20BE:
792           alsa->format = SND_PCM_FORMAT_S20_3BE;
793           break;
794         case GST_AUDIO_FORMAT_U20LE:
795           alsa->format = SND_PCM_FORMAT_U20_3LE;
796           break;
797         case GST_AUDIO_FORMAT_U20BE:
798           alsa->format = SND_PCM_FORMAT_U20_3BE;
799           break;
800         case GST_AUDIO_FORMAT_S18LE:
801           alsa->format = SND_PCM_FORMAT_S18_3LE;
802           break;
803         case GST_AUDIO_FORMAT_S18BE:
804           alsa->format = SND_PCM_FORMAT_S18_3BE;
805           break;
806         case GST_AUDIO_FORMAT_U18LE:
807           alsa->format = SND_PCM_FORMAT_U18_3LE;
808           break;
809         case GST_AUDIO_FORMAT_U18BE:
810           alsa->format = SND_PCM_FORMAT_U18_3BE;
811           break;
812         case GST_AUDIO_FORMAT_F32LE:
813           alsa->format = SND_PCM_FORMAT_FLOAT_LE;
814           break;
815         case GST_AUDIO_FORMAT_F32BE:
816           alsa->format = SND_PCM_FORMAT_FLOAT_BE;
817           break;
818         case GST_AUDIO_FORMAT_F64LE:
819           alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
820           break;
821         case GST_AUDIO_FORMAT_F64BE:
822           alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
823           break;
824         default:
825           goto error;
826       }
827       break;
828     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW:
829       alsa->format = SND_PCM_FORMAT_A_LAW;
830       break;
831     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW:
832       alsa->format = SND_PCM_FORMAT_MU_LAW;
833       break;
834     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
835     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
836     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
837     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
838       alsa->format = SND_PCM_FORMAT_S16_BE;
839       alsa->iec958 = TRUE;
840       break;
841     default:
842       goto error;
843 
844   }
845   alsa->rate = GST_AUDIO_INFO_RATE (&spec->info);
846   alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
847   alsa->buffer_time = spec->buffer_time;
848   alsa->period_time = spec->latency_time;
849   alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
850 
851   if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9)
852     gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SINK
853         (alsa)->ringbuffer, alsa_position[alsa->channels - 1]);
854 
855   return TRUE;
856 
857   /* ERRORS */
858 error:
859   {
860     return FALSE;
861   }
862 }
863 
864 static gboolean
gst_alsasink_open(GstAudioSink * asink)865 gst_alsasink_open (GstAudioSink * asink)
866 {
867   GstAlsaSink *alsa;
868   gint err;
869 
870   alsa = GST_ALSA_SINK (asink);
871 
872   /* open in non-blocking mode, we'll use snd_pcm_wait() for space to become
873    * available. */
874   CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK,
875           SND_PCM_NONBLOCK), open_error);
876   GST_LOG_OBJECT (alsa, "Opened device %s", alsa->device);
877 
878   return TRUE;
879 
880   /* ERRORS */
881 open_error:
882   {
883     if (err == -EBUSY) {
884       GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY,
885           (_("Could not open audio device for playback. "
886                   "Device is being used by another application.")),
887           ("Device '%s' is busy", alsa->device));
888     } else {
889       GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE,
890           (_("Could not open audio device for playback.")),
891           ("Playback open error on device '%s': %s", alsa->device,
892               snd_strerror (err)));
893     }
894     return FALSE;
895   }
896 }
897 
898 static gboolean
gst_alsasink_prepare(GstAudioSink * asink,GstAudioRingBufferSpec * spec)899 gst_alsasink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
900 {
901   GstAlsaSink *alsa;
902   gint err;
903 
904   alsa = GST_ALSA_SINK (asink);
905 
906   if (alsa->iec958) {
907     snd_pcm_close (alsa->handle);
908     alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa), alsa->device);
909     if (G_UNLIKELY (!alsa->handle)) {
910       goto no_iec958;
911     }
912   }
913 
914   if (!alsasink_parse_spec (alsa, spec))
915     goto spec_parse;
916 
917   CHECK (set_hwparams (alsa), hw_params_failed);
918   CHECK (set_swparams (alsa), sw_params_failed);
919 
920   alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
921   spec->segsize = alsa->period_size * alsa->bpf;
922   spec->segtotal = alsa->buffer_size / alsa->period_size;
923 
924   {
925     snd_output_t *out_buf = NULL;
926     char *msg = NULL;
927 
928     snd_output_buffer_open (&out_buf);
929     snd_pcm_dump_hw_setup (alsa->handle, out_buf);
930     snd_output_buffer_string (out_buf, &msg);
931     GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
932     snd_output_close (out_buf);
933     snd_output_buffer_open (&out_buf);
934     snd_pcm_dump_sw_setup (alsa->handle, out_buf);
935     snd_output_buffer_string (out_buf, &msg);
936     GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
937     snd_output_close (out_buf);
938   }
939 
940 #ifdef SND_CHMAP_API_VERSION
941   alsa_detect_channels_mapping (GST_OBJECT (alsa), alsa->handle, spec,
942       alsa->channels, GST_AUDIO_BASE_SINK (alsa)->ringbuffer);
943 #endif /* SND_CHMAP_API_VERSION */
944 
945   return TRUE;
946 
947   /* ERRORS */
948 no_iec958:
949   {
950     GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE, (NULL),
951         ("Could not open IEC958 (SPDIF) device for playback"));
952     return FALSE;
953   }
954 spec_parse:
955   {
956     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
957         ("Error parsing spec"));
958     return FALSE;
959   }
960 hw_params_failed:
961   {
962     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
963         ("Setting of hwparams failed: %s", snd_strerror (err)));
964     return FALSE;
965   }
966 sw_params_failed:
967   {
968     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
969         ("Setting of swparams failed: %s", snd_strerror (err)));
970     return FALSE;
971   }
972 }
973 
974 static gboolean
gst_alsasink_unprepare(GstAudioSink * asink)975 gst_alsasink_unprepare (GstAudioSink * asink)
976 {
977   GstAlsaSink *alsa;
978 
979   alsa = GST_ALSA_SINK (asink);
980 
981   snd_pcm_drop (alsa->handle);
982   snd_pcm_hw_free (alsa->handle);
983 
984   return TRUE;
985 }
986 
987 static gboolean
gst_alsasink_close(GstAudioSink * asink)988 gst_alsasink_close (GstAudioSink * asink)
989 {
990   GstAlsaSink *alsa = GST_ALSA_SINK (asink);
991 
992   GST_OBJECT_LOCK (asink);
993   if (alsa->handle) {
994     snd_pcm_close (alsa->handle);
995     alsa->handle = NULL;
996   }
997   gst_caps_replace (&alsa->cached_caps, NULL);
998   GST_OBJECT_UNLOCK (asink);
999 
1000   return TRUE;
1001 }
1002 
1003 
1004 /*
1005  *   Underrun and suspend recovery
1006  */
1007 static gint
xrun_recovery(GstAlsaSink * alsa,snd_pcm_t * handle,gint err)1008 xrun_recovery (GstAlsaSink * alsa, snd_pcm_t * handle, gint err)
1009 {
1010   GST_WARNING_OBJECT (alsa, "xrun recovery %d: %s", err, g_strerror (-err));
1011 
1012   if (err == -EPIPE) {          /* under-run */
1013     err = snd_pcm_prepare (handle);
1014     if (err < 0)
1015       GST_WARNING_OBJECT (alsa,
1016           "Can't recover from underrun, prepare failed: %s",
1017           snd_strerror (err));
1018     gst_audio_base_sink_report_device_failure (GST_AUDIO_BASE_SINK (alsa));
1019     return 0;
1020   } else if (err == -ESTRPIPE) {
1021     while ((err = snd_pcm_resume (handle)) == -EAGAIN)
1022       g_usleep (100);           /* wait until the suspend flag is released */
1023 
1024     if (err < 0) {
1025       err = snd_pcm_prepare (handle);
1026       if (err < 0)
1027         GST_WARNING_OBJECT (alsa,
1028             "Can't recover from suspend, prepare failed: %s",
1029             snd_strerror (err));
1030     }
1031     if (err == 0)
1032       gst_audio_base_sink_report_device_failure (GST_AUDIO_BASE_SINK (alsa));
1033     return 0;
1034   }
1035   return err;
1036 }
1037 
1038 static gint
gst_alsasink_write(GstAudioSink * asink,gpointer data,guint length)1039 gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
1040 {
1041   GstAlsaSink *alsa;
1042   gint err;
1043   gint cptr;
1044   guint8 *ptr = data;
1045 
1046   alsa = GST_ALSA_SINK (asink);
1047 
1048   if (alsa->iec958 && alsa->need_swap) {
1049     guint i;
1050     guint16 *ptr_tmp = (guint16 *) ptr;
1051 
1052     GST_DEBUG_OBJECT (asink, "swapping bytes");
1053     for (i = 0; i < length / 2; i++) {
1054       ptr_tmp[i] = GUINT16_SWAP_LE_BE (ptr_tmp[i]);
1055     }
1056   }
1057 
1058   GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length);
1059 
1060   cptr = length / alsa->bpf;
1061 
1062   GST_ALSA_SINK_LOCK (asink);
1063   while (cptr > 0) {
1064     /* start by doing a blocking wait for free space. Set the timeout
1065      * to 4 times the period time */
1066     err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000));
1067     if (err < 0) {
1068       GST_DEBUG_OBJECT (asink, "wait error, %d", err);
1069     } else {
1070       GST_DELAY_SINK_LOCK (asink);
1071       err = snd_pcm_writei (alsa->handle, ptr, cptr);
1072       GST_DELAY_SINK_UNLOCK (asink);
1073     }
1074 
1075     if (err < 0) {
1076       GST_DEBUG_OBJECT (asink, "Write error: %s (%d)", snd_strerror (err), err);
1077       if (err == -EAGAIN) {
1078         /* will continue out of the if/else group */
1079       } else if (err == -ENODEV) {
1080         goto device_disappeared;
1081       } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
1082         goto write_error;
1083       }
1084 
1085       /* Unlock so that _reset() can run and break an otherwise infinit loop
1086        * here */
1087       GST_ALSA_SINK_UNLOCK (asink);
1088       g_thread_yield ();
1089       GST_ALSA_SINK_LOCK (asink);
1090       continue;
1091     } else if (err == 0 && alsa->hw_support_pause) {
1092       /* We might be already paused, if so, just bail */
1093       if (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PAUSED)
1094         break;
1095     }
1096 
1097     GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr);
1098     ptr += snd_pcm_frames_to_bytes (alsa->handle, err);
1099     cptr -= err;
1100   }
1101   GST_ALSA_SINK_UNLOCK (asink);
1102 
1103   return length - (cptr * alsa->bpf);
1104 
1105 write_error:
1106   {
1107     GST_ALSA_SINK_UNLOCK (asink);
1108     return length;              /* skip one period */
1109   }
1110 device_disappeared:
1111   {
1112     GST_ELEMENT_ERROR (asink, RESOURCE, WRITE,
1113         (_("Error outputting to audio device. "
1114                 "The device has been disconnected.")), (NULL));
1115     goto write_error;
1116   }
1117 }
1118 
1119 static guint
gst_alsasink_delay(GstAudioSink * asink)1120 gst_alsasink_delay (GstAudioSink * asink)
1121 {
1122   GstAlsaSink *alsa;
1123   snd_pcm_sframes_t delay;
1124   int res = 0;
1125 
1126   alsa = GST_ALSA_SINK (asink);
1127 
1128   GST_DELAY_SINK_LOCK (asink);
1129   if (alsa->is_paused == TRUE) {
1130     delay = alsa->pos_in_buffer;
1131     alsa->is_paused = FALSE;
1132     alsa->after_paused = TRUE;
1133   } else {
1134     if (alsa->after_paused == TRUE) {
1135       delay = alsa->pos_in_buffer;
1136       alsa->after_paused = FALSE;
1137     } else {
1138       res = snd_pcm_delay (alsa->handle, &delay);
1139     }
1140   }
1141   GST_DELAY_SINK_UNLOCK (asink);
1142   if (G_UNLIKELY (res < 0)) {
1143     /* on errors, report 0 delay */
1144     GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res);
1145     delay = 0;
1146   }
1147   if (G_UNLIKELY (delay < 0)) {
1148     /* make sure we never return a negative delay */
1149     GST_WARNING_OBJECT (alsa, "snd_pcm_delay returned negative delay");
1150     delay = 0;
1151   }
1152 
1153   return delay;
1154 }
1155 
1156 static void
gst_alsasink_pause(GstAudioSink * asink)1157 gst_alsasink_pause (GstAudioSink * asink)
1158 {
1159   GstAlsaSink *alsa;
1160   gint err;
1161   snd_pcm_sframes_t delay;
1162 
1163   alsa = GST_ALSA_SINK (asink);
1164 
1165   if (alsa->hw_support_pause == TRUE) {
1166     GST_ALSA_SINK_LOCK (asink);
1167     snd_pcm_delay (alsa->handle, &delay);
1168     alsa->pos_in_buffer = delay;
1169     CHECK (snd_pcm_pause (alsa->handle, 1), pause_error);
1170     GST_DEBUG_OBJECT (alsa, "pause done");
1171     alsa->is_paused = TRUE;
1172     GST_ALSA_SINK_UNLOCK (asink);
1173   } else {
1174     gst_alsasink_stop (asink);
1175   }
1176 
1177   return;
1178 
1179 pause_error:
1180   {
1181     GST_ERROR_OBJECT (alsa, "alsa-pause: pcm pause error: %s",
1182         snd_strerror (err));
1183     GST_ALSA_SINK_UNLOCK (asink);
1184     return;
1185   }
1186 }
1187 
1188 static void
gst_alsasink_resume(GstAudioSink * asink)1189 gst_alsasink_resume (GstAudioSink * asink)
1190 {
1191   GstAlsaSink *alsa;
1192   gint err;
1193 
1194   alsa = GST_ALSA_SINK (asink);
1195 
1196   if (alsa->hw_support_pause == TRUE) {
1197     GST_ALSA_SINK_LOCK (asink);
1198     CHECK (snd_pcm_pause (alsa->handle, 0), resume_error);
1199     GST_DEBUG_OBJECT (alsa, "resume done");
1200     GST_ALSA_SINK_UNLOCK (asink);
1201   }
1202 
1203   return;
1204 
1205 resume_error:
1206   {
1207     GST_ERROR_OBJECT (alsa, "alsa-resume: pcm resume error: %s",
1208         snd_strerror (err));
1209     GST_ALSA_SINK_UNLOCK (asink);
1210     return;
1211   }
1212 }
1213 
1214 static void
gst_alsasink_stop(GstAudioSink * asink)1215 gst_alsasink_stop (GstAudioSink * asink)
1216 {
1217   GstAlsaSink *alsa;
1218   gint err;
1219 
1220   alsa = GST_ALSA_SINK (asink);
1221 
1222   GST_ALSA_SINK_LOCK (asink);
1223   GST_DEBUG_OBJECT (alsa, "drop");
1224   CHECK (snd_pcm_drop (alsa->handle), drop_error);
1225   GST_DEBUG_OBJECT (alsa, "prepare");
1226   CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
1227   GST_DEBUG_OBJECT (alsa, "stop done");
1228   GST_ALSA_SINK_UNLOCK (asink);
1229 
1230   return;
1231 
1232   /* ERRORS */
1233 drop_error:
1234   {
1235     GST_ERROR_OBJECT (alsa, "alsa-stop: pcm drop error: %s",
1236         snd_strerror (err));
1237     GST_ALSA_SINK_UNLOCK (asink);
1238     return;
1239   }
1240 prepare_error:
1241   {
1242     GST_ERROR_OBJECT (alsa, "alsa-stop: pcm prepare error: %s",
1243         snd_strerror (err));
1244     GST_ALSA_SINK_UNLOCK (asink);
1245     return;
1246   }
1247 }
1248 
1249 static GstBuffer *
gst_alsasink_payload(GstAudioBaseSink * sink,GstBuffer * buf)1250 gst_alsasink_payload (GstAudioBaseSink * sink, GstBuffer * buf)
1251 {
1252   GstAlsaSink *alsa;
1253 
1254   alsa = GST_ALSA_SINK (sink);
1255 
1256   if (alsa->iec958) {
1257     GstBuffer *out;
1258     gint framesize;
1259     GstMapInfo iinfo, oinfo;
1260 
1261     framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
1262     if (framesize <= 0)
1263       return NULL;
1264 
1265     out = gst_buffer_new_and_alloc (framesize);
1266 
1267     gst_buffer_map (buf, &iinfo, GST_MAP_READ);
1268     gst_buffer_map (out, &oinfo, GST_MAP_WRITE);
1269 
1270     if (!gst_audio_iec61937_payload (iinfo.data, iinfo.size,
1271             oinfo.data, oinfo.size, &sink->ringbuffer->spec, G_BIG_ENDIAN)) {
1272       gst_buffer_unmap (buf, &iinfo);
1273       gst_buffer_unmap (out, &oinfo);
1274       gst_buffer_unref (out);
1275       return NULL;
1276     }
1277 
1278     gst_buffer_unmap (buf, &iinfo);
1279     gst_buffer_unmap (out, &oinfo);
1280 
1281     gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1282     return out;
1283   }
1284 
1285   return gst_buffer_ref (buf);
1286 }
1287