Git init
[framework/multimedia/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, 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 = fopen("/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 = fopen("/dev/sndstat", "r")) &&
128         !(f = fopen("/proc/sndstat", "r")) &&
129         !(f = fopen("/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 }