1/**
2 * \file pcm/pcm_asym.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Asymmetrical Plugin Interface
5 * \author Takashi Iwai <tiwai@suse.de>
6 * \date 2003
7 */
8
9#include "pcm_local.h"
10
11#ifndef PIC
12/* entry for static linking */
13const char *_snd_module_pcm_asym = "";
14#endif
15
16/*! \page pcm_plugins
17
18\section pcm_plugins_asym Plugin: asym
19
20This plugin is a combination of playback and capture PCM streams.
21Slave PCMs can be defined asymmetrically for both directions.
22
23\code
24pcm.name {
25        type asym               # Asym PCM
26        playback STR            # Playback slave name
27        # or
28        playback {              # Playback slave definition
29                pcm STR         # Slave PCM name
30                # or
31                pcm { }         # Slave PCM definition
32        }
33        capture STR             # Capture slave name
34        # or
35        capture {               # Capture slave definition
36                pcm STR         # Slave PCM name
37                # or
38                pcm { }         # Slave PCM definition
39        }
40}
41\endcode
42
43For example, you can combine a dmix plugin and a dsnoop plugin as
44as a single PCM for playback and capture directions, respectively.
45\code
46pcm.duplex {
47	type asym
48	playback.pcm "dmix"
49	capture.pcm "dsnoop"
50}
51\endcode
52
53By defining only a single direction, the resultant PCM becomes
54half-duplex.
55
56\subsection pcm_plugins_asym_funcref Function reference
57
58<UL>
59  <LI>_snd_pcm_asym_open()
60</UL>
61
62*/
63
64/**
65 * \brief Creates a new asym stream PCM
66 * \param pcmp Returns created PCM handle
67 * \param name Name of PCM
68 * \param root Root configuration node
69 * \param conf Configuration node with copy PCM description
70 * \param stream Stream type
71 * \param mode Stream mode
72 * \retval zero on success otherwise a negative error code
73 * \warning Using of this function might be dangerous in the sense
74 *          of compatibility reasons. The prototype might be freely
75 *          changed in future.
76 */
77int _snd_pcm_asym_open(snd_pcm_t **pcmp, const char *name ATTRIBUTE_UNUSED,
78			 snd_config_t *root, snd_config_t *conf,
79			 snd_pcm_stream_t stream, int mode)
80{
81	snd_config_iterator_t i, next;
82	int err;
83	snd_config_t *slave = NULL, *sconf;
84	snd_config_for_each(i, next, conf) {
85		snd_config_t *n = snd_config_iterator_entry(i);
86		const char *id;
87		if (snd_config_get_id(n, &id) < 0)
88			continue;
89		if (snd_pcm_conf_generic_id(id))
90			continue;
91		if (strcmp(id, "playback") == 0) {
92			if (stream == SND_PCM_STREAM_PLAYBACK)
93				slave = n;
94			continue;
95		}
96		if (strcmp(id, "capture") == 0) {
97			if (stream == SND_PCM_STREAM_CAPTURE)
98				slave = n;
99			continue;
100		}
101		SNDERR("Unknown field %s", id);
102		return -EINVAL;
103	}
104	if (! slave) {
105		SNDERR("%s slave is not defined",
106		       stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture");
107		return -EINVAL;
108	}
109	err = snd_pcm_slave_conf(root, slave, &sconf, 0);
110	if (err < 0)
111		return err;
112	err = snd_pcm_open_named_slave(pcmp, name, root, sconf, stream,
113				       mode, conf);
114	snd_config_delete(sconf);
115	return err;
116}
117#ifndef DOC_HIDDEN
118SND_DLSYM_BUILD_VERSION(_snd_pcm_asym_open, SND_PCM_DLSYM_VERSION);
119#endif
120