MemoryLimit has been replaced by MemoryMax
[platform/upstream/pulseaudio.git] / 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, 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
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
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             pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
164
165             if (pa_module_load(&m, c, "module-oss", args) < 0)
166                 continue;
167
168             if (!pa_endswith(line, "default"))
169                 continue;
170
171             const char *p = strrchr(line, '(');
172
173             if (!p)
174                 continue;
175
176             if (!c->configured_default_sink && (strstr(p, "play") || (strstr(p, "p:") && !strstr(p, "(0p:")))) {
177                 uint32_t idx = PA_IDXSET_INVALID;
178                 pa_sink *s;
179                 PA_IDXSET_FOREACH(s, c->sinks, idx) {
180                     if (s->module == m) {
181                         pa_core_set_configured_default_sink(c, s->name);
182                         break;
183                     }
184                 }
185             }
186
187             if (!c->configured_default_source && (strstr(p, "rec") || (strstr(p, "r:") && !strstr(p, "/0r:")))) {
188                 uint32_t idx = PA_IDXSET_INVALID;
189                 pa_source *s;
190                 PA_IDXSET_FOREACH(s, c->sources, idx) {
191                     if (s->module == m) {
192                         pa_core_set_configured_default_source(c, s->name);
193                         break;
194                     }
195                 }
196             }
197         }
198
199         n++;
200
201         if (just_one)
202             break;
203     }
204
205     fclose(f);
206     return n;
207 }
208 #endif
209
210 #ifdef HAVE_SOLARIS
211 static int detect_solaris(pa_core *c, int just_one) {
212     struct stat s;
213     const char *dev;
214     char args[64];
215     pa_module *m = NULL;
216
217     dev = getenv("AUDIODEV");
218     if (!dev)
219         dev = "/dev/audio";
220
221     if (stat(dev, &s) < 0) {
222         if (errno != ENOENT)
223             pa_log_error("failed to open device %s: %s", dev, pa_cstrerror(errno));
224         return -1;
225     }
226
227     if (!S_ISCHR(s.st_mode))
228         return 0;
229
230     pa_snprintf(args, sizeof(args), "device=%s", dev);
231
232     if (pa_module_load(&m, c, "module-solaris", args) < 0)
233         return 0;
234
235     return 1;
236 }
237 #endif
238
239 #ifdef OS_IS_WIN32
240 static int detect_waveout(pa_core *c, int just_one) {
241     pa_module *m = NULL;
242     /*
243      * FIXME: No point in enumerating devices until the plugin supports
244      * selecting anything but the first.
245      */
246     if (pa_module_load(&m, c, "module-waveout", "") < 0)
247         return 0;
248
249     return 1;
250 }
251 #endif
252
253 int pa__init(pa_module*m) {
254     bool just_one = false;
255     int n = 0;
256     pa_modargs *ma;
257
258     pa_assert(m);
259
260     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
261         pa_log("Failed to parse module arguments");
262         goto fail;
263     }
264
265     if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) {
266         pa_log("just_one= expects a boolean argument.");
267         goto fail;
268     }
269
270 #ifdef HAVE_ALSA
271     if ((n = detect_alsa(m->core, just_one)) <= 0)
272 #endif
273 #ifdef HAVE_OSS_OUTPUT
274     if ((n = detect_oss(m->core, just_one)) <= 0)
275 #endif
276 #ifdef HAVE_SOLARIS
277     if ((n = detect_solaris(m->core, just_one)) <= 0)
278 #endif
279 #ifdef OS_IS_WIN32
280     if ((n = detect_waveout(m->core, just_one)) <= 0)
281 #endif
282     {
283         pa_log_warn("failed to detect any sound hardware.");
284         goto fail;
285     }
286
287     pa_log_info("loaded %i modules.", n);
288
289     /* We were successful and can unload ourselves now. */
290     pa_module_unload_request(m, true);
291
292     pa_modargs_free(ma);
293
294     return 0;
295
296 fail:
297     if (ma)
298         pa_modargs_free(ma);
299
300     return -1;
301 }