2 This file is part of PulseAudio.
4 Copyright 2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 Copyright 2006 Diego Pettenò
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.
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.
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
32 #include <sys/types.h>
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/module.h>
37 #include <pulsecore/modargs.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/macro.h>
42 PA_MODULE_AUTHOR("Lennart Poettering");
43 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
44 PA_MODULE_VERSION(PACKAGE_VERSION);
45 PA_MODULE_LOAD_ONCE(true);
46 PA_MODULE_USAGE("just-one=<boolean>");
49 PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-detect!");
52 static const char* const valid_modargs[] = {
59 static int detect_alsa(pa_core *c, int just_one) {
61 int n = 0, n_sink = 0, n_source = 0;
63 if (!(f = pa_fopen_cloexec("/proc/asound/devices", "r"))) {
66 pa_log_error("open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno));
72 char line[64], args[64];
73 unsigned device, subdevice;
77 if (!fgets(line, sizeof(line), f))
80 line[strcspn(line, "\r\n")] = 0;
82 if (pa_endswith(line, "digital audio playback"))
84 else if (pa_endswith(line, "digital audio capture"))
89 if (just_one && is_sink && n_sink >= 1)
92 if (just_one && !is_sink && n_source >= 1)
95 if (sscanf(line, " %*i: [%u- %u]: ", &device, &subdevice) != 2)
98 /* Only one sink per device */
102 pa_snprintf(args, sizeof(args), "device_id=%u", device);
103 if (pa_module_load(&m, c, is_sink ? "module-alsa-sink" : "module-alsa-source", args) < 0)
120 #ifdef HAVE_OSS_OUTPUT
121 static int detect_oss(pa_core *c, int just_one) {
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"))) {
130 pa_log_error("failed to open OSS sndstat device: %s", pa_cstrerror(errno));
136 char line[256], args[64];
140 if (!fgets(line, sizeof(line), f))
143 line[strcspn(line, "\r\n")] = 0;
146 b = pa_streq(line, "Audio devices:") || pa_streq(line, "Installed devices:");
153 if (sscanf(line, "%u: ", &device) == 1) {
155 pa_snprintf(args, sizeof(args), "device=/dev/dsp");
157 pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
159 if (pa_module_load(&m, c, "module-oss", args) < 0)
162 } else if (sscanf(line, "pcm%u: ", &device) == 1) {
163 pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
165 if (pa_module_load(&m, c, "module-oss", args) < 0)
168 if (!pa_endswith(line, "default"))
171 const char *p = strrchr(line, '(');
176 if (!c->configured_default_sink && (strstr(p, "play") || (strstr(p, "p:") && !strstr(p, "(0p:")))) {
177 uint32_t idx = PA_IDXSET_INVALID;
179 PA_IDXSET_FOREACH(s, c->sinks, idx) {
180 if (s->module == m) {
181 pa_core_set_configured_default_sink(c, s->name);
187 if (!c->configured_default_source && (strstr(p, "rec") || (strstr(p, "r:") && !strstr(p, "/0r:")))) {
188 uint32_t idx = PA_IDXSET_INVALID;
190 PA_IDXSET_FOREACH(s, c->sources, idx) {
191 if (s->module == m) {
192 pa_core_set_configured_default_source(c, s->name);
211 static int detect_solaris(pa_core *c, int just_one) {
217 dev = getenv("AUDIODEV");
221 if (stat(dev, &s) < 0) {
223 pa_log_error("failed to open device %s: %s", dev, pa_cstrerror(errno));
227 if (!S_ISCHR(s.st_mode))
230 pa_snprintf(args, sizeof(args), "device=%s", dev);
232 if (pa_module_load(&m, c, "module-solaris", args) < 0)
240 static int detect_waveout(pa_core *c, int just_one) {
243 * FIXME: No point in enumerating devices until the plugin supports
244 * selecting anything but the first.
246 if (pa_module_load(&m, c, "module-waveout", "") < 0)
253 int pa__init(pa_module*m) {
254 bool just_one = false;
260 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
261 pa_log("Failed to parse module arguments");
265 if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) {
266 pa_log("just_one= expects a boolean argument.");
271 if ((n = detect_alsa(m->core, just_one)) <= 0)
273 #ifdef HAVE_OSS_OUTPUT
274 if ((n = detect_oss(m->core, just_one)) <= 0)
277 if ((n = detect_solaris(m->core, just_one)) <= 0)
280 if ((n = detect_waveout(m->core, just_one)) <= 0)
283 pa_log_warn("failed to detect any sound hardware.");
287 pa_log_info("loaded %i modules.", n);
289 /* We were successful and can unload ourselves now. */
290 pa_module_unload_request(m, true);