source: trunk/src/3rdparty/phonon/gstreamer/alsasink2.c

Last change on this file was 2, checked in by Dmitry A. Kuminov, 17 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 49.3 KB
Line 
1/* GStreamer
2 * Copyright (C) 2001 CodeFactory AB
3 * Copyright (C) 2001 Thomas Nyberg <[email protected]>
4 * Copyright (C) 2001-2002 Andy Wingo <[email protected]>
5 * Copyright (C) 2003 Benjamin Otte <[email protected]>
6 * Copyright (C) 2005 Wim Taymans <[email protected]>
7 * Copyright (C) 2005, 2006 Tim-Philipp MÃŒller <tim centricular net>
8 * Copyright (C) 2008 Matthias Kretz <[email protected]>
9 *
10 * gstalsasink2.c:
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26/**
27 * SECTION:element-alsasink2
28 * @short_description: play audio to an ALSA device
29 * @see_also: alsasrc, alsamixer
30 *
31 * <refsect2>
32 * <para>
33 * This element renders raw audio samples using the ALSA api.
34 * </para>
35 * <title>Example pipelines</title>
36 * <para>
37 * Play an Ogg/Vorbis file.
38 * </para>
39 * <programlisting>
40 * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! alsasink2
41 * </programlisting>
42 * </refsect2>
43 *
44 * Last reviewed on 2006-03-01 (0.10.4)
45 */
46
47#define _XOPEN_SOURCE 600
48
49#include <sys/ioctl.h>
50#include <fcntl.h>
51#include <errno.h>
52#include <unistd.h>
53#include <string.h>
54#include <getopt.h>
55#include <alsa/asoundlib.h>
56
57#include "alsasink2.h"
58
59#include <gst/interfaces/propertyprobe.h>
60#include <gst/audio/multichannel.h>
61
62#define _(text) (text)
63
64#define GST_CHECK_ALSA_VERSION(major,minor,micro) \
65 (SND_LIB_MAJOR > (major) || \
66 (SND_LIB_MAJOR == (major) && SND_LIB_MINOR > (minor)) || \
67 (SND_LIB_MAJOR == (major) && SND_LIB_MINOR == (minor) && \
68 SND_LIB_SUBMINOR >= (micro)))
69
70static const GList *
71gst_alsa_device_property_probe_get_properties (GstPropertyProbe * probe)
72{
73 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
74 static GList *list = NULL;
75
76 /* well, not perfect, but better than no locking at all.
77 * In the worst case we leak a list node, so who cares? */
78 GST_CLASS_LOCK (GST_OBJECT_CLASS (klass));
79
80 if (!list) {
81 GParamSpec *pspec;
82
83 pspec = g_object_class_find_property (klass, "device");
84 list = g_list_append (NULL, pspec);
85 }
86
87 GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass));
88
89 return list;
90}
91
92static GList *
93gst_alsa_get_device_list (snd_pcm_stream_t stream)
94{
95 snd_ctl_t *handle;
96 int card, err, dev;
97 snd_ctl_card_info_t *info;
98 snd_pcm_info_t *pcminfo;
99 gboolean mixer = (stream == ~0u);
100 GList *list = NULL;
101
102 if (stream == ~0u)
103 stream = 0;
104
105 snd_ctl_card_info_malloc (&info);
106 snd_pcm_info_malloc (&pcminfo);
107 card = -1;
108
109 if (snd_card_next (&card) < 0 || card < 0) {
110 /* no soundcard found */
111 return NULL;
112 }
113
114 while (card >= 0) {
115 gchar name[32];
116
117 g_snprintf (name, sizeof (name), "hw:%d", card);
118 if ((err = snd_ctl_open (&handle, name, 0)) < 0) {
119 goto next_card;
120 }
121 if ((err = snd_ctl_card_info (handle, info)) < 0) {
122 snd_ctl_close (handle);
123 goto next_card;
124 }
125
126 if (mixer) {
127 list = g_list_append (list, g_strdup (name));
128 } else {
129 g_snprintf (name, sizeof (name), "default:CARD=%d", card);
130 list = g_list_append (list, g_strdup (name));
131 dev = -1;
132 while (1) {
133 gchar *gst_device;
134
135 snd_ctl_pcm_next_device (handle, &dev);
136
137 if (dev < 0)
138 break;
139 snd_pcm_info_set_device (pcminfo, dev);
140 snd_pcm_info_set_subdevice (pcminfo, 0);
141 snd_pcm_info_set_stream (pcminfo, stream);
142 if ((err = snd_ctl_pcm_info (handle, pcminfo)) < 0) {
143 continue;
144 }
145
146 gst_device = g_strdup_printf ("hw:%d,%d", card, dev);
147 list = g_list_append (list, gst_device);
148 }
149 }
150 snd_ctl_close (handle);
151 next_card:
152 if (snd_card_next (&card) < 0) {
153 break;
154 }
155 }
156
157 snd_ctl_card_info_free (info);
158 snd_pcm_info_free (pcminfo);
159
160 return list;
161}
162
163static void
164gst_alsa_device_property_probe_probe_property (GstPropertyProbe * probe,
165 guint prop_id, const GParamSpec * pspec)
166{
167 if (!g_str_equal (pspec->name, "device")) {
168 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
169 }
170}
171
172static gboolean
173gst_alsa_device_property_probe_needs_probe (GstPropertyProbe * probe,
174 guint prop_id, const GParamSpec * pspec)
175{
176 /* don't cache probed data */
177 return TRUE;
178}
179
180static GValueArray *
181gst_alsa_device_property_probe_get_values (GstPropertyProbe * probe,
182 guint prop_id, const GParamSpec * pspec)
183{
184 GstElementClass *klass;
185 const GList *templates;
186 snd_pcm_stream_t mode = -1;
187 GValueArray *array;
188 GValue value = { 0, };
189 GList *l, *list;
190
191 if (!g_str_equal (pspec->name, "device")) {
192 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
193 return NULL;
194 }
195
196 klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (probe));
197
198 /* I'm pretty sure ALSA has a good way to do this. However, their cool
199 * auto-generated documentation is pretty much useless if you try to
200 * do function-wise look-ups. */
201 /* we assume one pad template at max [zero=mixer] */
202 templates = gst_element_class_get_pad_template_list (klass);
203 if (templates) {
204 if (GST_PAD_TEMPLATE_DIRECTION (templates->data) == GST_PAD_SRC)
205 mode = SND_PCM_STREAM_CAPTURE;
206 else
207 mode = SND_PCM_STREAM_PLAYBACK;
208 }
209
210 list = gst_alsa_get_device_list (mode);
211
212 if (list == NULL) {
213 GST_LOG_OBJECT (probe, "No devices found");
214 return NULL;
215 }
216
217 array = g_value_array_new (g_list_length (list));
218 g_value_init (&value, G_TYPE_STRING);
219 for (l = list; l != NULL; l = l->next) {
220 GST_LOG_OBJECT (probe, "Found device: %s", (gchar *) l->data);
221 g_value_take_string (&value, (gchar *) l->data);
222 l->data = NULL;
223 g_value_array_append (array, &value);
224 }
225 g_value_unset (&value);
226 g_list_free (list);
227
228 return array;
229}
230
231static void
232gst_alsa_property_probe_interface_init (GstPropertyProbeInterface * iface)
233{
234 iface->get_properties = gst_alsa_device_property_probe_get_properties;
235 iface->probe_property = gst_alsa_device_property_probe_probe_property;
236 iface->needs_probe = gst_alsa_device_property_probe_needs_probe;
237 iface->get_values = gst_alsa_device_property_probe_get_values;
238}
239
240static void
241gst_alsa_type_add_device_property_probe_interface (GType type)
242{
243 static const GInterfaceInfo probe_iface_info = {
244 (GInterfaceInitFunc) gst_alsa_property_probe_interface_init,
245 NULL,
246 NULL,
247 };
248
249 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
250 &probe_iface_info);
251}
252
253static GstCaps *
254gst_alsa_detect_rates (GstObject * obj, snd_pcm_hw_params_t * hw_params,
255 GstCaps * in_caps)
256{
257 GstCaps *caps;
258 guint min, max;
259 gint err, dir, min_rate, max_rate;
260 guint i;
261
262 GST_LOG_OBJECT (obj, "probing sample rates ...");
263
264 if ((err = snd_pcm_hw_params_get_rate_min (hw_params, &min, &dir)) < 0)
265 goto min_rate_err;
266
267 if ((err = snd_pcm_hw_params_get_rate_max (hw_params, &max, &dir)) < 0)
268 goto max_rate_err;
269
270 min_rate = min;
271 max_rate = max;
272
273 if (min_rate < 4000)
274 min_rate = 4000; /* random 'sensible minimum' */
275
276 if (max_rate <= 0)
277 max_rate = G_MAXINT; /* or maybe just use 192400 or so? */
278 else if (max_rate > 0 && max_rate < 4000)
279 max_rate = MAX (4000, min_rate);
280
281 GST_DEBUG_OBJECT (obj, "Min. rate = %u (%d)", min_rate, min);
282 GST_DEBUG_OBJECT (obj, "Max. rate = %u (%d)", max_rate, max);
283
284 caps = gst_caps_make_writable (in_caps);
285
286 for (i = 0; i < gst_caps_get_size (caps); ++i) {
287 GstStructure *s;
288
289 s = gst_caps_get_structure (caps, i);
290 if (min_rate == max_rate) {
291 gst_structure_set (s, "rate", G_TYPE_INT, min_rate, NULL);
292 } else {
293 gst_structure_set (s, "rate", GST_TYPE_INT_RANGE,
294 min_rate, max_rate, NULL);
295 }
296 }
297
298 return caps;
299
300 /* ERRORS */
301min_rate_err:
302 {
303 GST_ERROR_OBJECT (obj, "failed to query minimum sample rate: %s",
304 snd_strerror (err));
305 gst_caps_unref (in_caps);
306 return NULL;
307 }
308max_rate_err:
309 {
310 GST_ERROR_OBJECT (obj, "failed to query maximum sample rate: %s",
311 snd_strerror (err));
312 gst_caps_unref (in_caps);
313 return NULL;
314 }
315}
316
317static const struct
318{
319 const int width;
320 const int depth;
321 const int sformat;
322 const int uformat;
323} pcmformats[] = {
324 {
325 8, 8, SND_PCM_FORMAT_S8, SND_PCM_FORMAT_U8}, {
326 16, 16, SND_PCM_FORMAT_S16, SND_PCM_FORMAT_U16}, {
327 32, 24, SND_PCM_FORMAT_S24, SND_PCM_FORMAT_U24}, {
328#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) /* no endian-unspecific enum available */
329 24, 24, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_U24_3LE}, {
330#else
331 24, 24, SND_PCM_FORMAT_S24_3BE, SND_PCM_FORMAT_U24_3BE}, {
332#endif
333 32, 32, SND_PCM_FORMAT_S32, SND_PCM_FORMAT_U32}
334};
335
336static GstCaps *
337gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params,
338 GstCaps * in_caps)
339{
340 snd_pcm_format_mask_t *mask;
341 GstStructure *s;
342 GstCaps *caps;
343 guint i;
344
345 snd_pcm_format_mask_malloc (&mask);
346 snd_pcm_hw_params_get_format_mask (hw_params, mask);
347
348 caps = gst_caps_new_empty ();
349
350 for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
351 GstStructure *scopy;
352 guint w;
353 gint width = 0, depth = 0;
354
355 s = gst_caps_get_structure (in_caps, i);
356 if (!gst_structure_has_name (s, "audio/x-raw-int")) {
357 GST_WARNING_OBJECT (obj, "skipping non-int format");
358 continue;
359 }
360 if (!gst_structure_get_int (s, "width", &width) ||
361 !gst_structure_get_int (s, "depth", &depth))
362 continue;
363 if (width == 0 || (width % 8) != 0)
364 continue; /* Only full byte widths are valid */
365 for (w = 0; w < G_N_ELEMENTS (pcmformats); w++)
366 if (pcmformats[w].width == width && pcmformats[w].depth == depth)
367 break;
368 if (w == G_N_ELEMENTS (pcmformats))
369 continue; /* Unknown format */
370
371 if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat) &&
372 snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) {
373 /* template contains { true, false } or just one, leave it as it is */
374 scopy = gst_structure_copy (s);
375 } else if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat)) {
376 scopy = gst_structure_copy (s);
377 gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
378 } else if (snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) {
379 scopy = gst_structure_copy (s);
380 gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
381 } else {
382 scopy = NULL;
383 }
384 if (scopy) {
385 if (width > 8) {
386 /* TODO: proper endianness detection, for now it's CPU endianness only */
387 gst_structure_set (scopy, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
388 }
389 gst_caps_append_structure (caps, scopy);
390 }
391 }
392
393 snd_pcm_format_mask_free (mask);
394 gst_caps_unref (in_caps);
395 return caps;
396}
397
398/* we don't have channel mappings for more than this many channels */
399#define GST_ALSA_MAX_CHANNELS 8
400
401static GstStructure *
402get_channel_free_structure (const GstStructure * in_structure)
403{
404 GstStructure *s = gst_structure_copy (in_structure);
405
406 gst_structure_remove_field (s, "channels");
407 return s;
408}
409
410static void
411caps_add_channel_configuration (GstCaps * caps,
412 const GstStructure * in_structure, gint min_chans, gint max_chans)
413{
414 GstAudioChannelPosition pos[8] = {
415 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
416 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
417 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
418 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
419 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
420 GST_AUDIO_CHANNEL_POSITION_LFE,
421 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
422 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
423 };
424 GstStructure *s = NULL;
425 gint c;
426
427 if (min_chans == max_chans && max_chans <= 2) {
428 s = get_channel_free_structure (in_structure);
429 gst_structure_set (s, "channels", G_TYPE_INT, max_chans, NULL);
430 gst_caps_append_structure (caps, s);
431 return;
432 }
433
434 g_assert (min_chans >= 1);
435
436 /* mono and stereo don't need channel configurations */
437 if (min_chans == 2) {
438 s = get_channel_free_structure (in_structure);
439 gst_structure_set (s, "channels", G_TYPE_INT, 2, NULL);
440 gst_caps_append_structure (caps, s);
441 } else if (min_chans == 1 && max_chans >= 2) {
442 s = get_channel_free_structure (in_structure);
443 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
444 gst_caps_append_structure (caps, s);
445 }
446
447 /* don't know whether to use 2.1 or 3.0 here - but I suspect
448 * alsa might work around that/fix it somehow. Can we tell alsa
449 * what our channel layout is like? */
450 if (max_chans >= 3 && min_chans <= 3) {
451 GstAudioChannelPosition pos_21[3] = {
452 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
453 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
454 GST_AUDIO_CHANNEL_POSITION_LFE
455 };
456
457 s = get_channel_free_structure (in_structure);
458 gst_structure_set (s, "channels", G_TYPE_INT, 3, NULL);
459 gst_audio_set_channel_positions (s, pos_21);
460 gst_caps_append_structure (caps, s);
461 }
462
463 /* everything else (4, 6, 8 channels) needs a channel layout */
464 for (c = MAX (4, min_chans); c <= 8; c += 2) {
465 if (max_chans >= c) {
466 s = get_channel_free_structure (in_structure);
467 gst_structure_set (s, "channels", G_TYPE_INT, c, NULL);
468 gst_audio_set_channel_positions (s, pos);
469 gst_caps_append_structure (caps, s);
470 }
471 }
472
473 for (c = MAX (9, min_chans); c <= max_chans; ++c) {
474 GstAudioChannelPosition *ch_layout;
475 gint i;
476
477 ch_layout = g_new (GstAudioChannelPosition, c);
478 for (i = 0; i < c; ++i) {
479 ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
480 }
481 s = get_channel_free_structure (in_structure);
482 gst_structure_set (s, "channels", G_TYPE_INT, c, NULL);
483 gst_audio_set_channel_positions (s, ch_layout);
484 gst_caps_append_structure (caps, s);
485 g_free (ch_layout);
486 }
487}
488
489static GstCaps *
490gst_alsa_detect_channels (GstObject * obj, snd_pcm_hw_params_t * hw_params,
491 GstCaps * in_caps)
492{
493 GstCaps *caps;
494 guint min, max;
495 gint min_chans, max_chans;
496 gint err;
497 guint i;
498
499 GST_LOG_OBJECT (obj, "probing channels ...");
500
501 if ((err = snd_pcm_hw_params_get_channels_min (hw_params, &min)) < 0)
502 goto min_chan_error;
503
504 if ((err = snd_pcm_hw_params_get_channels_max (hw_params, &max)) < 0)
505 goto max_chan_error;
506
507 /* note: the above functions may return (guint) -1 */
508 min_chans = min;
509 max_chans = max;
510
511 if (min_chans < 0) {
512 min_chans = 1;
513 max_chans = GST_ALSA_MAX_CHANNELS;
514 } else if (max_chans < 0) {
515 max_chans = GST_ALSA_MAX_CHANNELS;
516 }
517
518 if (min_chans > max_chans) {
519 gint temp;
520
521 GST_WARNING_OBJECT (obj, "minimum channels > maximum channels (%d > %d), "
522 "please fix your soundcard drivers", min, max);
523 temp = min_chans;
524 min_chans = max_chans;
525 max_chans = temp;
526 }
527
528 /* pro cards seem to return large numbers for min_channels */
529 if (min_chans > GST_ALSA_MAX_CHANNELS) {
530 GST_DEBUG_OBJECT (obj, "min_chans = %u, looks like a pro card", min_chans);
531 if (max_chans < min_chans) {
532 max_chans = min_chans;
533 } else {
534 /* only support [max_chans; max_chans] for these cards for now
535 * to avoid inflating the source caps with loads of structures ... */
536 min_chans = max_chans;
537 }
538 } else {
539 min_chans = MAX (min_chans, 1);
540 max_chans = MIN (GST_ALSA_MAX_CHANNELS, max_chans);
541 }
542
543 GST_DEBUG_OBJECT (obj, "Min. channels = %d (%d)", min_chans, min);
544 GST_DEBUG_OBJECT (obj, "Max. channels = %d (%d)", max_chans, max);
545
546 caps = gst_caps_new_empty ();
547
548 for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
549 GstStructure *s;
550 GType field_type;
551 gint c_min = min_chans;
552 gint c_max = max_chans;
553
554 s = gst_caps_get_structure (in_caps, i);
555 /* the template caps might limit the number of channels (like alsasrc),
556 * in which case we don't want to return a superset, so hack around this
557 * for the two common cases where the channels are either a fixed number
558 * or a min/max range). Example: alsasrc template has channels = [1,2] and
559 * the detection will claim to support 8 channels for device 'plughw:0' */
560 field_type = gst_structure_get_field_type (s, "channels");
561 if (field_type == G_TYPE_INT) {
562 gst_structure_get_int (s, "channels", &c_min);
563 gst_structure_get_int (s, "channels", &c_max);
564 } else if (field_type == GST_TYPE_INT_RANGE) {
565 const GValue *val;
566
567 val = gst_structure_get_value (s, "channels");
568 c_min = CLAMP (gst_value_get_int_range_min (val), min_chans, max_chans);
569 c_max = CLAMP (gst_value_get_int_range_max (val), min_chans, max_chans);
570 } else {
571 c_min = min_chans;
572 c_max = max_chans;
573 }
574
575 caps_add_channel_configuration (caps, s, c_min, c_max);
576 }
577
578 gst_caps_unref (in_caps);
579
580 return caps;
581
582 /* ERRORS */
583min_chan_error:
584 {
585 GST_ERROR_OBJECT (obj, "failed to query minimum channel count: %s",
586 snd_strerror (err));
587 return NULL;
588 }
589max_chan_error:
590 {
591 GST_ERROR_OBJECT (obj, "failed to query maximum channel count: %s",
592 snd_strerror (err));
593 return NULL;
594 }
595}
596
597#ifndef GST_CHECK_VERSION
598#define GST_CHECK_VERSION(major,minor,micro) \
599 (GST_VERSION_MAJOR > (major) || \
600 (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR > (minor)) || \
601 (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR == (minor) && GST_VERSION_MICRO >= (micro)))
602#endif
603
604#if GST_CHECK_VERSION(0, 10, 18)
605snd_pcm_t *
606gst_alsa_open_iec958_pcm (GstObject * obj)
607{
608 char *iec958_pcm_name = NULL;
609 snd_pcm_t *pcm = NULL;
610 int res;
611 char devstr[256]; /* Storage for local 'default' device string */
612
613 /*
614 * Try and open our default iec958 device. Fall back to searching on card x
615 * if this fails, which should only happen on older alsa setups
616 */
617
618 /* The string will be one of these:
619 * SPDIF_CON: Non-audio flag not set:
620 * spdif:{AES0 0x0 AES1 0x82 AES2 0x0 AES3 0x2}
621 * SPDIF_CON: Non-audio flag set:
622 * spdif:{AES0 0x2 AES1 0x82 AES2 0x0 AES3 0x2}
623 */
624 sprintf (devstr,
625 "iec958:{AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}",
626 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
627 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
628 0, IEC958_AES3_CON_FS_48000);
629
630 GST_DEBUG_OBJECT (obj, "Generated device string \"%s\"", devstr);
631 iec958_pcm_name = devstr;
632
633 res = snd_pcm_open (&pcm, iec958_pcm_name, SND_PCM_STREAM_PLAYBACK, 0);
634 if (G_UNLIKELY (res < 0)) {
635 GST_DEBUG_OBJECT (obj, "failed opening IEC958 device: %s",
636 snd_strerror (res));
637 pcm = NULL;
638 }
639
640 return pcm;
641}
642#endif
643
644
645/*
646 * gst_alsa_probe_supported_formats:
647 *
648 * Takes the template caps and returns the subset which is actually
649 * supported by this device.
650 *
651 */
652
653GstCaps *
654gst_alsa_probe_supported_formats (GstObject * obj, snd_pcm_t * handle,
655 const GstCaps * template_caps)
656{
657 snd_pcm_hw_params_t *hw_params;
658 snd_pcm_stream_t stream_type;
659 GstCaps *caps;
660 gint err;
661
662 snd_pcm_hw_params_malloc (&hw_params);
663 if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0)
664 goto error;
665
666 stream_type = snd_pcm_stream (handle);
667
668 caps = gst_caps_copy (template_caps);
669
670 if (!(caps = gst_alsa_detect_formats (obj, hw_params, caps)))
671 goto subroutine_error;
672
673 if (!(caps = gst_alsa_detect_rates (obj, hw_params, caps)))
674 goto subroutine_error;
675
676 if (!(caps = gst_alsa_detect_channels (obj, hw_params, caps)))
677 goto subroutine_error;
678
679#if GST_CHECK_VERSION(0, 10, 18)
680 /* Try opening IEC958 device to see if we can support that format (playback
681 * only for now but we could add SPDIF capture later) */
682 if (stream_type == SND_PCM_STREAM_PLAYBACK) {
683 snd_pcm_t *pcm = gst_alsa_open_iec958_pcm (obj);
684
685 if (G_LIKELY (pcm)) {
686 gst_caps_append (caps, gst_caps_new_simple ("audio/x-iec958", NULL));
687 snd_pcm_close (pcm);
688 }
689 }
690#endif
691
692 snd_pcm_hw_params_free (hw_params);
693 return caps;
694
695 /* ERRORS */
696error:
697 {
698 GST_ERROR_OBJECT (obj, "failed to query formats: %s", snd_strerror (err));
699 snd_pcm_hw_params_free (hw_params);
700 return NULL;
701 }
702subroutine_error:
703 {
704 GST_ERROR_OBJECT (obj, "failed to query formats");
705 snd_pcm_hw_params_free (hw_params);
706 return NULL;
707 }
708}
709
710static gchar *
711gst_alsa_find_device_name_no_handle (GstObject * obj, const gchar * devcard,
712 gint device_num, snd_pcm_stream_t stream)
713{
714 snd_ctl_card_info_t *info = NULL;
715 snd_ctl_t *ctl = NULL;
716 gchar *ret = NULL;
717 gint dev = -1;
718
719 GST_LOG_OBJECT (obj, "[%s] device=%d", devcard, device_num);
720
721 if (snd_ctl_open (&ctl, devcard, 0) < 0)
722 return NULL;
723
724 snd_ctl_card_info_malloc (&info);
725 if (snd_ctl_card_info (ctl, info) < 0)
726 goto done;
727
728 while (snd_ctl_pcm_next_device (ctl, &dev) == 0 && dev >= 0) {
729 if (dev == device_num) {
730 snd_pcm_info_t *pcminfo;
731
732 snd_pcm_info_malloc (&pcminfo);
733 snd_pcm_info_set_device (pcminfo, dev);
734 snd_pcm_info_set_subdevice (pcminfo, 0);
735 snd_pcm_info_set_stream (pcminfo, stream);
736 if (snd_ctl_pcm_info (ctl, pcminfo) < 0) {
737 snd_pcm_info_free (pcminfo);
738 break;
739 }
740
741 ret = g_strdup (snd_pcm_info_get_name (pcminfo));
742 snd_pcm_info_free (pcminfo);
743 GST_LOG_OBJECT (obj, "name from pcminfo: %s", GST_STR_NULL (ret));
744 }
745 }
746
747 if (ret == NULL) {
748 char *name = NULL;
749 gint card;
750
751 GST_LOG_OBJECT (obj, "no luck so far, trying backup");
752 card = snd_ctl_card_info_get_card (info);
753 snd_card_get_name (card, &name);
754 ret = g_strdup (name);
755 free (name);
756 }
757
758done:
759 snd_ctl_card_info_free (info);
760 snd_ctl_close (ctl);
761
762 return ret;
763}
764
765gchar *
766gst_alsa_find_device_name (GstObject * obj, const gchar * device,
767 snd_pcm_t * handle, snd_pcm_stream_t stream)
768{
769 gchar *ret = NULL;
770
771 if (device != NULL) {
772 gchar *dev, *comma;
773 gint devnum;
774
775 GST_LOG_OBJECT (obj, "Trying to get device name from string '%s'", device);
776
777 /* only want name:card bit, but not devices and subdevices */
778 dev = g_strdup (device);
779 if ((comma = strchr (dev, ','))) {
780 *comma = '\0';
781 devnum = atoi (comma + 1);
782 ret = gst_alsa_find_device_name_no_handle (obj, dev, devnum, stream);
783 }
784 g_free (dev);
785 }
786
787 if (ret == NULL && handle != NULL) {
788 snd_pcm_info_t *info;
789
790 GST_LOG_OBJECT (obj, "Trying to get device name from open handle");
791 snd_pcm_info_malloc (&info);
792 snd_pcm_info (handle, info);
793 ret = g_strdup (snd_pcm_info_get_name (info));