• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  *
4  * gstalsasrc.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., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 /**
23  * SECTION:element-alsasrc
24  * @title: alsasrc
25  * @see_also: alsasink
26  *
27  * This element reads data from an audio card using the ALSA API.
28  *
29  * ## Example pipelines
30  * |[
31  * gst-launch-1.0 -v alsasrc ! queue ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
32  * ]|
33  *  Record from a sound card using ALSA and encode to Ogg/Vorbis.
34  *
35  */
36 
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 #include <sys/ioctl.h>
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <getopt.h>
46 #include <alsa/asoundlib.h>
47 
48 #include "gstalsaelements.h"
49 #include "gstalsasrc.h"
50 
51 #include <gst/gst-i18n-plugin.h>
52 
53 #ifndef ESTRPIPE
54 #define ESTRPIPE EPIPE
55 #endif
56 
57 #define DEFAULT_PROP_DEVICE		  "default"
58 #define DEFAULT_PROP_DEVICE_NAME	  ""
59 #define DEFAULT_PROP_CARD_NAME	          ""
60 #define DEFAULT_PROP_USE_DRIVER_TIMESTAMP TRUE
61 
62 enum
63 {
64   PROP_0,
65   PROP_DEVICE,
66   PROP_DEVICE_NAME,
67   PROP_CARD_NAME,
68   PROP_USE_DRIVER_TIMESTAMP,
69   PROP_LAST
70 };
71 
72 #define gst_alsasrc_parent_class parent_class
73 G_DEFINE_TYPE (GstAlsaSrc, gst_alsasrc, GST_TYPE_AUDIO_SRC);
74 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (alsasrc, "alsasrc", GST_RANK_PRIMARY,
75     GST_TYPE_ALSA_SRC, alsa_element_init (plugin));
76 
77 static void gst_alsasrc_finalize (GObject * object);
78 static void gst_alsasrc_set_property (GObject * object,
79     guint prop_id, const GValue * value, GParamSpec * pspec);
80 static void gst_alsasrc_get_property (GObject * object,
81     guint prop_id, GValue * value, GParamSpec * pspec);
82 static GstStateChangeReturn gst_alsasrc_change_state (GstElement * element,
83     GstStateChange transition);
84 static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
85 
86 static gboolean gst_alsasrc_open (GstAudioSrc * asrc);
87 static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc,
88     GstAudioRingBufferSpec * spec);
89 static gboolean gst_alsasrc_unprepare (GstAudioSrc * asrc);
90 static gboolean gst_alsasrc_close (GstAudioSrc * asrc);
91 static guint gst_alsasrc_read
92     (GstAudioSrc * asrc, gpointer data, guint length, GstClockTime * timestamp);
93 static guint gst_alsasrc_delay (GstAudioSrc * asrc);
94 static void gst_alsasrc_reset (GstAudioSrc * asrc);
95 
96 /* AlsaSrc signals and args */
97 enum
98 {
99   LAST_SIGNAL
100 };
101 
102 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
103 # define ALSA_SRC_FACTORY_ENDIANNESS   "LITTLE_ENDIAN, BIG_ENDIAN"
104 #else
105 # define ALSA_SRC_FACTORY_ENDIANNESS   "BIG_ENDIAN, LITTLE_ENDIAN"
106 #endif
107 
108 static GstStaticPadTemplate alsasrc_src_factory =
109 GST_STATIC_PAD_TEMPLATE ("src",
110     GST_PAD_SRC,
111     GST_PAD_ALWAYS,
112     GST_STATIC_CAPS ("audio/x-raw, "
113         "format = (string) " GST_AUDIO_FORMATS_ALL ", "
114         "layout = (string) interleaved, "
115         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
116     );
117 
118 static void
gst_alsasrc_finalize(GObject * object)119 gst_alsasrc_finalize (GObject * object)
120 {
121   GstAlsaSrc *src = GST_ALSA_SRC (object);
122 
123   g_free (src->device);
124   g_mutex_clear (&src->alsa_lock);
125 
126   G_OBJECT_CLASS (parent_class)->finalize (object);
127 }
128 
129 static void
gst_alsasrc_class_init(GstAlsaSrcClass * klass)130 gst_alsasrc_class_init (GstAlsaSrcClass * klass)
131 {
132   GObjectClass *gobject_class;
133   GstElementClass *gstelement_class;
134   GstBaseSrcClass *gstbasesrc_class;
135   GstAudioSrcClass *gstaudiosrc_class;
136 
137   gobject_class = (GObjectClass *) klass;
138   gstelement_class = (GstElementClass *) klass;
139   gstbasesrc_class = (GstBaseSrcClass *) klass;
140   gstaudiosrc_class = (GstAudioSrcClass *) klass;
141 
142   gobject_class->finalize = gst_alsasrc_finalize;
143   gobject_class->get_property = gst_alsasrc_get_property;
144   gobject_class->set_property = gst_alsasrc_set_property;
145 
146   gst_element_class_set_static_metadata (gstelement_class,
147       "Audio source (ALSA)", "Source/Audio",
148       "Read from a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
149 
150   gst_element_class_add_static_pad_template (gstelement_class,
151       &alsasrc_src_factory);
152 
153   gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps);
154 
155   gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_alsasrc_open);
156   gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasrc_prepare);
157   gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasrc_unprepare);
158   gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_alsasrc_close);
159   gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_alsasrc_read);
160   gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_alsasrc_delay);
161   gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_alsasrc_reset);
162   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_alsasrc_change_state);
163 
164   g_object_class_install_property (gobject_class, PROP_DEVICE,
165       g_param_spec_string ("device", "Device",
166           "ALSA device, as defined in an asound configuration file",
167           DEFAULT_PROP_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168 
169   g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
170       g_param_spec_string ("device-name", "Device name",
171           "Human-readable name of the sound device",
172           DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
173 
174   g_object_class_install_property (gobject_class, PROP_CARD_NAME,
175       g_param_spec_string ("card-name", "Card name",
176           "Human-readable name of the sound card",
177           DEFAULT_PROP_CARD_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS
178           | GST_PARAM_DOC_SHOW_DEFAULT));
179 
180   g_object_class_install_property (gobject_class, PROP_USE_DRIVER_TIMESTAMP,
181       g_param_spec_boolean ("use-driver-timestamps", "Use driver timestamps",
182           "Use driver timestamps or the pipeline clock timestamps",
183           DEFAULT_PROP_USE_DRIVER_TIMESTAMP,
184           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
185 }
186 
187 static void
gst_alsasrc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)188 gst_alsasrc_set_property (GObject * object, guint prop_id,
189     const GValue * value, GParamSpec * pspec)
190 {
191   GstAlsaSrc *src;
192 
193   src = GST_ALSA_SRC (object);
194 
195   switch (prop_id) {
196     case PROP_DEVICE:
197       g_free (src->device);
198       src->device = g_value_dup_string (value);
199       if (src->device == NULL) {
200         src->device = g_strdup (DEFAULT_PROP_DEVICE);
201       }
202       break;
203     case PROP_USE_DRIVER_TIMESTAMP:
204       GST_OBJECT_LOCK (src);
205       src->use_driver_timestamps = g_value_get_boolean (value);
206       GST_OBJECT_UNLOCK (src);
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211   }
212 }
213 
214 static void
gst_alsasrc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)215 gst_alsasrc_get_property (GObject * object, guint prop_id,
216     GValue * value, GParamSpec * pspec)
217 {
218   GstAlsaSrc *src;
219 
220   src = GST_ALSA_SRC (object);
221 
222   switch (prop_id) {
223     case PROP_DEVICE:
224       g_value_set_string (value, src->device);
225       break;
226     case PROP_DEVICE_NAME:
227       g_value_take_string (value,
228           gst_alsa_find_device_name (GST_OBJECT_CAST (src),
229               src->device, src->handle, SND_PCM_STREAM_CAPTURE));
230       break;
231     case PROP_CARD_NAME:
232       g_value_take_string (value,
233           gst_alsa_find_card_name (GST_OBJECT_CAST (src),
234               src->device, SND_PCM_STREAM_CAPTURE));
235       break;
236     case PROP_USE_DRIVER_TIMESTAMP:
237       GST_OBJECT_LOCK (src);
238       g_value_set_boolean (value, src->use_driver_timestamps);
239       GST_OBJECT_UNLOCK (src);
240       break;
241     default:
242       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243       break;
244   }
245 }
246 
247 static GstStateChangeReturn
gst_alsasrc_change_state(GstElement * element,GstStateChange transition)248 gst_alsasrc_change_state (GstElement * element, GstStateChange transition)
249 {
250   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
251   GstAlsaSrc *alsa = GST_ALSA_SRC (element);
252   GstClock *clk;
253 
254   switch (transition) {
255       /* show the compiler that we care */
256     case GST_STATE_CHANGE_NULL_TO_READY:
257     case GST_STATE_CHANGE_READY_TO_PAUSED:
258     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
259     case GST_STATE_CHANGE_PAUSED_TO_READY:
260     case GST_STATE_CHANGE_READY_TO_NULL:
261     case GST_STATE_CHANGE_NULL_TO_NULL:
262     case GST_STATE_CHANGE_READY_TO_READY:
263     case GST_STATE_CHANGE_PAUSED_TO_PAUSED:
264     case GST_STATE_CHANGE_PLAYING_TO_PLAYING:
265       break;
266     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
267       alsa->driver_timestamps = FALSE;
268 
269       clk = gst_element_get_clock (element);
270       if (clk != NULL) {
271         if (G_OBJECT_TYPE (clk) == GST_TYPE_SYSTEM_CLOCK) {
272           gint clocktype;
273           g_object_get (clk, "clock-type", &clocktype, NULL);
274           if (clocktype == GST_CLOCK_TYPE_MONOTONIC &&
275               alsa->use_driver_timestamps) {
276             GST_INFO ("Using driver timestamps !");
277             alsa->driver_timestamps = TRUE;
278           } else {
279             GST_INFO ("Not using driver timestamps !");
280             alsa->driver_timestamps = FALSE;
281           }
282         }
283 
284         gst_object_unref (clk);
285       }
286       break;
287   }
288   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
289 
290   return ret;
291 }
292 
293 static void
gst_alsasrc_init(GstAlsaSrc * alsasrc)294 gst_alsasrc_init (GstAlsaSrc * alsasrc)
295 {
296   GST_DEBUG_OBJECT (alsasrc, "initializing");
297 
298   alsasrc->device = g_strdup (DEFAULT_PROP_DEVICE);
299   alsasrc->cached_caps = NULL;
300   alsasrc->driver_timestamps = FALSE;
301   alsasrc->use_driver_timestamps = DEFAULT_PROP_USE_DRIVER_TIMESTAMP;
302 
303   g_mutex_init (&alsasrc->alsa_lock);
304 }
305 
306 #define CHECK(call, error) \
307 G_STMT_START {                  \
308 if ((err = call) < 0)           \
309   goto error;                   \
310 } G_STMT_END;
311 
312 
313 static GstCaps *
gst_alsasrc_getcaps(GstBaseSrc * bsrc,GstCaps * filter)314 gst_alsasrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
315 {
316   GstElementClass *element_class;
317   GstPadTemplate *pad_template;
318   GstAlsaSrc *src;
319   GstCaps *caps, *templ_caps;
320 
321   src = GST_ALSA_SRC (bsrc);
322 
323   if (src->handle == NULL) {
324     GST_DEBUG_OBJECT (src, "device not open, using template caps");
325     return GST_BASE_SRC_CLASS (parent_class)->get_caps (bsrc, filter);
326   }
327 
328   if (src->cached_caps) {
329     GST_LOG_OBJECT (src, "Returning cached caps");
330     if (filter)
331       return gst_caps_intersect_full (filter, src->cached_caps,
332           GST_CAPS_INTERSECT_FIRST);
333     else
334       return gst_caps_ref (src->cached_caps);
335   }
336 
337   element_class = GST_ELEMENT_GET_CLASS (src);
338   pad_template = gst_element_class_get_pad_template (element_class, "src");
339   g_return_val_if_fail (pad_template != NULL, NULL);
340 
341   templ_caps = gst_pad_template_get_caps (pad_template);
342   GST_INFO_OBJECT (src, "template caps %" GST_PTR_FORMAT, templ_caps);
343 
344   caps = gst_alsa_probe_supported_formats (GST_OBJECT (src),
345       src->device, src->handle, templ_caps);
346   gst_caps_unref (templ_caps);
347 
348   if (caps) {
349     src->cached_caps = gst_caps_ref (caps);
350   }
351 
352   GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps);
353 
354   if (filter) {
355     GstCaps *intersection;
356 
357     intersection =
358         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
359     gst_caps_unref (caps);
360     return intersection;
361   } else {
362     return caps;
363   }
364 }
365 
366 static int
set_hwparams(GstAlsaSrc * alsa)367 set_hwparams (GstAlsaSrc * alsa)
368 {
369   guint rrate;
370   gint err = 0;
371   snd_pcm_hw_params_t *params, *params_copy;
372 
373   snd_pcm_hw_params_malloc (&params);
374   snd_pcm_hw_params_malloc (&params_copy);
375 
376   /* choose all parameters */
377   CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config);
378   /* set the interleaved read/write format */
379   CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access),
380       wrong_access);
381   /* set the sample format */
382   CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format),
383       no_sample_format);
384   /* set the count of channels */
385   CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels),
386       no_channels);
387   /* set the stream rate */
388   rrate = alsa->rate;
389   CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL),
390       no_rate);
391   if (rrate != alsa->rate)
392     goto rate_match;
393 
394 #ifndef GST_DISABLE_GST_DEBUG
395   /* get and dump some limits */
396   {
397     guint min, max;
398 
399     snd_pcm_hw_params_get_buffer_time_min (params, &min, NULL);
400     snd_pcm_hw_params_get_buffer_time_max (params, &max, NULL);
401 
402     GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u",
403         alsa->buffer_time, min, max);
404 
405     snd_pcm_hw_params_get_period_time_min (params, &min, NULL);
406     snd_pcm_hw_params_get_period_time_max (params, &max, NULL);
407 
408     GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u",
409         alsa->period_time, min, max);
410 
411     snd_pcm_hw_params_get_periods_min (params, &min, NULL);
412     snd_pcm_hw_params_get_periods_max (params, &max, NULL);
413 
414     GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max);
415   }
416 #endif
417   /* Keep a copy of initial params struct that can be used later */
418   snd_pcm_hw_params_copy (params_copy, params);
419   /* Following pulseaudio's approach in
420    * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/commit/557c4295107dc7374c850b0bd5331dd35e8fdd0f
421    * we'll try various configuration to set the buffer time and period time as some
422    * driver can be picky on the order of the calls.
423    */
424   if (alsa->period_time != -1 && alsa->buffer_time != -1) {
425     if ((snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
426                 &alsa->period_time, NULL) >= 0)
427         && (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
428                 &alsa->buffer_time, NULL) >= 0)) {
429       GST_DEBUG_OBJECT (alsa, "period time %u buffer time %u set correctly",
430           alsa->period_time, alsa->buffer_time);
431       goto success;
432     }
433     /* Try the new order with previous params struct as current one might
434        have partial settings from the order that was tried unsuccessfully */
435     snd_pcm_hw_params_copy (params, params_copy);
436     if ((snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
437                 &alsa->buffer_time, NULL) >= 0)
438         && (snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
439                 &alsa->period_time, NULL) >= 0)) {
440       GST_DEBUG_OBJECT (alsa, "buffer time %u period time %u set correctly",
441           alsa->buffer_time, alsa->period_time);
442       goto success;
443     }
444   }
445   if (alsa->period_time != -1) {
446     snd_pcm_hw_params_copy (params, params_copy);
447     /* set the period time only */
448     if ((snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
449                 &alsa->period_time, NULL) >= 0)) {
450       GST_DEBUG_OBJECT (alsa, "period time %u set correctly",
451           alsa->period_time);
452       goto success;
453     }
454   }
455   if (alsa->buffer_time != -1) {
456     snd_pcm_hw_params_copy (params, params_copy);
457     /* set the buffer time only */
458     if ((snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
459                 &alsa->buffer_time, NULL) >= 0)) {
460       GST_DEBUG_OBJECT (alsa, "buffer time %u set correctly",
461           alsa->buffer_time);
462       goto success;
463     }
464   }
465   /* Set nothing if all above failed */
466   snd_pcm_hw_params_copy (params, params_copy);
467   GST_DEBUG_OBJECT (alsa, "Not setting period time and buffer time");
468 
469 success:
470   /* write the parameters to device */
471   CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);
472   CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
473       buffer_size);
474   GST_DEBUG_OBJECT (alsa, "buffer size : %lu", alsa->buffer_size);
475   CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size,
476           NULL), period_size);
477   GST_DEBUG_OBJECT (alsa, "period size : %lu", alsa->period_size);
478 
479   goto exit;
480   /* ERRORS */
481 no_config:
482   {
483     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
484         ("Broken configuration for recording: no configurations available: %s",
485             snd_strerror (err)));
486     goto exit;
487   }
488 wrong_access:
489   {
490     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
491         ("Access type not available for recording: %s", snd_strerror (err)));
492     goto exit;
493   }
494 no_sample_format:
495   {
496     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
497         ("Sample format not available for recording: %s", snd_strerror (err)));
498     goto exit;
499   }
500 no_channels:
501   {
502     gchar *msg = NULL;
503 
504     if ((alsa->channels) == 1)
505       msg = g_strdup (_("Could not open device for recording in mono mode."));
506     if ((alsa->channels) == 2)
507       msg = g_strdup (_("Could not open device for recording in stereo mode."));
508     if ((alsa->channels) > 2)
509       msg =
510           g_strdup_printf (_
511           ("Could not open device for recording in %d-channel mode"),
512           alsa->channels);
513     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, ("%s", msg),
514         ("%s", snd_strerror (err)));
515     g_free (msg);
516     goto exit;
517   }
518 no_rate:
519   {
520     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
521         ("Rate %iHz not available for recording: %s",
522             alsa->rate, snd_strerror (err)));
523     goto exit;
524   }
525 rate_match:
526   {
527     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
528         ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err));
529     err = -EINVAL;
530     goto exit;
531   }
532 buffer_size:
533   {
534     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
535         ("Unable to get buffer size for recording: %s", snd_strerror (err)));
536     goto exit;
537   }
538 period_size:
539   {
540     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
541         ("Unable to get period size for recording: %s", snd_strerror (err)));
542     goto exit;
543   }
544 set_hw_params:
545   {
546     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
547         ("Unable to set hw params for recording: %s", snd_strerror (err)));
548   }
549 exit:
550   {
551     snd_pcm_hw_params_free (params);
552     snd_pcm_hw_params_free (params_copy);
553     return err;
554   }
555 }
556 
557 static int
set_swparams(GstAlsaSrc * alsa)558 set_swparams (GstAlsaSrc * alsa)
559 {
560   int err;
561   snd_pcm_sw_params_t *params;
562 
563   snd_pcm_sw_params_malloc (&params);
564 
565   /* get the current swparams */
566   CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
567   /* allow the transfer when at least period_size samples can be processed */
568   CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
569           alsa->period_size), set_avail);
570   /* start the transfer on first read */
571   CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
572           0), start_threshold);
573   /* use monotonic timestamping */
574   CHECK (snd_pcm_sw_params_set_tstamp_mode (alsa->handle, params,
575           SND_PCM_TSTAMP_MMAP), tstamp_mode);
576 
577 #if GST_CHECK_ALSA_VERSION(1,0,16)
578   /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
579 #else
580   /* align all transfers to 1 sample */
581   CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
582 #endif
583 
584   /* write the parameters to the recording device */
585   CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);
586 
587   snd_pcm_sw_params_free (params);
588   return 0;
589 
590   /* ERRORS */
591 no_config:
592   {
593     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
594         ("Unable to determine current swparams for playback: %s",
595             snd_strerror (err)));
596     snd_pcm_sw_params_free (params);
597     return err;
598   }
599 start_threshold:
600   {
601     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
602         ("Unable to set start threshold mode for playback: %s",
603             snd_strerror (err)));
604     snd_pcm_sw_params_free (params);
605     return err;
606   }
607 set_avail:
608   {
609     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
610         ("Unable to set avail min for playback: %s", snd_strerror (err)));
611     snd_pcm_sw_params_free (params);
612     return err;
613   }
614 tstamp_mode:
615   {
616     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
617         ("Unable to set tstamp mode for playback: %s", snd_strerror (err)));
618     snd_pcm_sw_params_free (params);
619     return err;
620   }
621 #if !GST_CHECK_ALSA_VERSION(1,0,16)
622 set_align:
623   {
624     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
625         ("Unable to set transfer align for playback: %s", snd_strerror (err)));
626     snd_pcm_sw_params_free (params);
627     return err;
628   }
629 #endif
630 set_sw_params:
631   {
632     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
633         ("Unable to set sw params for playback: %s", snd_strerror (err)));
634     snd_pcm_sw_params_free (params);
635     return err;
636   }
637 }
638 
639 static gboolean
alsasrc_parse_spec(GstAlsaSrc * alsa,GstAudioRingBufferSpec * spec)640 alsasrc_parse_spec (GstAlsaSrc * alsa, GstAudioRingBufferSpec * spec)
641 {
642   switch (spec->type) {
643     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW:
644       switch (GST_AUDIO_INFO_FORMAT (&spec->info)) {
645         case GST_AUDIO_FORMAT_U8:
646           alsa->format = SND_PCM_FORMAT_U8;
647           break;
648         case GST_AUDIO_FORMAT_S8:
649           alsa->format = SND_PCM_FORMAT_S8;
650           break;
651         case GST_AUDIO_FORMAT_S16LE:
652           alsa->format = SND_PCM_FORMAT_S16_LE;
653           break;
654         case GST_AUDIO_FORMAT_S16BE:
655           alsa->format = SND_PCM_FORMAT_S16_BE;
656           break;
657         case GST_AUDIO_FORMAT_U16LE:
658           alsa->format = SND_PCM_FORMAT_U16_LE;
659           break;
660         case GST_AUDIO_FORMAT_U16BE:
661           alsa->format = SND_PCM_FORMAT_U16_BE;
662           break;
663         case GST_AUDIO_FORMAT_S24_32LE:
664           alsa->format = SND_PCM_FORMAT_S24_LE;
665           break;
666         case GST_AUDIO_FORMAT_S24_32BE:
667           alsa->format = SND_PCM_FORMAT_S24_BE;
668           break;
669         case GST_AUDIO_FORMAT_U24_32LE:
670           alsa->format = SND_PCM_FORMAT_U24_LE;
671           break;
672         case GST_AUDIO_FORMAT_U24_32BE:
673           alsa->format = SND_PCM_FORMAT_U24_BE;
674           break;
675         case GST_AUDIO_FORMAT_S32LE:
676           alsa->format = SND_PCM_FORMAT_S32_LE;
677           break;
678         case GST_AUDIO_FORMAT_S32BE:
679           alsa->format = SND_PCM_FORMAT_S32_BE;
680           break;
681         case GST_AUDIO_FORMAT_U32LE:
682           alsa->format = SND_PCM_FORMAT_U32_LE;
683           break;
684         case GST_AUDIO_FORMAT_U32BE:
685           alsa->format = SND_PCM_FORMAT_U32_BE;
686           break;
687         case GST_AUDIO_FORMAT_S24LE:
688           alsa->format = SND_PCM_FORMAT_S24_3LE;
689           break;
690         case GST_AUDIO_FORMAT_S24BE:
691           alsa->format = SND_PCM_FORMAT_S24_3BE;
692           break;
693         case GST_AUDIO_FORMAT_U24LE:
694           alsa->format = SND_PCM_FORMAT_U24_3LE;
695           break;
696         case GST_AUDIO_FORMAT_U24BE:
697           alsa->format = SND_PCM_FORMAT_U24_3BE;
698           break;
699         case GST_AUDIO_FORMAT_S20LE:
700           alsa->format = SND_PCM_FORMAT_S20_3LE;
701           break;
702         case GST_AUDIO_FORMAT_S20BE:
703           alsa->format = SND_PCM_FORMAT_S20_3BE;
704           break;
705         case GST_AUDIO_FORMAT_U20LE:
706           alsa->format = SND_PCM_FORMAT_U20_3LE;
707           break;
708         case GST_AUDIO_FORMAT_U20BE:
709           alsa->format = SND_PCM_FORMAT_U20_3BE;
710           break;
711         case GST_AUDIO_FORMAT_S18LE:
712           alsa->format = SND_PCM_FORMAT_S18_3LE;
713           break;
714         case GST_AUDIO_FORMAT_S18BE:
715           alsa->format = SND_PCM_FORMAT_S18_3BE;
716           break;
717         case GST_AUDIO_FORMAT_U18LE:
718           alsa->format = SND_PCM_FORMAT_U18_3LE;
719           break;
720         case GST_AUDIO_FORMAT_U18BE:
721           alsa->format = SND_PCM_FORMAT_U18_3BE;
722           break;
723         case GST_AUDIO_FORMAT_F32LE:
724           alsa->format = SND_PCM_FORMAT_FLOAT_LE;
725           break;
726         case GST_AUDIO_FORMAT_F32BE:
727           alsa->format = SND_PCM_FORMAT_FLOAT_BE;
728           break;
729         case GST_AUDIO_FORMAT_F64LE:
730           alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
731           break;
732         case GST_AUDIO_FORMAT_F64BE:
733           alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
734           break;
735         default:
736           goto error;
737       }
738       break;
739     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW:
740       alsa->format = SND_PCM_FORMAT_A_LAW;
741       break;
742     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW:
743       alsa->format = SND_PCM_FORMAT_MU_LAW;
744       break;
745     default:
746       goto error;
747 
748   }
749   alsa->rate = GST_AUDIO_INFO_RATE (&spec->info);
750   alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
751   alsa->buffer_time = spec->buffer_time;
752   alsa->period_time = spec->latency_time;
753   alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
754 
755   if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9)
756     gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
757         (alsa)->ringbuffer, alsa_position[alsa->channels - 1]);
758 
759   return TRUE;
760 
761   /* ERRORS */
762 error:
763   {
764     return FALSE;
765   }
766 }
767 
768 static gboolean
gst_alsasrc_open(GstAudioSrc * asrc)769 gst_alsasrc_open (GstAudioSrc * asrc)
770 {
771   GstAlsaSrc *alsa;
772   gint err;
773 
774   alsa = GST_ALSA_SRC (asrc);
775 
776   CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_CAPTURE,
777           (alsa->driver_timestamps) ? 0 : SND_PCM_NONBLOCK), open_error);
778 
779   return TRUE;
780 
781   /* ERRORS */
782 open_error:
783   {
784     if (err == -EBUSY) {
785       GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY,
786           (_("Could not open audio device for recording. "
787                   "Device is being used by another application.")),
788           ("Device '%s' is busy", alsa->device));
789     } else {
790       GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
791           (_("Could not open audio device for recording.")),
792           ("Recording open error on device '%s': %s", alsa->device,
793               snd_strerror (err)));
794     }
795     return FALSE;
796   }
797 }
798 
799 static gboolean
gst_alsasrc_prepare(GstAudioSrc * asrc,GstAudioRingBufferSpec * spec)800 gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
801 {
802   GstAlsaSrc *alsa;
803   gint err;
804 
805   alsa = GST_ALSA_SRC (asrc);
806 
807   if (!alsasrc_parse_spec (alsa, spec))
808     goto spec_parse;
809 
810   CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);
811 
812   CHECK (set_hwparams (alsa), hw_params_failed);
813   CHECK (set_swparams (alsa), sw_params_failed);
814   CHECK (snd_pcm_prepare (alsa->handle), prepare_failed);
815 
816   alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
817   spec->segsize = alsa->period_size * alsa->bpf;
818   spec->segtotal = alsa->buffer_size / alsa->period_size;
819 
820   {
821     snd_output_t *out_buf = NULL;
822     char *msg = NULL;
823 
824     snd_output_buffer_open (&out_buf);
825     snd_pcm_dump_hw_setup (alsa->handle, out_buf);
826     snd_output_buffer_string (out_buf, &msg);
827     GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
828     snd_output_close (out_buf);
829     snd_output_buffer_open (&out_buf);
830     snd_pcm_dump_sw_setup (alsa->handle, out_buf);
831     snd_output_buffer_string (out_buf, &msg);
832     GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
833     snd_output_close (out_buf);
834   }
835 
836 #ifdef SND_CHMAP_API_VERSION
837   alsa_detect_channels_mapping (GST_OBJECT (alsa), alsa->handle, spec,
838       alsa->channels, GST_AUDIO_BASE_SRC (alsa)->ringbuffer);
839 #endif /* SND_CHMAP_API_VERSION */
840 
841   return TRUE;
842 
843   /* ERRORS */
844 spec_parse:
845   {
846     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
847         ("Error parsing spec"));
848     return FALSE;
849   }
850 non_block:
851   {
852     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
853         ("Could not set device to blocking: %s", snd_strerror (err)));
854     return FALSE;
855   }
856 hw_params_failed:
857   {
858     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
859         ("Setting of hwparams failed: %s", snd_strerror (err)));
860     return FALSE;
861   }
862 sw_params_failed:
863   {
864     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
865         ("Setting of swparams failed: %s", snd_strerror (err)));
866     return FALSE;
867   }
868 prepare_failed:
869   {
870     GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
871         ("Prepare failed: %s", snd_strerror (err)));
872     return FALSE;
873   }
874 }
875 
876 static gboolean
gst_alsasrc_unprepare(GstAudioSrc * asrc)877 gst_alsasrc_unprepare (GstAudioSrc * asrc)
878 {
879   GstAlsaSrc *alsa;
880 
881   alsa = GST_ALSA_SRC (asrc);
882 
883   snd_pcm_drop (alsa->handle);
884   snd_pcm_hw_free (alsa->handle);
885   snd_pcm_nonblock (alsa->handle, 1);
886 
887   return TRUE;
888 }
889 
890 static gboolean
gst_alsasrc_close(GstAudioSrc * asrc)891 gst_alsasrc_close (GstAudioSrc * asrc)
892 {
893   GstAlsaSrc *alsa = GST_ALSA_SRC (asrc);
894 
895   snd_pcm_close (alsa->handle);
896   alsa->handle = NULL;
897 
898   gst_caps_replace (&alsa->cached_caps, NULL);
899 
900   return TRUE;
901 }
902 
903 /*
904  *   Underrun and suspend recovery
905  */
906 static gint
xrun_recovery(GstAlsaSrc * alsa,snd_pcm_t * handle,gint err)907 xrun_recovery (GstAlsaSrc * alsa, snd_pcm_t * handle, gint err)
908 {
909   GST_WARNING_OBJECT (alsa, "xrun recovery %d: %s", err, g_strerror (-err));
910 
911   if (err == -EPIPE) {          /* under-run */
912     err = snd_pcm_prepare (handle);
913     if (err < 0)
914       GST_WARNING_OBJECT (alsa,
915           "Can't recover from underrun, prepare failed: %s",
916           snd_strerror (err));
917     return 0;
918   } else if (err == -ESTRPIPE) {
919     while ((err = snd_pcm_resume (handle)) == -EAGAIN)
920       g_usleep (100);           /* wait until the suspend flag is released */
921 
922     if (err < 0) {
923       err = snd_pcm_prepare (handle);
924       if (err < 0)
925         GST_WARNING_OBJECT (alsa,
926             "Can't recover from suspend, prepare failed: %s",
927             snd_strerror (err));
928     }
929     return 0;
930   }
931   return err;
932 }
933 
934 static GstClockTime
gst_alsasrc_get_timestamp(GstAlsaSrc * asrc)935 gst_alsasrc_get_timestamp (GstAlsaSrc * asrc)
936 {
937   snd_pcm_status_t *status;
938   snd_htimestamp_t tstamp;
939   GstClockTime timestamp;
940   snd_pcm_uframes_t avail;
941   gint err = -EPIPE;
942 
943   if (G_UNLIKELY (!asrc)) {
944     GST_ERROR_OBJECT (asrc, "No alsa handle created yet !");
945     return GST_CLOCK_TIME_NONE;
946   }
947 
948   if (G_UNLIKELY (snd_pcm_status_malloc (&status) != 0)) {
949     GST_ERROR_OBJECT (asrc, "snd_pcm_status_malloc failed");
950     return GST_CLOCK_TIME_NONE;
951   }
952 
953   if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) {
954     GST_ERROR_OBJECT (asrc, "snd_pcm_status failed");
955     return GST_CLOCK_TIME_NONE;
956   }
957 
958   /* in case an xrun condition has occurred we need to handle this */
959   if (snd_pcm_status_get_state (status) != SND_PCM_STATE_RUNNING) {
960     if (xrun_recovery (asrc, asrc->handle, err) < 0) {
961       GST_WARNING_OBJECT (asrc, "Could not recover from xrun condition !");
962     }
963     /* reload the status alsa status object, since recovery made it invalid */
964     if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) {
965       GST_ERROR_OBJECT (asrc, "snd_pcm_status failed");
966     }
967   }
968 
969   /* get high resolution time stamp from driver */
970   snd_pcm_status_get_htstamp (status, &tstamp);
971 
972   if (tstamp.tv_sec == 0 && tstamp.tv_nsec == 0)
973     return GST_CLOCK_TIME_NONE;
974 
975   timestamp = GST_TIMESPEC_TO_TIME (tstamp);
976 
977   /* max available frames sets the depth of the buffer */
978   avail = snd_pcm_status_get_avail (status);
979 
980   /* calculate the timestamp of the next sample to be read */
981   timestamp -= gst_util_uint64_scale_int (avail, GST_SECOND, asrc->rate);
982 
983   /* compensate for the fact that we really need the timestamp of the
984    * previously read data segment */
985   timestamp -= asrc->period_time * 1000;
986 
987   snd_pcm_status_free (status);
988 
989   GST_LOG_OBJECT (asrc, "ALSA timestamp : %" GST_TIME_FORMAT
990       ", delay %lu", GST_TIME_ARGS (timestamp), avail);
991 
992   return timestamp;
993 }
994 
995 static guint
gst_alsasrc_read(GstAudioSrc * asrc,gpointer data,guint length,GstClockTime * timestamp)996 gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length,
997     GstClockTime * timestamp)
998 {
999   GstAlsaSrc *alsa;
1000   gint err;
1001   gint cptr;
1002   guint8 *ptr = data;
1003 
1004   alsa = GST_ALSA_SRC (asrc);
1005 
1006   cptr = length / alsa->bpf;
1007 
1008   GST_ALSA_SRC_LOCK (asrc);
1009   while (cptr > 0) {
1010     if ((err = snd_pcm_readi (alsa->handle, ptr, cptr)) < 0) {
1011       if (err == -EAGAIN) {
1012         GST_DEBUG_OBJECT (asrc, "Read error: %s", snd_strerror (err));
1013         continue;
1014       } else if (err == -ENODEV) {
1015         goto device_disappeared;
1016       } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
1017         goto read_error;
1018       }
1019       continue;
1020     }
1021 
1022     ptr += snd_pcm_frames_to_bytes (alsa->handle, err);
1023     cptr -= err;
1024   }
1025   GST_ALSA_SRC_UNLOCK (asrc);
1026 
1027   /* if driver timestamps are enabled we need to return this here */
1028   if (alsa->driver_timestamps && timestamp)
1029     *timestamp = gst_alsasrc_get_timestamp (alsa);
1030 
1031   return length - (cptr * alsa->bpf);
1032 
1033 read_error:
1034   {
1035     GST_ALSA_SRC_UNLOCK (asrc);
1036     return length;              /* skip one period */
1037   }
1038 device_disappeared:
1039   {
1040     GST_ELEMENT_ERROR (asrc, RESOURCE, READ,
1041         (_("Error recording from audio device. "
1042                 "The device has been disconnected.")), (NULL));
1043     GST_ALSA_SRC_UNLOCK (asrc);
1044     return (guint) - 1;
1045   }
1046 }
1047 
1048 static guint
gst_alsasrc_delay(GstAudioSrc * asrc)1049 gst_alsasrc_delay (GstAudioSrc * asrc)
1050 {
1051   GstAlsaSrc *alsa;
1052   snd_pcm_sframes_t delay;
1053   int res;
1054 
1055   alsa = GST_ALSA_SRC (asrc);
1056 
1057   res = snd_pcm_delay (alsa->handle, &delay);
1058   if (G_UNLIKELY (res < 0)) {
1059     GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res);
1060     delay = 0;
1061   }
1062 
1063   return CLAMP (delay, 0, alsa->buffer_size);
1064 }
1065 
1066 static void
gst_alsasrc_reset(GstAudioSrc * asrc)1067 gst_alsasrc_reset (GstAudioSrc * asrc)
1068 {
1069   GstAlsaSrc *alsa;
1070   gint err;
1071 
1072   alsa = GST_ALSA_SRC (asrc);
1073 
1074   GST_ALSA_SRC_LOCK (asrc);
1075   GST_DEBUG_OBJECT (alsa, "drop");
1076   CHECK (snd_pcm_drop (alsa->handle), drop_error);
1077   GST_DEBUG_OBJECT (alsa, "prepare");
1078   CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
1079   GST_DEBUG_OBJECT (alsa, "reset done");
1080   GST_ALSA_SRC_UNLOCK (asrc);
1081 
1082   return;
1083 
1084   /* ERRORS */
1085 drop_error:
1086   {
1087     GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s",
1088         snd_strerror (err));
1089     GST_ALSA_SRC_UNLOCK (asrc);
1090     return;
1091   }
1092 prepare_error:
1093   {
1094     GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s",
1095         snd_strerror (err));
1096     GST_ALSA_SRC_UNLOCK (asrc);
1097     return;
1098   }
1099 }
1100