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