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 (¶ms);
432 snd_pcm_hw_params_malloc (¶ms_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 (¶ms);
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