]> code.delx.au - pulseaudio/blob - src/modules/module-detect.c
zeroconf-publish: Don't assume any particular defer event ordering
[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 <pulsecore/core-error.h>
38 #include <pulsecore/module.h>
39 #include <pulsecore/modargs.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/core-util.h>
42 #include <pulsecore/macro.h>
43
44 #include "module-detect-symdef.h"
45
46 PA_MODULE_AUTHOR("Lennart Poettering");
47 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
48 PA_MODULE_VERSION(PACKAGE_VERSION);
49 PA_MODULE_LOAD_ONCE(true);
50 PA_MODULE_USAGE("just-one=<boolean>");
51 PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-detect!");
52
53 static const char* const valid_modargs[] = {
54 "just-one",
55 NULL
56 };
57
58 #ifdef HAVE_ALSA
59
60 static int detect_alsa(pa_core *c, int just_one) {
61 FILE *f;
62 int n = 0, n_sink = 0, n_source = 0;
63
64 if (!(f = pa_fopen_cloexec("/proc/asound/devices", "r"))) {
65
66 if (errno != ENOENT)
67 pa_log_error("open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno));
68
69 return -1;
70 }
71
72 while (!feof(f)) {
73 char line[64], args[64];
74 unsigned device, subdevice;
75 int is_sink;
76
77 if (!fgets(line, sizeof(line), f))
78 break;
79
80 line[strcspn(line, "\r\n")] = 0;
81
82 if (pa_endswith(line, "digital audio playback"))
83 is_sink = 1;
84 else if (pa_endswith(line, "digital audio capture"))
85 is_sink = 0;
86 else
87 continue;
88
89 if (just_one && is_sink && n_sink >= 1)
90 continue;
91
92 if (just_one && !is_sink && n_source >= 1)
93 continue;
94
95 if (sscanf(line, " %*i: [%u- %u]: ", &device, &subdevice) != 2)
96 continue;
97
98 /* Only one sink per device */
99 if (subdevice != 0)
100 continue;
101
102 pa_snprintf(args, sizeof(args), "device_id=%u", device);
103 if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args))
104 continue;
105
106 n++;
107
108 if (is_sink)
109 n_sink++;
110 else
111 n_source++;
112 }
113
114 fclose(f);
115
116 return n;
117 }
118 #endif
119
120 #ifdef HAVE_OSS_OUTPUT
121 static int detect_oss(pa_core *c, int just_one) {
122 FILE *f;
123 int n = 0, b = 0;
124
125 if (!(f = pa_fopen_cloexec("/dev/sndstat", "r")) &&
126 !(f = pa_fopen_cloexec("/proc/sndstat", "r")) &&
127 !(f = pa_fopen_cloexec("/proc/asound/oss/sndstat", "r"))) {
128
129 if (errno != ENOENT)
130 pa_log_error("failed to open OSS sndstat device: %s", pa_cstrerror(errno));
131
132 return -1;
133 }
134
135 while (!feof(f)) {
136 char line[64], args[64];
137 unsigned device;
138
139 if (!fgets(line, sizeof(line), f))
140 break;
141
142 line[strcspn(line, "\r\n")] = 0;
143
144 if (!b) {
145 b = pa_streq(line, "Audio devices:") || pa_streq(line, "Installed devices:");
146 continue;
147 }
148
149 if (line[0] == 0)
150 break;
151
152 if (sscanf(line, "%u: ", &device) == 1) {
153 if (device == 0)
154 pa_snprintf(args, sizeof(args), "device=/dev/dsp");
155 else
156 pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
157
158 if (!pa_module_load(c, "module-oss", args))
159 continue;
160
161 } else if (sscanf(line, "pcm%u: ", &device) == 1) {
162 /* FreeBSD support, the devices are named /dev/dsp0.0, dsp0.1 and so on */
163 pa_snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device);
164
165 if (!pa_module_load(c, "module-oss", args))
166 continue;
167 }
168
169 n++;
170
171 if (just_one)
172 break;
173 }
174
175 fclose(f);
176 return n;
177 }
178 #endif
179
180 #ifdef HAVE_SOLARIS
181 static int detect_solaris(pa_core *c, int just_one) {
182 struct stat s;
183 const char *dev;
184 char args[64];
185
186 dev = getenv("AUDIODEV");
187 if (!dev)
188 dev = "/dev/audio";
189
190 if (stat(dev, &s) < 0) {
191 if (errno != ENOENT)
192 pa_log_error("failed to open device %s: %s", dev, pa_cstrerror(errno));
193 return -1;
194 }
195
196 if (!S_ISCHR(s.st_mode))
197 return 0;
198
199 pa_snprintf(args, sizeof(args), "device=%s", dev);
200
201 if (!pa_module_load(c, "module-solaris", args))
202 return 0;
203
204 return 1;
205 }
206 #endif
207
208 #ifdef OS_IS_WIN32
209 static int detect_waveout(pa_core *c, int just_one) {
210 /*
211 * FIXME: No point in enumerating devices until the plugin supports
212 * selecting anything but the first.
213 */
214 if (!pa_module_load(c, "module-waveout", ""))
215 return 0;
216
217 return 1;
218 }
219 #endif
220
221 int pa__init(pa_module*m) {
222 bool just_one = false;
223 int n = 0;
224 pa_modargs *ma;
225
226 pa_assert(m);
227
228 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
229 pa_log("Failed to parse module arguments");
230 goto fail;
231 }
232
233 if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) {
234 pa_log("just_one= expects a boolean argument.");
235 goto fail;
236 }
237
238 #ifdef HAVE_ALSA
239 if ((n = detect_alsa(m->core, just_one)) <= 0)
240 #endif
241 #ifdef HAVE_OSS_OUTPUT
242 if ((n = detect_oss(m->core, just_one)) <= 0)
243 #endif
244 #ifdef HAVE_SOLARIS
245 if ((n = detect_solaris(m->core, just_one)) <= 0)
246 #endif
247 #ifdef OS_IS_WIN32
248 if ((n = detect_waveout(m->core, just_one)) <= 0)
249 #endif
250 {
251 pa_log_warn("failed to detect any sound hardware.");
252 goto fail;
253 }
254
255 pa_log_info("loaded %i modules.", n);
256
257 /* We were successful and can unload ourselves now. */
258 pa_module_unload_request(m, true);
259
260 pa_modargs_free(ma);
261
262 return 0;
263
264 fail:
265 if (ma)
266 pa_modargs_free(ma);
267
268 return -1;
269 }