• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, see <http://www.gnu.org/licenses/>.
20 ***/
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 
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>
41 
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>");
47 
48 #ifdef __linux__
49 PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-detect!");
50 #endif
51 
52 static const char* const valid_modargs[] = {
53     "just-one",
54     NULL
55 };
56 
57 #ifdef HAVE_ALSA
58 
detect_alsa(pa_core * c,int just_one)59 static int detect_alsa(pa_core *c, int just_one) {
60     FILE *f;
61     int n = 0, n_sink = 0, n_source = 0;
62 
63     if (!(f = pa_fopen_cloexec("/proc/asound/devices", "r"))) {
64 
65         if (errno != ENOENT)
66             pa_log_error("open(\"/proc/asound/devices\") failed: %s", pa_cstrerror(errno));
67 
68         return -1;
69     }
70 
71     while (!feof(f)) {
72         char line[64], args[64];
73         unsigned device, subdevice;
74         int is_sink;
75         pa_module *m = NULL;
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(&m, c, is_sink ? "module-alsa-sink" : "module-alsa-source", args) < 0)
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
detect_oss(pa_core * c,int just_one)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[256], args[64];
137         unsigned device;
138         pa_module *m = NULL;
139 
140         if (!fgets(line, sizeof(line), f))
141             break;
142 
143         line[strcspn(line, "\r\n")] = 0;
144 
145         if (!b) {
146             b = pa_streq(line, "Audio devices:") || pa_streq(line, "Installed devices:");
147             continue;
148         }
149 
150         if (line[0] == 0)
151             break;
152 
153         if (sscanf(line, "%u: ", &device) == 1) {
154             if (device == 0)
155                 pa_snprintf(args, sizeof(args), "device=/dev/dsp");
156             else
157                 pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
158 
159             if (pa_module_load(&m, c, "module-oss", args) < 0)
160                 continue;
161 
162         } else if (sscanf(line, "pcm%u: ", &device) == 1) {
163             /* FreeBSD support, the devices are named /dev/dsp0.0, dsp0.1 and so on */
164             pa_snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device);
165 
166             if (pa_module_load(&m, c, "module-oss", args) < 0)
167                 continue;
168         }
169 
170         n++;
171 
172         if (just_one)
173             break;
174     }
175 
176     fclose(f);
177     return n;
178 }
179 #endif
180 
181 #ifdef HAVE_SOLARIS
detect_solaris(pa_core * c,int just_one)182 static int detect_solaris(pa_core *c, int just_one) {
183     struct stat s;
184     const char *dev;
185     char args[64];
186     pa_module *m = NULL;
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(&m, c, "module-solaris", args) < 0)
204         return 0;
205 
206     return 1;
207 }
208 #endif
209 
210 #ifdef OS_IS_WIN32
detect_waveout(pa_core * c,int just_one)211 static int detect_waveout(pa_core *c, int just_one) {
212     pa_module *m = NULL;
213     /*
214      * FIXME: No point in enumerating devices until the plugin supports
215      * selecting anything but the first.
216      */
217     if (pa_module_load(&m, c, "module-waveout", "") < 0)
218         return 0;
219 
220     return 1;
221 }
222 #endif
223 
pa__init(pa_module * m)224 int pa__init(pa_module*m) {
225     bool 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 #ifdef HAVE_ALSA
242     if ((n = detect_alsa(m->core, just_one)) <= 0)
243 #endif
244 #ifdef HAVE_OSS_OUTPUT
245     if ((n = detect_oss(m->core, just_one)) <= 0)
246 #endif
247 #ifdef HAVE_SOLARIS
248     if ((n = detect_solaris(m->core, just_one)) <= 0)
249 #endif
250 #ifdef 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, true);
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 }
273