]> code.delx.au - pulseaudio/blob - src/modules/module-detect.c
Completely rework ALSA device selection code: choose the device to open depending...
[pulseaudio] / src / modules / module-detect.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8 Copyright 2006 Diego Pettenò
9
10 PulseAudio is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published
12 by the Free Software Foundation; either version 2 of the License,
13 or (at your option) any later version.
14
15 PulseAudio is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with PulseAudio; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 USA.
24 ***/
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38
39 #include <pulse/xmalloc.h>
40
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/modargs.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/core-util.h>
46 #include <pulsecore/macro.h>
47
48 #include "module-detect-symdef.h"
49
50 PA_MODULE_AUTHOR("Lennart Poettering");
51 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
52 PA_MODULE_VERSION(PACKAGE_VERSION);
53 PA_MODULE_LOAD_ONCE(TRUE);
54 PA_MODULE_USAGE("just-one=<boolean>");
55
56 static const char* const valid_modargs[] = {
57 "just-one",
58 NULL
59 };
60
61 #ifdef HAVE_ALSA
62
63 static int detect_alsa(pa_core *c, int just_one) {
64 FILE *f;
65 int n = 0, n_sink = 0, n_source = 0;
66
67 if (!(f = fopen("/proc/asound/devices", "r"))) {
68
69 if (errno != ENOENT)
70 pa_log_error("open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno));
71
72 return -1;
73 }
74
75 while (!feof(f)) {
76 char line[64], args[64];
77 unsigned device, subdevice;
78 int is_sink;
79
80 if (!fgets(line, sizeof(line), f))
81 break;
82
83 line[strcspn(line, "\r\n")] = 0;
84
85 if (pa_endswith(line, "digital audio playback"))
86 is_sink = 1;
87 else if (pa_endswith(line, "digital audio capture"))
88 is_sink = 0;
89 else
90 continue;
91
92 if (just_one && is_sink && n_sink >= 1)
93 continue;
94
95 if (just_one && !is_sink && n_source >= 1)
96 continue;
97
98 if (sscanf(line, " %*i: [%u- %u]: ", &device, &subdevice) != 2)
99 continue;
100
101 /* Only one sink per device */
102 if (subdevice != 0)
103 continue;
104
105 pa_snprintf(args, sizeof(args), "device=hw:%u", device);
106 if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args))
107 continue;
108
109 n++;
110
111 if (is_sink)
112 n_sink++;
113 else
114 n_source++;
115 }
116
117 fclose(f);
118
119 return n;
120 }
121 #endif
122
123 #ifdef HAVE_OSS
124 static int detect_oss(pa_core *c, int just_one) {
125 FILE *f;
126 int n = 0, b = 0;
127
128 if (!(f = fopen("/dev/sndstat", "r")) &&
129 !(f = fopen("/proc/sndstat", "r")) &&
130 !(f = fopen("/proc/asound/oss/sndstat", "r"))) {
131
132 if (errno != ENOENT)
133 pa_log_error("failed to open OSS sndstat device: %s", pa_cstrerror(errno));
134
135 return -1;
136 }
137
138 while (!feof(f)) {
139 char line[64], args[64];
140 unsigned device;
141
142 if (!fgets(line, sizeof(line), f))
143 break;
144
145 line[strcspn(line, "\r\n")] = 0;
146
147 if (!b) {
148 b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0;
149 continue;
150 }
151
152 if (line[0] == 0)
153 break;
154
155 if (sscanf(line, "%u: ", &device) == 1) {
156 if (device == 0)
157 pa_snprintf(args, sizeof(args), "device=/dev/dsp");
158 else
159 pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
160
161 if (!pa_module_load(c, "module-oss", args))
162 continue;
163
164 } else if (sscanf(line, "pcm%u: ", &device) == 1) {
165 /* FreeBSD support, the devices are named /dev/dsp0.0, dsp0.1 and so on */
166 pa_snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device);
167
168 if (!pa_module_load(c, "module-oss", args))
169 continue;
170 }
171
172 n++;
173
174 if (just_one)
175 break;
176 }
177
178 fclose(f);
179 return n;
180 }
181 #endif
182
183 #ifdef HAVE_SOLARIS
184 static int detect_solaris(pa_core *c, int just_one) {
185 struct stat s;
186 const char *dev;
187 char args[64];
188
189 dev = getenv("AUDIODEV");
190 if (!dev)
191 dev = "/dev/audio";
192
193 if (stat(dev, &s) < 0) {
194 if (errno != ENOENT)
195 pa_log_error("failed to open device %s: %s", dev, pa_cstrerror(errno));
196 return -1;
197 }
198
199 if (!S_ISCHR(s.st_mode))
200 return 0;
201
202 pa_snprintf(args, sizeof(args), "device=%s", dev);
203
204 if (!pa_module_load(c, "module-solaris", args))
205 return 0;
206
207 return 1;
208 }
209 #endif
210
211 #ifdef OS_IS_WIN32
212 static int detect_waveout(pa_core *c, int just_one) {
213 /*
214 * FIXME: No point in enumerating devices until the plugin supports
215 * selecting anything but the first.
216 */
217 if (!pa_module_load(c, "module-waveout", ""))
218 return 0;
219
220 return 1;
221 }
222 #endif
223
224 int pa__init(pa_module*m) {
225 pa_bool_t just_one = FALSE;
226 int n = 0;
227 pa_modargs *ma;
228
229 pa_assert(m);
230
231 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
232 pa_log("Failed to parse module arguments");
233 goto fail;
234 }
235
236 if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) {
237 pa_log("just_one= expects a boolean argument.");
238 goto fail;
239 }
240
241 #if HAVE_ALSA
242 if ((n = detect_alsa(m->core, just_one)) <= 0)
243 #endif
244 #if HAVE_OSS
245 if ((n = detect_oss(m->core, just_one)) <= 0)
246 #endif
247 #if HAVE_SOLARIS
248 if ((n = detect_solaris(m->core, just_one)) <= 0)
249 #endif
250 #if OS_IS_WIN32
251 if ((n = detect_waveout(m->core, just_one)) <= 0)
252 #endif
253 {
254 pa_log_warn("failed to detect any sound hardware.");
255 goto fail;
256 }
257
258 pa_log_info("loaded %i modules.", n);
259
260 /* We were successful and can unload ourselves now. */
261 pa_module_unload_request(m);
262
263 pa_modargs_free(ma);
264
265 return 0;
266
267 fail:
268 if (ma)
269 pa_modargs_free(ma);
270
271 return -1;
272 }