format: Don't assert on errors in getters
[profile/ivi/pulseaudio-panda.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 <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 = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0;
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     pa_bool_t 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 }