• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2006 Lennart Poettering
5   Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #ifdef _FILE_OFFSET_BITS
26 #undef _FILE_OFFSET_BITS
27 #endif
28 
29 #ifndef _LARGEFILE64_SOURCE
30 #define _LARGEFILE64_SOURCE 1
31 #endif
32 
33 #include <sys/soundcard.h>
34 #include <sys/ioctl.h>
35 #include <pthread.h>
36 #include <unistd.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <dlfcn.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <signal.h>
46 
47 #ifdef __linux__
48 #include <linux/sockios.h>
49 #endif
50 
51 #include <pulse/pulseaudio.h>
52 #include <pulse/gccmacro.h>
53 #include <pulsecore/llist.h>
54 #include <pulsecore/core-util.h>
55 #include <pulsecore/sample-util.h>
56 
57 /* On some systems SIOCINQ isn't defined, but FIONREAD is just an alias */
58 #if !defined(SIOCINQ) && defined(FIONREAD)
59 # define SIOCINQ FIONREAD
60 #endif
61 
62 /* make sure gcc doesn't redefine open and friends as macros */
63 #undef open
64 #undef open64
65 
66 typedef enum {
67     FD_INFO_MIXER,
68     FD_INFO_STREAM,
69 } fd_info_type_t;
70 
71 typedef struct fd_info fd_info;
72 
73 struct fd_info {
74     pthread_mutex_t mutex;
75     int ref;
76     int unusable;
77 
78     fd_info_type_t type;
79     int app_fd, thread_fd;
80 
81     pa_sample_spec sample_spec;
82     size_t fragment_size;
83     unsigned n_fragments;
84 
85     pa_threaded_mainloop *mainloop;
86     pa_context *context;
87     pa_stream *play_stream;
88     pa_stream *rec_stream;
89     int play_precork;
90     int rec_precork;
91 
92     pa_io_event *io_event;
93     pa_io_event_flags_t io_flags;
94 
95     void *buf;
96     size_t leftover;
97     size_t rec_offset;
98 
99     int operation_success;
100 
101     pa_cvolume sink_volume, source_volume;
102     uint32_t sink_index, source_index;
103     int volume_modify_count;
104 
105     int optr_n_blocks;
106 
107     PA_LLIST_FIELDS(fd_info);
108 };
109 
110 static int dsp_drain(fd_info *i);
111 static void fd_info_remove_from_list(fd_info *i);
112 
113 static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER;
114 static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER;
115 
116 static PA_LLIST_HEAD(fd_info, fd_infos) = NULL;
117 
118 static int (*_ioctl)(int, int, void*) = NULL;
119 static int (*_close)(int) = NULL;
120 static int (*_open)(const char *, int, mode_t) = NULL;
121 static int (*___open_2)(const char *, int) = NULL;
122 static FILE* (*_fopen)(const char *path, const char *mode) = NULL;
123 static int (*_stat)(const char *, struct stat *) = NULL;
124 #ifdef _STAT_VER
125 static int (*___xstat)(int, const char *, struct stat *) = NULL;
126 #endif
127 #ifdef HAVE_OPEN64
128 static int (*_open64)(const char *, int, mode_t) = NULL;
129 static int (*___open64_2)(const char *, int) = NULL;
130 static FILE* (*_fopen64)(const char *path, const char *mode) = NULL;
131 static int (*_stat64)(const char *, struct stat64 *) = NULL;
132 #ifdef _STAT_VER
133 static int (*___xstat64)(int, const char *, struct stat64 *) = NULL;
134 #endif
135 #endif
136 static int (*_fclose)(FILE *f) = NULL;
137 static int (*_access)(const char *, int) = NULL;
138 
139 /* dlsym() violates ISO C, so confide the breakage into this function to
140  * avoid warnings. */
141 typedef void (*fnptr)(void);
dlsym_fn(void * handle,const char * symbol)142 static inline fnptr dlsym_fn(void *handle, const char *symbol) {
143     return (fnptr) (long) dlsym(handle, symbol);
144 }
145 
146 #define LOAD_IOCTL_FUNC() \
147 do { \
148     pthread_mutex_lock(&func_mutex); \
149     if (!_ioctl)  \
150         _ioctl = (int (*)(int, int, void*)) dlsym_fn(RTLD_NEXT, "ioctl"); \
151     pthread_mutex_unlock(&func_mutex); \
152 } while(0)
153 
154 #define LOAD_OPEN_FUNC() \
155 do { \
156     pthread_mutex_lock(&func_mutex); \
157     if (!_open) \
158         _open = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open"); \
159     pthread_mutex_unlock(&func_mutex); \
160 } while(0)
161 
162 #define LOAD___OPEN_2_FUNC() \
163 do { \
164     pthread_mutex_lock(&func_mutex); \
165     if (!___open_2) \
166         ___open_2 = (int (*)(const char *, int)) dlsym_fn(RTLD_NEXT, "__open_2"); \
167     pthread_mutex_unlock(&func_mutex); \
168 } while(0)
169 
170 #define LOAD_OPEN64_FUNC() \
171 do { \
172     pthread_mutex_lock(&func_mutex); \
173     if (!_open64) \
174         _open64 = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open64"); \
175     pthread_mutex_unlock(&func_mutex); \
176 } while(0)
177 
178 #define LOAD___OPEN64_2_FUNC() \
179 do { \
180     pthread_mutex_lock(&func_mutex); \
181     if (!___open64_2) \
182         ___open64_2 = (int (*)(const char *, int)) dlsym_fn(RTLD_NEXT, "__open64_2"); \
183     pthread_mutex_unlock(&func_mutex); \
184 } while(0)
185 
186 #define LOAD_CLOSE_FUNC() \
187 do { \
188     pthread_mutex_lock(&func_mutex); \
189     if (!_close) \
190         _close = (int (*)(int)) dlsym_fn(RTLD_NEXT, "close"); \
191     pthread_mutex_unlock(&func_mutex); \
192 } while(0)
193 
194 #define LOAD_ACCESS_FUNC() \
195 do { \
196     pthread_mutex_lock(&func_mutex); \
197     if (!_access) \
198         _access = (int (*)(const char*, int)) dlsym_fn(RTLD_NEXT, "access"); \
199     pthread_mutex_unlock(&func_mutex); \
200 } while(0)
201 
202 #define LOAD_STAT_FUNC() \
203 do { \
204     pthread_mutex_lock(&func_mutex); \
205     if (!_stat) \
206         _stat = (int (*)(const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "stat"); \
207     pthread_mutex_unlock(&func_mutex); \
208 } while(0)
209 
210 #define LOAD_STAT64_FUNC() \
211 do { \
212     pthread_mutex_lock(&func_mutex); \
213     if (!_stat64) \
214         _stat64 = (int (*)(const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "stat64"); \
215     pthread_mutex_unlock(&func_mutex); \
216 } while(0)
217 
218 #define LOAD_XSTAT_FUNC() \
219 do { \
220     pthread_mutex_lock(&func_mutex); \
221     if (!___xstat) \
222         ___xstat = (int (*)(int, const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "__xstat"); \
223     pthread_mutex_unlock(&func_mutex); \
224 } while(0)
225 
226 #define LOAD_XSTAT64_FUNC() \
227 do { \
228     pthread_mutex_lock(&func_mutex); \
229     if (!___xstat64) \
230         ___xstat64 = (int (*)(int, const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "__xstat64"); \
231     pthread_mutex_unlock(&func_mutex); \
232 } while(0)
233 
234 #define LOAD_FOPEN_FUNC() \
235 do { \
236     pthread_mutex_lock(&func_mutex); \
237     if (!_fopen) \
238         _fopen = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen"); \
239     pthread_mutex_unlock(&func_mutex); \
240 } while(0)
241 
242 #define LOAD_FOPEN64_FUNC() \
243 do { \
244     pthread_mutex_lock(&func_mutex); \
245     if (!_fopen64) \
246         _fopen64 = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen64"); \
247     pthread_mutex_unlock(&func_mutex); \
248 } while(0)
249 
250 #define LOAD_FCLOSE_FUNC() \
251 do { \
252     pthread_mutex_lock(&func_mutex); \
253     if (!_fclose) \
254         _fclose = (int (*)(FILE *)) dlsym_fn(RTLD_NEXT, "fclose"); \
255     pthread_mutex_unlock(&func_mutex); \
256 } while(0)
257 
258 #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \
259 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \
260     debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
261     goto label; \
262 } \
263 } while(0)
264 
265 #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \
266 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
267     !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \
268     debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
269     goto label; \
270 } \
271 } while(0)
272 
273 #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \
274 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
275     !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \
276     debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
277     goto label; \
278 } \
279 } while(0)
280 
281 static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3);
282 
283 #define DEBUG_LEVEL_ALWAYS                0
284 #define DEBUG_LEVEL_NORMAL                1
285 #define DEBUG_LEVEL_VERBOSE               2
286 
debug(int level,const char * format,...)287 static void debug(int level, const char *format, ...) {
288     va_list ap;
289     const char *dlevel_s;
290     int dlevel;
291 
292     dlevel_s = getenv("PADSP_DEBUG");
293     if (!dlevel_s)
294         return;
295 
296     dlevel = atoi(dlevel_s);
297 
298     if (dlevel < level)
299         return;
300 
301     va_start(ap, format);
302     vfprintf(stderr, format, ap);
303     va_end(ap);
304 }
305 
padsp_disabled(void)306 static int padsp_disabled(void) {
307     static int *sym;
308     static int sym_resolved = 0;
309 
310     /* If the current process has a symbol __padsp_disabled__ we use
311      * it to detect whether we should enable our stuff or not. A
312      * program needs to be compiled with -rdynamic for this to work!
313      * The symbol must be an int containing a three bit bitmask: bit 1
314      * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat
315      * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value
316      * of 7 disables padsp entirely. */
317 
318     pthread_mutex_lock(&func_mutex);
319     if (!sym_resolved) {
320         sym = (int*) dlsym(RTLD_DEFAULT, "__padsp_disabled__");
321         sym_resolved = 1;
322     }
323     pthread_mutex_unlock(&func_mutex);
324 
325     if (!sym)
326         return 0;
327 
328     return *sym;
329 }
330 
dsp_cloak_enable(void)331 static int dsp_cloak_enable(void) {
332     if (padsp_disabled() & 1)
333         return 0;
334 
335     if (getenv("PADSP_NO_DSP") || getenv("PULSE_INTERNAL"))
336         return 0;
337 
338     return 1;
339 }
340 
sndstat_cloak_enable(void)341 static int sndstat_cloak_enable(void) {
342     if (padsp_disabled() & 2)
343         return 0;
344 
345     if (getenv("PADSP_NO_SNDSTAT") || getenv("PULSE_INTERNAL"))
346         return 0;
347 
348     return 1;
349 }
350 
mixer_cloak_enable(void)351 static int mixer_cloak_enable(void) {
352     if (padsp_disabled() & 4)
353         return 0;
354 
355     if (getenv("PADSP_NO_MIXER") || getenv("PULSE_INTERNAL"))
356         return 0;
357 
358     return 1;
359 }
360 static pthread_key_t recursion_key;
361 
recursion_key_alloc(void)362 static void recursion_key_alloc(void) {
363     pthread_key_create(&recursion_key, NULL);
364 }
365 
function_enter(void)366 static int function_enter(void) {
367     /* Avoid recursive calls */
368     static pthread_once_t recursion_key_once = PTHREAD_ONCE_INIT;
369     pthread_once(&recursion_key_once, recursion_key_alloc);
370 
371     if (pthread_getspecific(recursion_key))
372         return 0;
373 
374     pthread_setspecific(recursion_key, (void*) 1);
375     return 1;
376 }
377 
function_exit(void)378 static void function_exit(void) {
379     pthread_setspecific(recursion_key, NULL);
380 }
381 
fd_info_free(fd_info * i)382 static void fd_info_free(fd_info *i) {
383     assert(i);
384 
385     debug(DEBUG_LEVEL_NORMAL, __FILE__": freeing fd info (fd=%i)\n", i->app_fd);
386 
387     dsp_drain(i);
388 
389     if (i->mainloop)
390         pa_threaded_mainloop_stop(i->mainloop);
391 
392     if (i->play_stream) {
393         pa_stream_disconnect(i->play_stream);
394         pa_stream_unref(i->play_stream);
395     }
396 
397     if (i->rec_stream) {
398         pa_stream_disconnect(i->rec_stream);
399         pa_stream_unref(i->rec_stream);
400     }
401 
402     if (i->context) {
403         pa_context_disconnect(i->context);
404         pa_context_unref(i->context);
405     }
406 
407     if (i->mainloop)
408         pa_threaded_mainloop_free(i->mainloop);
409 
410     if (i->app_fd >= 0) {
411         LOAD_CLOSE_FUNC();
412         _close(i->app_fd);
413     }
414 
415     if (i->thread_fd >= 0) {
416         LOAD_CLOSE_FUNC();
417         _close(i->thread_fd);
418     }
419 
420     free(i->buf);
421 
422     pthread_mutex_destroy(&i->mutex);
423     free(i);
424 }
425 
fd_info_ref(fd_info * i)426 static fd_info *fd_info_ref(fd_info *i) {
427     assert(i);
428 
429     pthread_mutex_lock(&i->mutex);
430     assert(i->ref >= 1);
431     i->ref++;
432 
433     debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref++, now %i\n", i->ref);
434     pthread_mutex_unlock(&i->mutex);
435 
436     return i;
437 }
438 
fd_info_unref(fd_info * i)439 static void fd_info_unref(fd_info *i) {
440     int r;
441     pthread_mutex_lock(&i->mutex);
442     assert(i->ref >= 1);
443     r = --i->ref;
444     debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref);
445     pthread_mutex_unlock(&i->mutex);
446 
447     if (r <= 0)
448         fd_info_free(i);
449 }
450 
context_state_cb(pa_context * c,void * userdata)451 static void context_state_cb(pa_context *c, void *userdata) {
452     fd_info *i = userdata;
453     assert(c);
454 
455     switch (pa_context_get_state(c)) {
456         case PA_CONTEXT_READY:
457         case PA_CONTEXT_TERMINATED:
458         case PA_CONTEXT_FAILED:
459             pa_threaded_mainloop_signal(i->mainloop, 0);
460             break;
461 
462         case PA_CONTEXT_UNCONNECTED:
463         case PA_CONTEXT_CONNECTING:
464         case PA_CONTEXT_AUTHORIZING:
465         case PA_CONTEXT_SETTING_NAME:
466             break;
467     }
468 }
469 
reset_params(fd_info * i)470 static void reset_params(fd_info *i) {
471     assert(i);
472 
473     i->sample_spec.format = PA_SAMPLE_U8;
474     i->sample_spec.channels = 1;
475     i->sample_spec.rate = 8000;
476     i->fragment_size = 0;
477     i->n_fragments = 0;
478 }
479 
client_name(char * buf,size_t n)480 static const char *client_name(char *buf, size_t n) {
481     char *p;
482     const char *e;
483 
484     if ((e = getenv("PADSP_CLIENT_NAME")))
485         return e;
486 
487     if ((p = pa_get_binary_name_malloc())) {
488         snprintf(buf, n, "OSS Emulation[%s]", p);
489         pa_xfree(p);
490     } else
491         snprintf(buf, n, "OSS");
492 
493     return buf;
494 }
495 
stream_name(void)496 static const char *stream_name(void) {
497     const char *e;
498 
499     if ((e = getenv("PADSP_STREAM_NAME")))
500         return e;
501 
502     return "Audio Stream";
503 }
504 
atfork_prepare(void)505 static void atfork_prepare(void) {
506     fd_info *i;
507 
508     debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() enter\n");
509 
510     function_enter();
511 
512     pthread_mutex_lock(&fd_infos_mutex);
513 
514     for (i = fd_infos; i; i = i->next) {
515         pthread_mutex_lock(&i->mutex);
516         pa_threaded_mainloop_lock(i->mainloop);
517     }
518 
519     pthread_mutex_lock(&func_mutex);
520 
521     debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_prepare() exit\n");
522 }
523 
atfork_parent(void)524 static void atfork_parent(void) {
525     fd_info *i;
526 
527     debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() enter\n");
528 
529     pthread_mutex_unlock(&func_mutex);
530 
531     for (i = fd_infos; i; i = i->next) {
532         pa_threaded_mainloop_unlock(i->mainloop);
533         pthread_mutex_unlock(&i->mutex);
534     }
535 
536     pthread_mutex_unlock(&fd_infos_mutex);
537 
538     function_exit();
539 
540     debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_parent() exit\n");
541 }
542 
atfork_child(void)543 static void atfork_child(void) {
544     fd_info *i;
545 
546     debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() enter\n");
547 
548     /* We do only the bare minimum to get all fds closed */
549     pthread_mutex_init(&func_mutex, NULL);
550     pthread_mutex_init(&fd_infos_mutex, NULL);
551 
552     for (i = fd_infos; i; i = i->next) {
553         pthread_mutex_init(&i->mutex, NULL);
554 
555         if (i->context) {
556             pa_context_disconnect(i->context);
557             pa_context_unref(i->context);
558             i->context = NULL;
559         }
560 
561         if (i->play_stream) {
562             pa_stream_unref(i->play_stream);
563             i->play_stream = NULL;
564         }
565 
566         if (i->rec_stream) {
567             pa_stream_unref(i->rec_stream);
568             i->rec_stream = NULL;
569         }
570 
571         if (i->app_fd >= 0) {
572             LOAD_CLOSE_FUNC();
573             _close(i->app_fd);
574             i->app_fd = -1;
575         }
576 
577         if (i->thread_fd >= 0) {
578             LOAD_CLOSE_FUNC();
579             _close(i->thread_fd);
580             i->thread_fd = -1;
581         }
582 
583         i->unusable = 1;
584     }
585 
586     function_exit();
587 
588     debug(DEBUG_LEVEL_NORMAL, __FILE__": atfork_child() exit\n");
589 }
590 
install_atfork(void)591 static void install_atfork(void) {
592     pthread_atfork(atfork_prepare, atfork_parent, atfork_child);
593 }
594 
stream_success_cb(pa_stream * s,int success,void * userdata)595 static void stream_success_cb(pa_stream *s, int success, void *userdata) {
596     fd_info *i = userdata;
597 
598     assert(s);
599     assert(i);
600 
601     i->operation_success = success;
602     pa_threaded_mainloop_signal(i->mainloop, 0);
603 }
604 
context_success_cb(pa_context * c,int success,void * userdata)605 static void context_success_cb(pa_context *c, int success, void *userdata) {
606     fd_info *i = userdata;
607 
608     assert(c);
609     assert(i);
610 
611     i->operation_success = success;
612     pa_threaded_mainloop_signal(i->mainloop, 0);
613 }
614 
fd_info_new(fd_info_type_t type,int * _errno)615 static fd_info* fd_info_new(fd_info_type_t type, int *_errno) {
616     fd_info *i;
617     int sfds[2] = { -1, -1 };
618     char name[64];
619     static pthread_once_t install_atfork_once = PTHREAD_ONCE_INIT;
620 
621     debug(DEBUG_LEVEL_NORMAL, __FILE__": fd_info_new()\n");
622 
623     signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */
624 
625     pthread_once(&install_atfork_once, install_atfork);
626 
627     if (!(i = malloc(sizeof(fd_info)))) {
628         *_errno = ENOMEM;
629         goto fail;
630     }
631 
632     i->app_fd = i->thread_fd = -1;
633     i->type = type;
634 
635     i->mainloop = NULL;
636     i->context = NULL;
637     i->play_stream = NULL;
638     i->rec_stream = NULL;
639     i->play_precork = 0;
640     i->rec_precork = 0;
641     i->io_event = NULL;
642     i->io_flags = 0;
643     pthread_mutex_init(&i->mutex, NULL);
644     i->ref = 1;
645     i->buf = NULL;
646     i->leftover = 0;
647     i->rec_offset = 0;
648     i->unusable = 0;
649     pa_cvolume_reset(&i->sink_volume, 2);
650     pa_cvolume_reset(&i->source_volume, 2);
651     i->volume_modify_count = 0;
652     i->sink_index = (uint32_t) -1;
653     i->source_index = (uint32_t) -1;
654     i->optr_n_blocks = 0;
655     PA_LLIST_INIT(fd_info, i);
656 
657     reset_params(i);
658 
659     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfds) < 0) {
660         *_errno = errno;
661         debug(DEBUG_LEVEL_NORMAL, __FILE__": socket() failed: %s\n", strerror(errno));
662         goto fail;
663     }
664 
665     i->app_fd = sfds[0];
666     i->thread_fd = sfds[1];
667 
668     if (!(i->mainloop = pa_threaded_mainloop_new())) {
669         *_errno = EIO;
670         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_new() failed\n");
671         goto fail;
672     }
673 
674     if (!(i->context = pa_context_new(pa_threaded_mainloop_get_api(i->mainloop), client_name(name, sizeof(name))))) {
675         *_errno = EIO;
676         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_new() failed\n");
677         goto fail;
678     }
679 
680     pa_context_set_state_callback(i->context, context_state_cb, i);
681 
682     if (pa_context_connect(i->context, NULL, 0, NULL) < 0) {
683         *_errno = ECONNREFUSED;
684         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
685         goto fail;
686     }
687 
688     pa_threaded_mainloop_lock(i->mainloop);
689 
690     if (pa_threaded_mainloop_start(i->mainloop) < 0) {
691         *_errno = EIO;
692         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_threaded_mainloop_start() failed\n");
693         goto unlock_and_fail;
694     }
695 
696     /* Wait until the context is ready */
697     pa_threaded_mainloop_wait(i->mainloop);
698 
699     if (pa_context_get_state(i->context) != PA_CONTEXT_READY) {
700         *_errno = ECONNREFUSED;
701         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
702         goto unlock_and_fail;
703     }
704 
705     pa_threaded_mainloop_unlock(i->mainloop);
706     return i;
707 
708 unlock_and_fail:
709 
710     pa_threaded_mainloop_unlock(i->mainloop);
711 
712 fail:
713 
714     if (i)
715         fd_info_unref(i);
716 
717     return NULL;
718 }
719 
fd_info_add_to_list(fd_info * i)720 static void fd_info_add_to_list(fd_info *i) {
721     assert(i);
722 
723     pthread_mutex_lock(&fd_infos_mutex);
724     PA_LLIST_PREPEND(fd_info, fd_infos, i);
725     pthread_mutex_unlock(&fd_infos_mutex);
726 
727     fd_info_ref(i);
728 }
729 
fd_info_remove_from_list(fd_info * i)730 static void fd_info_remove_from_list(fd_info *i) {
731     assert(i);
732 
733     pthread_mutex_lock(&fd_infos_mutex);
734     PA_LLIST_REMOVE(fd_info, fd_infos, i);
735     pthread_mutex_unlock(&fd_infos_mutex);
736 
737     fd_info_unref(i);
738 }
739 
fd_info_find(int fd)740 static fd_info* fd_info_find(int fd) {
741     fd_info *i;
742 
743     pthread_mutex_lock(&fd_infos_mutex);
744 
745     for (i = fd_infos; i; i = i->next)
746         if (i->app_fd == fd && !i->unusable) {
747             fd_info_ref(i);
748             break;
749         }
750 
751     pthread_mutex_unlock(&fd_infos_mutex);
752 
753     return i;
754 }
755 
fix_metrics(fd_info * i)756 static void fix_metrics(fd_info *i) {
757     size_t fs;
758     char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
759 
760     fs = pa_frame_size(&i->sample_spec);
761 
762     /* Don't fix things more than necessary */
763     if ((i->fragment_size % fs) == 0 &&
764         i->n_fragments >= 2 &&
765         i->fragment_size > 0)
766         return;
767 
768     i->fragment_size = (i->fragment_size/fs)*fs;
769 
770     /* Number of fragments set? */
771     if (i->n_fragments < 2) {
772         if (i->fragment_size > 0) {
773             i->n_fragments = (unsigned) (pa_bytes_per_second(&i->sample_spec) / 2 / i->fragment_size);
774             if (i->n_fragments < 2)
775                 i->n_fragments = 2;
776         } else
777             i->n_fragments = 12;
778     }
779 
780     /* Fragment size set? */
781     if (i->fragment_size <= 0) {
782         i->fragment_size = pa_bytes_per_second(&i->sample_spec) / 2 / i->n_fragments;
783         if (i->fragment_size < 1024)
784             i->fragment_size = 1024;
785     }
786 
787     debug(DEBUG_LEVEL_NORMAL, __FILE__": sample spec: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
788     debug(DEBUG_LEVEL_NORMAL, __FILE__": fixated metrics to %i fragments, %li bytes each.\n", i->n_fragments, (long)i->fragment_size);
789 }
790 
stream_request_cb(pa_stream * s,size_t length,void * userdata)791 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
792     fd_info *i = userdata;
793     assert(s);
794 
795     if (i->io_event) {
796         pa_mainloop_api *api;
797         size_t n;
798 
799         api = pa_threaded_mainloop_get_api(i->mainloop);
800 
801         if (s == i->play_stream) {
802             n = pa_stream_writable_size(i->play_stream);
803             if (n == (size_t)-1) {
804                 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n",
805                     pa_strerror(pa_context_errno(i->context)));
806             }
807 
808             if (n >= i->fragment_size)
809                 i->io_flags |= PA_IO_EVENT_INPUT;
810             else
811                 i->io_flags &= ~PA_IO_EVENT_INPUT;
812         }
813 
814         if (s == i->rec_stream) {
815             n = pa_stream_readable_size(i->rec_stream);
816             if (n == (size_t)-1) {
817                 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n",
818                     pa_strerror(pa_context_errno(i->context)));
819             }
820 
821             if (n >= i->fragment_size)
822                 i->io_flags |= PA_IO_EVENT_OUTPUT;
823             else
824                 i->io_flags &= ~PA_IO_EVENT_OUTPUT;
825         }
826 
827         api->io_enable(i->io_event, i->io_flags);
828     }
829 }
830 
stream_latency_update_cb(pa_stream * s,void * userdata)831 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
832     fd_info *i = userdata;
833     assert(s);
834 
835     pa_threaded_mainloop_signal(i->mainloop, 0);
836 }
837 
fd_info_shutdown(fd_info * i)838 static void fd_info_shutdown(fd_info *i) {
839     assert(i);
840 
841     if (i->io_event) {
842         pa_mainloop_api *api;
843         api = pa_threaded_mainloop_get_api(i->mainloop);
844         api->io_free(i->io_event);
845         i->io_event = NULL;
846         i->io_flags = 0;
847     }
848 
849     if (i->thread_fd >= 0) {
850         close(i->thread_fd);
851         i->thread_fd = -1;
852     }
853 }
854 
fd_info_copy_data(fd_info * i,int force)855 static int fd_info_copy_data(fd_info *i, int force) {
856     size_t n;
857 
858     if (!i->play_stream && !i->rec_stream)
859         return -1;
860 
861     if ((i->play_stream) && (pa_stream_get_state(i->play_stream) == PA_STREAM_READY)) {
862         n = pa_stream_writable_size(i->play_stream);
863 
864         if (n == (size_t)-1) {
865             debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n",
866                 pa_strerror(pa_context_errno(i->context)));
867             return -1;
868         }
869 
870         while (n >= i->fragment_size || force) {
871             ssize_t r;
872             size_t to_write;
873 
874             if (!i->buf) {
875                 if (!(i->buf = malloc(i->fragment_size))) {
876                     debug(DEBUG_LEVEL_NORMAL, __FILE__": malloc() failed.\n");
877                     return -1;
878                 }
879 
880                 i->leftover = 0;
881             }
882 
883             if ((r = read(i->thread_fd, ((uint8_t *) i->buf) + i->leftover, i->fragment_size - i->leftover)) <= 0) {
884 
885                 if (errno == EAGAIN)
886                     break;
887 
888                 debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", r == 0 ? "EOF" : strerror(errno));
889                 return -1;
890             }
891 
892             to_write = pa_frame_align(r + i->leftover, &i->sample_spec);
893 
894             if (pa_stream_write(i->play_stream, i->buf, to_write, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
895                 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i->context)));
896                 return -1;
897             }
898 
899             i->leftover += r - to_write;
900             if (i->leftover)
901                 memmove(i->buf, ((uint8_t *) i->buf) + to_write, i->leftover);
902 
903             assert(n >= (size_t) to_write);
904             n -= (size_t) to_write;
905         }
906 
907         if (n >= i->fragment_size)
908             i->io_flags |= PA_IO_EVENT_INPUT;
909         else
910             i->io_flags &= ~PA_IO_EVENT_INPUT;
911     }
912 
913     if ((i->rec_stream) && (pa_stream_get_state(i->rec_stream) == PA_STREAM_READY)) {
914         n = pa_stream_readable_size(i->rec_stream);
915 
916         if (n == (size_t)-1) {
917             debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n",
918                 pa_strerror(pa_context_errno(i->context)));
919             return -1;
920         }
921 
922         while (n >= i->fragment_size || force) {
923             ssize_t r;
924             const void *data;
925             const char *buf;
926             size_t len;
927 
928             if (pa_stream_peek(i->rec_stream, &data, &len) < 0) {
929                 debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i->context)));
930                 return -1;
931             }
932 
933             if (len <= 0)
934                 break;
935 
936             if (!data) {
937                 /* Maybe we should generate silence here, but I'm lazy and
938                  * I'll just skip any holes in the stream. */
939                 if (pa_stream_drop(i->rec_stream) < 0) {
940                     debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i->context)));
941                     return -1;
942                 }
943 
944                 assert(n >= len);
945                 n -= len;
946                 continue;
947             }
948 
949             buf = (const char*)data + i->rec_offset;
950 
951             if ((r = write(i->thread_fd, buf, len - i->rec_offset)) <= 0) {
952 
953                 if (errno == EAGAIN)
954                     break;
955 
956                 debug(DEBUG_LEVEL_NORMAL, __FILE__": write(): %s\n", strerror(errno));
957                 return -1;
958             }
959 
960             assert((size_t)r <= len - i->rec_offset);
961             i->rec_offset += (size_t) r;
962 
963             if (i->rec_offset == len) {
964                 if (pa_stream_drop(i->rec_stream) < 0) {
965                     debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i->context)));
966                     return -1;
967                 }
968                 i->rec_offset = 0;
969             }
970 
971             assert(n >= (size_t) r);
972             n -= (size_t) r;
973         }
974 
975         if (n >= i->fragment_size)
976             i->io_flags |= PA_IO_EVENT_OUTPUT;
977         else
978             i->io_flags &= ~PA_IO_EVENT_OUTPUT;
979     }
980 
981     if (i->io_event) {
982         pa_mainloop_api *api;
983 
984         api = pa_threaded_mainloop_get_api(i->mainloop);
985         api->io_enable(i->io_event, i->io_flags);
986     }
987 
988     /* So, we emptied the socket now, let's tell dsp_empty_socket()
989      * about this */
990     pa_threaded_mainloop_signal(i->mainloop, 0);
991 
992     return 0;
993 }
994 
stream_state_cb(pa_stream * s,void * userdata)995 static void stream_state_cb(pa_stream *s, void * userdata) {
996     fd_info *i = userdata;
997     assert(s);
998 
999     switch (pa_stream_get_state(s)) {
1000 
1001         case PA_STREAM_READY:
1002             debug(DEBUG_LEVEL_NORMAL, __FILE__": stream established.\n");
1003             break;
1004 
1005         case PA_STREAM_FAILED:
1006             if (s == i->play_stream) {
1007                 debug(DEBUG_LEVEL_NORMAL,
1008                     __FILE__": pa_stream_connect_playback() failed: %s\n",
1009                     pa_strerror(pa_context_errno(i->context)));
1010                 pa_stream_unref(i->play_stream);
1011                 i->play_stream = NULL;
1012             } else if (s == i->rec_stream) {
1013                 debug(DEBUG_LEVEL_NORMAL,
1014                     __FILE__": pa_stream_connect_record() failed: %s\n",
1015                     pa_strerror(pa_context_errno(i->context)));
1016                 pa_stream_unref(i->rec_stream);
1017                 i->rec_stream = NULL;
1018             }
1019             fd_info_shutdown(i);
1020             break;
1021 
1022         case PA_STREAM_TERMINATED:
1023         case PA_STREAM_UNCONNECTED:
1024         case PA_STREAM_CREATING:
1025             break;
1026     }
1027 }
1028 
create_playback_stream(fd_info * i)1029 static int create_playback_stream(fd_info *i) {
1030     pa_buffer_attr attr;
1031     int n, flags;
1032 
1033     assert(i);
1034 
1035     fix_metrics(i);
1036 
1037     if (!(i->play_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) {
1038         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1039         goto fail;
1040     }
1041 
1042     pa_stream_set_state_callback(i->play_stream, stream_state_cb, i);
1043     pa_stream_set_write_callback(i->play_stream, stream_request_cb, i);
1044     pa_stream_set_latency_update_callback(i->play_stream, stream_latency_update_cb, i);
1045 
1046     memset(&attr, 0, sizeof(attr));
1047     attr.maxlength = (uint32_t) (i->fragment_size * (i->n_fragments+1));
1048     attr.tlength = (uint32_t) (i->fragment_size * i->n_fragments);
1049     attr.prebuf = (uint32_t) i->fragment_size;
1050     attr.minreq = (uint32_t) i->fragment_size;
1051 
1052     flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_EARLY_REQUESTS;
1053     if (i->play_precork) {
1054         flags |= PA_STREAM_START_CORKED;
1055         debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n");
1056     }
1057     if (pa_stream_connect_playback(i->play_stream, NULL, &attr, flags, NULL, NULL) < 0) {
1058         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1059         goto fail;
1060     }
1061 
1062     n = (int) i->fragment_size;
1063     setsockopt(i->app_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
1064     n = (int) i->fragment_size;
1065     setsockopt(i->thread_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
1066 
1067     return 0;
1068 
1069 fail:
1070     return -1;
1071 }
1072 
create_record_stream(fd_info * i)1073 static int create_record_stream(fd_info *i) {
1074     pa_buffer_attr attr;
1075     int n, flags;
1076 
1077     assert(i);
1078 
1079     fix_metrics(i);
1080 
1081     if (!(i->rec_stream = pa_stream_new(i->context, stream_name(), &i->sample_spec, NULL))) {
1082         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1083         goto fail;
1084     }
1085 
1086     pa_stream_set_state_callback(i->rec_stream, stream_state_cb, i);
1087     pa_stream_set_read_callback(i->rec_stream, stream_request_cb, i);
1088     pa_stream_set_latency_update_callback(i->rec_stream, stream_latency_update_cb, i);
1089 
1090     memset(&attr, 0, sizeof(attr));
1091     attr.maxlength = (uint32_t) (i->fragment_size * (i->n_fragments+1));
1092     attr.fragsize = (uint32_t) i->fragment_size;
1093 
1094     flags = PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE;
1095     if (i->rec_precork) {
1096         flags |= PA_STREAM_START_CORKED;
1097         debug(DEBUG_LEVEL_NORMAL, __FILE__": creating stream corked\n");
1098     }
1099     if (pa_stream_connect_record(i->rec_stream, NULL, &attr, flags) < 0) {
1100         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i->context)));
1101         goto fail;
1102     }
1103 
1104     n = (int) i->fragment_size;
1105     setsockopt(i->app_fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
1106     n = (int) i->fragment_size;
1107     setsockopt(i->thread_fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n));
1108 
1109     return 0;
1110 
1111 fail:
1112     return -1;
1113 }
1114 
free_streams(fd_info * i)1115 static void free_streams(fd_info *i) {
1116     assert(i);
1117 
1118     if (i->play_stream) {
1119         pa_stream_disconnect(i->play_stream);
1120         pa_stream_unref(i->play_stream);
1121         i->play_stream = NULL;
1122         i->io_flags |= PA_IO_EVENT_INPUT;
1123     }
1124 
1125     if (i->rec_stream) {
1126         pa_stream_disconnect(i->rec_stream);
1127         pa_stream_unref(i->rec_stream);
1128         i->rec_stream = NULL;
1129         i->io_flags |= PA_IO_EVENT_OUTPUT;
1130     }
1131 
1132     if (i->io_event) {
1133         pa_mainloop_api *api;
1134 
1135         api = pa_threaded_mainloop_get_api(i->mainloop);
1136         api->io_enable(i->io_event, i->io_flags);
1137     }
1138 }
1139 
io_event_cb(pa_mainloop_api * api,pa_io_event * e,int fd,pa_io_event_flags_t flags,void * userdata)1140 static void io_event_cb(pa_mainloop_api *api, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
1141     fd_info *i = userdata;
1142 
1143     pa_threaded_mainloop_signal(i->mainloop, 0);
1144 
1145     if (flags & PA_IO_EVENT_INPUT) {
1146 
1147         if (!i->play_stream) {
1148             if (create_playback_stream(i) < 0)
1149                 goto fail;
1150         } else {
1151             if (fd_info_copy_data(i, 0) < 0)
1152                 goto fail;
1153         }
1154 
1155     } else if (flags & PA_IO_EVENT_OUTPUT) {
1156 
1157         if (!i->rec_stream) {
1158             if (create_record_stream(i) < 0)
1159                 goto fail;
1160         } else {
1161             if (fd_info_copy_data(i, 0) < 0)
1162                 goto fail;
1163         }
1164 
1165     } else if (flags & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR))
1166         goto fail;
1167 
1168     return;
1169 
1170 fail:
1171     /* We can't do anything better than removing the event source */
1172     fd_info_shutdown(i);
1173 }
1174 
dsp_open(int flags,int * _errno)1175 static int dsp_open(int flags, int *_errno) {
1176     fd_info *i;
1177     pa_mainloop_api *api;
1178     int ret;
1179     int f;
1180 
1181     debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open()\n");
1182 
1183     if (!(i = fd_info_new(FD_INFO_STREAM, _errno)))
1184         return -1;
1185 
1186     if ((flags & O_NONBLOCK) == O_NONBLOCK) {
1187         if ((f = fcntl(i->app_fd, F_GETFL)) >= 0)
1188             fcntl(i->app_fd, F_SETFL, f|O_NONBLOCK);
1189     }
1190     if ((f = fcntl(i->thread_fd, F_GETFL)) >= 0)
1191         fcntl(i->thread_fd, F_SETFL, f|O_NONBLOCK);
1192 
1193     fcntl(i->app_fd, F_SETFD, FD_CLOEXEC);
1194     fcntl(i->thread_fd, F_SETFD, FD_CLOEXEC);
1195 
1196     pa_threaded_mainloop_lock(i->mainloop);
1197     api = pa_threaded_mainloop_get_api(i->mainloop);
1198 
1199     switch (flags & O_ACCMODE) {
1200     case O_RDONLY:
1201         i->io_flags = PA_IO_EVENT_OUTPUT;
1202         shutdown(i->thread_fd, SHUT_RD);
1203         shutdown(i->app_fd, SHUT_WR);
1204         break;
1205     case O_WRONLY:
1206         i->io_flags = PA_IO_EVENT_INPUT;
1207         shutdown(i->thread_fd, SHUT_WR);
1208         shutdown(i->app_fd, SHUT_RD);
1209         break;
1210     case O_RDWR:
1211         i->io_flags = PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT;
1212         break;
1213     default:
1214         pa_threaded_mainloop_unlock(i->mainloop);
1215         fd_info_unref(i);
1216         *_errno = EIO;
1217         return -1;
1218     }
1219 
1220     if (!(i->io_event = api->io_new(api, i->thread_fd, i->io_flags, io_event_cb, i)))
1221         goto fail;
1222 
1223     pa_threaded_mainloop_unlock(i->mainloop);
1224 
1225     debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() succeeded, fd=%i\n", i->app_fd);
1226 
1227     fd_info_add_to_list(i);
1228     ret = i->app_fd;
1229     fd_info_unref(i);
1230 
1231     return ret;
1232 
1233 fail:
1234     pa_threaded_mainloop_unlock(i->mainloop);
1235 
1236     if (i)
1237         fd_info_unref(i);
1238 
1239     *_errno = EIO;
1240 
1241     debug(DEBUG_LEVEL_NORMAL, __FILE__": dsp_open() failed\n");
1242 
1243     return -1;
1244 }
1245 
sink_info_cb(pa_context * context,const pa_sink_info * si,int eol,void * userdata)1246 static void sink_info_cb(pa_context *context, const pa_sink_info *si, int eol, void *userdata) {
1247     fd_info *i = userdata;
1248 
1249     if (eol < 0) {
1250         i->operation_success = 0;
1251         pa_threaded_mainloop_signal(i->mainloop, 0);
1252         return;
1253     }
1254 
1255     if (eol)
1256         return;
1257 
1258     if (!pa_cvolume_equal(&i->sink_volume, &si->volume))
1259         i->volume_modify_count++;
1260 
1261     i->sink_volume = si->volume;
1262     i->sink_index = si->index;
1263 
1264     i->operation_success = 1;
1265     pa_threaded_mainloop_signal(i->mainloop, 0);
1266 }
1267 
source_info_cb(pa_context * context,const pa_source_info * si,int eol,void * userdata)1268 static void source_info_cb(pa_context *context, const pa_source_info *si, int eol, void *userdata) {
1269     fd_info *i = userdata;
1270 
1271     if (eol < 0) {
1272         i->operation_success = 0;
1273         pa_threaded_mainloop_signal(i->mainloop, 0);
1274         return;
1275     }
1276 
1277     if (eol)
1278         return;
1279 
1280     if (!pa_cvolume_equal(&i->source_volume, &si->volume))
1281         i->volume_modify_count++;
1282 
1283     i->source_volume = si->volume;
1284     i->source_index = si->index;
1285 
1286     i->operation_success = 1;
1287     pa_threaded_mainloop_signal(i->mainloop, 0);
1288 }
1289 
subscribe_cb(pa_context * context,pa_subscription_event_type_t t,uint32_t idx,void * userdata)1290 static void subscribe_cb(pa_context *context, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
1291     fd_info *i = userdata;
1292     pa_operation *o = NULL;
1293 
1294     if (i->sink_index != idx)
1295         return;
1296 
1297     if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
1298         return;
1299 
1300     if (!(o = pa_context_get_sink_info_by_index(i->context, i->sink_index, sink_info_cb, i))) {
1301         debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1302         return;
1303     }
1304 
1305     pa_operation_unref(o);
1306 }
1307 
mixer_open(int flags,int * _errno)1308 static int mixer_open(int flags, int *_errno) {
1309     fd_info *i;
1310     pa_operation *o = NULL;
1311     int ret;
1312 
1313     debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open()\n");
1314 
1315     if (!(i = fd_info_new(FD_INFO_MIXER, _errno)))
1316         return -1;
1317 
1318     pa_threaded_mainloop_lock(i->mainloop);
1319 
1320     pa_context_set_subscribe_callback(i->context, subscribe_cb, i);
1321 
1322     if (!(o = pa_context_subscribe(i->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, context_success_cb, i))) {
1323         debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context)));
1324         *_errno = EIO;
1325         goto fail;
1326     }
1327 
1328     i->operation_success = 0;
1329     while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1330         pa_threaded_mainloop_wait(i->mainloop);
1331         CONTEXT_CHECK_DEAD_GOTO(i, fail);
1332     }
1333 
1334     pa_operation_unref(o);
1335     o = NULL;
1336 
1337     if (!i->operation_success) {
1338         debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i->context)));
1339         *_errno = EIO;
1340         goto fail;
1341     }
1342 
1343     /* Get sink info */
1344 
1345     if (!(o = pa_context_get_sink_info_by_name(i->context, NULL, sink_info_cb, i))) {
1346         debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1347         *_errno = EIO;
1348         goto fail;
1349     }
1350 
1351     i->operation_success = 0;
1352     while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1353         pa_threaded_mainloop_wait(i->mainloop);
1354         CONTEXT_CHECK_DEAD_GOTO(i, fail);
1355     }
1356 
1357     pa_operation_unref(o);
1358     o = NULL;
1359 
1360     if (!i->operation_success) {
1361         debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get sink info: %s", pa_strerror(pa_context_errno(i->context)));
1362         *_errno = EIO;
1363         goto fail;
1364     }
1365 
1366     /* Get source info */
1367 
1368     if (!(o = pa_context_get_source_info_by_name(i->context, NULL, source_info_cb, i))) {
1369         debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context)));
1370         *_errno = EIO;
1371         goto fail;
1372     }
1373 
1374     i->operation_success = 0;
1375     while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1376         pa_threaded_mainloop_wait(i->mainloop);
1377         CONTEXT_CHECK_DEAD_GOTO(i, fail);
1378     }
1379 
1380     pa_operation_unref(o);
1381     o = NULL;
1382 
1383     if (!i->operation_success) {
1384         debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to get source info: %s", pa_strerror(pa_context_errno(i->context)));
1385         *_errno = EIO;
1386         goto fail;
1387     }
1388 
1389     pa_threaded_mainloop_unlock(i->mainloop);
1390 
1391     debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() succeeded, fd=%i\n", i->app_fd);
1392 
1393     fd_info_add_to_list(i);
1394     ret = i->app_fd;
1395     fd_info_unref(i);
1396 
1397     return ret;
1398 
1399 fail:
1400     if (o)
1401         pa_operation_unref(o);
1402 
1403     pa_threaded_mainloop_unlock(i->mainloop);
1404 
1405     if (i)
1406         fd_info_unref(i);
1407 
1408     *_errno = EIO;
1409 
1410     debug(DEBUG_LEVEL_NORMAL, __FILE__": mixer_open() failed\n");
1411 
1412     return -1;
1413 }
1414 
sndstat_open(int flags,int * _errno)1415 static int sndstat_open(int flags, int *_errno) {
1416     static const char sndstat[] =
1417         "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n"
1418         "Kernel: POSIX\n"
1419         "Config options: 0\n"
1420         "\n"
1421         "Installed drivers:\n"
1422         "Type 255: PulseAudio Virtual OSS\n"
1423         "\n"
1424         "Card config:\n"
1425         "PulseAudio Virtual OSS\n"
1426         "\n"
1427         "Audio devices:\n"
1428         "0: PulseAudio Virtual OSS\n"
1429         "\n"
1430         "Synth devices: NOT ENABLED IN CONFIG\n"
1431         "\n"
1432         "Midi devices:\n"
1433         "\n"
1434         "Timers:\n"
1435         "\n"
1436         "Mixers:\n"
1437         "0: PulseAudio Virtual OSS\n";
1438 
1439     char *fn;
1440     mode_t u;
1441     int fd = -1;
1442     int e;
1443 
1444     fn = pa_sprintf_malloc("%s" PA_PATH_SEP "padsp-sndstat-XXXXXX", pa_get_temp_dir());
1445 
1446     debug(DEBUG_LEVEL_NORMAL, __FILE__": sndstat_open()\n");
1447 
1448     if (flags != O_RDONLY
1449 #ifdef O_LARGEFILE
1450         && flags != (O_RDONLY|O_LARGEFILE)
1451 #endif
1452        ) {
1453         *_errno = EACCES;
1454         debug(DEBUG_LEVEL_NORMAL, __FILE__": bad access!\n");
1455         goto fail;
1456     }
1457 
1458     u = umask(0077);
1459     fd = mkstemp(fn);
1460     e = errno;
1461     umask(u);
1462 
1463     if (fd < 0) {
1464         *_errno = e;
1465         debug(DEBUG_LEVEL_NORMAL, __FILE__": mkstemp() failed: %s\n", strerror(errno));
1466         goto fail;
1467     }
1468 
1469     unlink(fn);
1470     pa_xfree(fn);
1471     fn = NULL;
1472 
1473     if (write(fd, sndstat, sizeof(sndstat) -1) != sizeof(sndstat)-1) {
1474         *_errno = errno;
1475         debug(DEBUG_LEVEL_NORMAL, __FILE__": write() failed: %s\n", strerror(errno));
1476         goto fail;
1477     }
1478 
1479     if (lseek(fd, SEEK_SET, 0) < 0) {
1480         *_errno = errno;
1481         debug(DEBUG_LEVEL_NORMAL, __FILE__": lseek() failed: %s\n", strerror(errno));
1482         goto fail;
1483     }
1484 
1485     return fd;
1486 
1487 fail:
1488     pa_xfree(fn);
1489     if (fd >= 0)
1490         close(fd);
1491     return -1;
1492 }
1493 
real_open(const char * filename,int flags,mode_t mode)1494 static int real_open(const char *filename, int flags, mode_t mode) {
1495     int r, _errno = 0;
1496 
1497     debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename?filename:"NULL");
1498 
1499     if (!function_enter()) {
1500         LOAD_OPEN_FUNC();
1501         return _open(filename, flags, mode);
1502     }
1503 
1504     if (filename && dsp_cloak_enable() && (pa_streq(filename, "/dev/dsp") || pa_streq(filename, "/dev/adsp") || pa_streq(filename, "/dev/audio")))
1505         r = dsp_open(flags, &_errno);
1506     else if (filename && mixer_cloak_enable() && pa_streq(filename, "/dev/mixer"))
1507         r = mixer_open(flags, &_errno);
1508     else if (filename && sndstat_cloak_enable() && pa_streq(filename, "/dev/sndstat"))
1509         r = sndstat_open(flags, &_errno);
1510     else {
1511         function_exit();
1512         LOAD_OPEN_FUNC();
1513         return _open(filename, flags, mode);
1514     }
1515 
1516     function_exit();
1517 
1518     if (_errno)
1519         errno = _errno;
1520 
1521     return r;
1522 }
1523 
open(const char * filename,int flags,...)1524 int open(const char *filename, int flags, ...) {
1525     va_list args;
1526     mode_t mode = 0;
1527 
1528     if (flags & O_CREAT) {
1529         va_start(args, flags);
1530         if (sizeof(mode_t) < sizeof(int))
1531             mode = (mode_t) va_arg(args, int);
1532         else
1533             mode = va_arg(args, mode_t);
1534         va_end(args);
1535     }
1536 
1537     return real_open(filename, flags, mode);
1538 }
1539 
is_audio_device_node(const char * path)1540 static bool is_audio_device_node(const char *path) {
1541     return
1542         pa_streq(path, "/dev/dsp") ||
1543         pa_streq(path, "/dev/adsp") ||
1544         pa_streq(path, "/dev/audio") ||
1545         pa_streq(path, "/dev/sndstat") ||
1546         pa_streq(path, "/dev/mixer");
1547 }
1548 
__open_2(const char * filename,int flags)1549 int __open_2(const char *filename, int flags) {
1550     debug(DEBUG_LEVEL_VERBOSE, __FILE__": __open_2(%s)\n", filename?filename:"NULL");
1551 
1552     if ((flags & O_CREAT) ||
1553         !filename ||
1554         !is_audio_device_node(filename)) {
1555         LOAD___OPEN_2_FUNC();
1556         return ___open_2(filename, flags);
1557     }
1558     return real_open(filename, flags, 0);
1559 }
1560 
mixer_ioctl(fd_info * i,unsigned long request,void * argp,int * _errno)1561 static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
1562     int ret = -1;
1563 
1564     switch (request) {
1565         case SOUND_MIXER_READ_DEVMASK :
1566             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_DEVMASK\n");
1567 
1568             *(int*) argp = SOUND_MASK_PCM | SOUND_MASK_IGAIN;
1569             break;
1570 
1571         case SOUND_MIXER_READ_RECMASK :
1572             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECMASK\n");
1573 
1574             *(int*) argp = SOUND_MASK_IGAIN;
1575             break;
1576 
1577         case SOUND_MIXER_READ_STEREODEVS:
1578             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_STEREODEVS\n");
1579 
1580             pa_threaded_mainloop_lock(i->mainloop);
1581             *(int*) argp = 0;
1582             if (i->sink_volume.channels > 1)
1583                 *(int*) argp |= SOUND_MASK_PCM;
1584             if (i->source_volume.channels > 1)
1585                 *(int*) argp |= SOUND_MASK_IGAIN;
1586             pa_threaded_mainloop_unlock(i->mainloop);
1587 
1588             break;
1589 
1590         case SOUND_MIXER_READ_RECSRC:
1591             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_RECSRC\n");
1592 
1593             *(int*) argp = SOUND_MASK_IGAIN;
1594             break;
1595 
1596         case SOUND_MIXER_WRITE_RECSRC:
1597             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_RECSRC\n");
1598             break;
1599 
1600         case SOUND_MIXER_READ_CAPS:
1601             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_CAPS\n");
1602 
1603             *(int*) argp = 0;
1604             break;
1605 
1606         case SOUND_MIXER_READ_PCM:
1607         case SOUND_MIXER_READ_IGAIN: {
1608             pa_cvolume *v;
1609 
1610             if (request == SOUND_MIXER_READ_PCM)
1611                 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_PCM\n");
1612             else
1613                 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_READ_IGAIN\n");
1614 
1615             pa_threaded_mainloop_lock(i->mainloop);
1616 
1617             if (request == SOUND_MIXER_READ_PCM)
1618                 v = &i->sink_volume;
1619             else
1620                 v = &i->source_volume;
1621 
1622             *(int*) argp =
1623                 ((v->values[0]*100/PA_VOLUME_NORM)) |
1624                 ((v->values[v->channels > 1 ? 1 : 0]*100/PA_VOLUME_NORM) << 8);
1625 
1626             pa_threaded_mainloop_unlock(i->mainloop);
1627 
1628             break;
1629         }
1630 
1631         case SOUND_MIXER_WRITE_PCM:
1632         case SOUND_MIXER_WRITE_IGAIN: {
1633             pa_cvolume v, *pv;
1634 
1635             if (request == SOUND_MIXER_WRITE_PCM)
1636                 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_PCM\n");
1637             else
1638                 debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_WRITE_IGAIN\n");
1639 
1640             pa_threaded_mainloop_lock(i->mainloop);
1641 
1642             if (request == SOUND_MIXER_WRITE_PCM) {
1643                 v = i->sink_volume;
1644                 pv = &i->sink_volume;
1645             } else {
1646                 v = i->source_volume;
1647                 pv = &i->source_volume;
1648             }
1649 
1650             pv->values[0] = ((*(int*) argp & 0xFF)*PA_VOLUME_NORM)/100;
1651             pv->values[1] = ((*(int*) argp >> 8)*PA_VOLUME_NORM)/100;
1652 
1653             if (!pa_cvolume_equal(pv, &v)) {
1654                 pa_operation *o;
1655 
1656                 if (request == SOUND_MIXER_WRITE_PCM)
1657                     o = pa_context_set_sink_volume_by_index(i->context, i->sink_index, pv, context_success_cb, i);
1658                 else
1659                     o = pa_context_set_source_volume_by_index(i->context, i->source_index, pv, context_success_cb, i);
1660 
1661                 if (!o)
1662                     debug(DEBUG_LEVEL_NORMAL, __FILE__":Failed set volume: %s", pa_strerror(pa_context_errno(i->context)));
1663                 else {
1664 
1665                     i->operation_success = 0;
1666                     while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1667                         CONTEXT_CHECK_DEAD_GOTO(i, exit_loop);
1668 
1669                         pa_threaded_mainloop_wait(i->mainloop);
1670                     }
1671                 exit_loop:
1672 
1673                     if (!i->operation_success)
1674                         debug(DEBUG_LEVEL_NORMAL, __FILE__": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i->context)));
1675 
1676                     pa_operation_unref(o);
1677                 }
1678 
1679                 /* We don't wait for completion here */
1680                 i->volume_modify_count++;
1681             }
1682 
1683             pa_threaded_mainloop_unlock(i->mainloop);
1684 
1685             break;
1686         }
1687 
1688         case SOUND_MIXER_INFO: {
1689             mixer_info *mi = argp;
1690 
1691             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_MIXER_INFO\n");
1692 
1693             memset(mi, 0, sizeof(mixer_info));
1694             strncpy(mi->id, "PULSEAUDIO", sizeof(mi->id));
1695             strncpy(mi->name, "PulseAudio Virtual OSS", sizeof(mi->name));
1696             pa_threaded_mainloop_lock(i->mainloop);
1697             mi->modify_counter = i->volume_modify_count;
1698             pa_threaded_mainloop_unlock(i->mainloop);
1699             break;
1700         }
1701 
1702         default:
1703             debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request);
1704 
1705             *_errno = EINVAL;
1706             goto fail;
1707     }
1708 
1709     ret = 0;
1710 
1711 fail:
1712 
1713     return ret;
1714 }
1715 
map_format(int * fmt,pa_sample_spec * ss)1716 static int map_format(int *fmt, pa_sample_spec *ss) {
1717 
1718     switch (*fmt) {
1719         case AFMT_MU_LAW:
1720             ss->format = PA_SAMPLE_ULAW;
1721             break;
1722 
1723         case AFMT_A_LAW:
1724             ss->format = PA_SAMPLE_ALAW;
1725             break;
1726 
1727         case AFMT_S8:
1728             *fmt = AFMT_U8;
1729             /* fall through */
1730         case AFMT_U8:
1731             ss->format = PA_SAMPLE_U8;
1732             break;
1733 
1734         case AFMT_U16_BE:
1735             *fmt = AFMT_S16_BE;
1736             /* fall through */
1737         case AFMT_S16_BE:
1738             ss->format = PA_SAMPLE_S16BE;
1739             break;
1740 
1741         case AFMT_U16_LE:
1742             *fmt = AFMT_S16_LE;
1743             /* fall through */
1744         case AFMT_S16_LE:
1745             ss->format = PA_SAMPLE_S16LE;
1746             break;
1747 
1748         default:
1749             ss->format = PA_SAMPLE_S16NE;
1750             *fmt = AFMT_S16_NE;
1751             break;
1752     }
1753 
1754     return 0;
1755 }
1756 
map_format_back(pa_sample_format_t format)1757 static int map_format_back(pa_sample_format_t format) {
1758     switch (format) {
1759         case PA_SAMPLE_S16LE: return AFMT_S16_LE;
1760         case PA_SAMPLE_S16BE: return AFMT_S16_BE;
1761         case PA_SAMPLE_ULAW: return AFMT_MU_LAW;
1762         case PA_SAMPLE_ALAW: return AFMT_A_LAW;
1763         case PA_SAMPLE_U8: return AFMT_U8;
1764         default:
1765             abort();
1766     }
1767 }
1768 
dsp_flush_fd(int fd)1769 static int dsp_flush_fd(int fd) {
1770 #ifdef SIOCINQ
1771     int l;
1772 
1773     if (ioctl(fd, SIOCINQ, &l) < 0) {
1774         debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno));
1775         return -1;
1776     }
1777 
1778     while (l > 0) {
1779         char buf[1024];
1780         size_t k;
1781         ssize_t r;
1782 
1783         k = (size_t) l > sizeof(buf) ? sizeof(buf) : (size_t) l;
1784         r = read(fd, buf, k);
1785         if (r < 0) {
1786             if (errno == EAGAIN)
1787                 break;
1788             debug(DEBUG_LEVEL_NORMAL, __FILE__": read(): %s\n", strerror(errno));
1789             return -1;
1790         } else if (r == 0)
1791             break;
1792         l -= r;
1793     }
1794 
1795     return 0;
1796 #else
1797 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1798     return 0;
1799 #endif
1800 }
1801 
dsp_flush_socket(fd_info * i)1802 static int dsp_flush_socket(fd_info *i) {
1803     int res = 0;
1804 
1805     if ((i->thread_fd < 0) && (i->app_fd < 0))
1806         return -1;
1807 
1808     if (i->thread_fd >= 0)
1809         res = dsp_flush_fd(i->thread_fd);
1810 
1811     if (res < 0)
1812         return res;
1813 
1814     if (i->app_fd >= 0)
1815         res = dsp_flush_fd(i->app_fd);
1816 
1817     if (res < 0)
1818         return res;
1819 
1820     return 0;
1821 }
1822 
dsp_empty_socket(fd_info * i)1823 static int dsp_empty_socket(fd_info *i) {
1824 #ifdef SIOCINQ
1825     int ret = -1;
1826 
1827     /* Empty the socket */
1828     for (;;) {
1829         int l;
1830 
1831         if (i->thread_fd < 0)
1832             break;
1833 
1834         if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
1835             debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ: %s\n", strerror(errno));
1836             break;
1837         }
1838 
1839         if (!l) {
1840             ret = 0;
1841             break;
1842         }
1843 
1844         pa_threaded_mainloop_wait(i->mainloop);
1845     }
1846 
1847     return ret;
1848 #else
1849 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1850     return 0;
1851 #endif
1852 }
1853 
dsp_drain(fd_info * i)1854 static int dsp_drain(fd_info *i) {
1855     pa_operation *o = NULL;
1856     int r = -1;
1857 
1858     if (!i->mainloop)
1859         return 0;
1860 
1861     debug(DEBUG_LEVEL_NORMAL, __FILE__": Draining.\n");
1862 
1863     pa_threaded_mainloop_lock(i->mainloop);
1864 
1865     if (dsp_empty_socket(i) < 0)
1866         goto fail;
1867 
1868     if (!i->play_stream)
1869         goto fail;
1870 
1871     debug(DEBUG_LEVEL_NORMAL, __FILE__": Really draining.\n");
1872 
1873     if (!(o = pa_stream_drain(i->play_stream, stream_success_cb, i))) {
1874         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i->context)));
1875         goto fail;
1876     }
1877 
1878     i->operation_success = 0;
1879     while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1880         PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1881 
1882         pa_threaded_mainloop_wait(i->mainloop);
1883     }
1884 
1885     if (!i->operation_success) {
1886         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i->context)));
1887         goto fail;
1888     }
1889 
1890     r = 0;
1891 
1892 fail:
1893 
1894     if (o)
1895         pa_operation_unref(o);
1896 
1897     pa_threaded_mainloop_unlock(i->mainloop);
1898 
1899     return r;
1900 }
1901 
dsp_trigger(fd_info * i)1902 static int dsp_trigger(fd_info *i) {
1903     pa_operation *o = NULL;
1904     int r = -1;
1905 
1906     if (!i->play_stream)
1907         return 0;
1908 
1909     pa_threaded_mainloop_lock(i->mainloop);
1910 
1911     if (dsp_empty_socket(i) < 0)
1912         goto fail;
1913 
1914     debug(DEBUG_LEVEL_NORMAL, __FILE__": Triggering.\n");
1915 
1916     if (!(o = pa_stream_trigger(i->play_stream, stream_success_cb, i))) {
1917         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
1918         goto fail;
1919     }
1920 
1921     i->operation_success = 0;
1922     while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1923         PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1924 
1925         pa_threaded_mainloop_wait(i->mainloop);
1926     }
1927 
1928     if (!i->operation_success) {
1929         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i->context)));
1930         goto fail;
1931     }
1932 
1933     r = 0;
1934 
1935 fail:
1936 
1937     if (o)
1938         pa_operation_unref(o);
1939 
1940     pa_threaded_mainloop_unlock(i->mainloop);
1941 
1942     return r;
1943 }
1944 
dsp_cork(fd_info * i,pa_stream * s,int b)1945 static int dsp_cork(fd_info *i, pa_stream *s, int b) {
1946     pa_operation *o = NULL;
1947     int r = -1;
1948 
1949     pa_threaded_mainloop_lock(i->mainloop);
1950 
1951     if (!(o = pa_stream_cork(s, b, stream_success_cb, i))) {
1952         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context)));
1953         goto fail;
1954     }
1955 
1956     i->operation_success = 0;
1957     while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
1958         if (s == i->play_stream)
1959             PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, fail);
1960         else if (s == i->rec_stream)
1961             RECORD_STREAM_CHECK_DEAD_GOTO(i, fail);
1962 
1963         pa_threaded_mainloop_wait(i->mainloop);
1964     }
1965 
1966     if (!i->operation_success) {
1967         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i->context)));
1968         goto fail;
1969     }
1970 
1971     r = 0;
1972 
1973 fail:
1974 
1975     if (o)
1976         pa_operation_unref(o);
1977 
1978     pa_threaded_mainloop_unlock(i->mainloop);
1979 
1980     return r;
1981 }
1982 
dsp_ioctl(fd_info * i,unsigned long request,void * argp,int * _errno)1983 static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
1984     int ret = -1;
1985 
1986     if (i->thread_fd == -1) {
1987         /*
1988          * We've encountered some fatal error and are just waiting
1989          * for a close.
1990          */
1991         debug(DEBUG_LEVEL_NORMAL, __FILE__": got ioctl 0x%08lx in fatal error state\n", request);
1992         *_errno = EIO;
1993         return -1;
1994     }
1995 
1996     switch (request) {
1997         case SNDCTL_DSP_SETFMT: {
1998             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp);
1999 
2000             pa_threaded_mainloop_lock(i->mainloop);
2001 
2002             if (*(int*) argp == AFMT_QUERY)
2003                 *(int*) argp = map_format_back(i->sample_spec.format);
2004             else {
2005                 map_format((int*) argp, &i->sample_spec);
2006                 free_streams(i);
2007             }
2008 
2009             pa_threaded_mainloop_unlock(i->mainloop);
2010             break;
2011         }
2012 
2013         case SNDCTL_DSP_SPEED: {
2014             pa_sample_spec ss;
2015             int valid;
2016             char t[256];
2017 
2018             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SPEED: %i\n", *(int*) argp);
2019 
2020             pa_threaded_mainloop_lock(i->mainloop);
2021 
2022             ss = i->sample_spec;
2023             ss.rate = *(int*) argp;
2024 
2025             if ((valid = pa_sample_spec_valid(&ss))) {
2026                 i->sample_spec = ss;
2027                 free_streams(i);
2028             }
2029 
2030             debug(DEBUG_LEVEL_NORMAL, __FILE__": ss: %s\n", pa_sample_spec_snprint(t, sizeof(t), &i->sample_spec));
2031 
2032             pa_threaded_mainloop_unlock(i->mainloop);
2033 
2034             if (!valid) {
2035                 *_errno = EINVAL;
2036                 goto fail;
2037             }
2038 
2039             break;
2040         }
2041 
2042         case SNDCTL_DSP_STEREO:
2043             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_STEREO: %i\n", *(int*) argp);
2044 
2045             pa_threaded_mainloop_lock(i->mainloop);
2046 
2047             i->sample_spec.channels = *(int*) argp ? 2 : 1;
2048             free_streams(i);
2049 
2050             pa_threaded_mainloop_unlock(i->mainloop);
2051             return 0;
2052 
2053         case SNDCTL_DSP_CHANNELS: {
2054             pa_sample_spec ss;
2055             int valid;
2056 
2057             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp);
2058 
2059             pa_threaded_mainloop_lock(i->mainloop);
2060 
2061             ss = i->sample_spec;
2062             ss.channels = *(int*) argp;
2063 
2064             if ((valid = pa_sample_spec_valid(&ss))) {
2065                 i->sample_spec = ss;
2066                 free_streams(i);
2067             }
2068 
2069             pa_threaded_mainloop_unlock(i->mainloop);
2070 
2071             if (!valid) {
2072                 *_errno = EINVAL;
2073                 goto fail;
2074             }
2075 
2076             break;
2077         }
2078 
2079         case SNDCTL_DSP_GETBLKSIZE:
2080             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETBLKSIZE\n");
2081 
2082             pa_threaded_mainloop_lock(i->mainloop);
2083 
2084             fix_metrics(i);
2085             *(int*) argp = i->fragment_size;
2086 
2087             pa_threaded_mainloop_unlock(i->mainloop);
2088 
2089             break;
2090 
2091         case SNDCTL_DSP_SETFRAGMENT:
2092             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp);
2093 
2094             pa_threaded_mainloop_lock(i->mainloop);
2095 
2096             i->fragment_size = 1 << ((*(int*) argp) & 31);
2097             i->n_fragments = (*(int*) argp) >> 16;
2098 
2099             /* 0x7FFF means that we can set whatever we like */
2100             if (i->n_fragments == 0x7FFF)
2101                 i->n_fragments = 12;
2102 
2103             free_streams(i);
2104 
2105             pa_threaded_mainloop_unlock(i->mainloop);
2106 
2107             break;
2108 
2109         case SNDCTL_DSP_GETCAPS:
2110             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_CAPS\n");
2111 
2112             *(int*) argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER
2113 #ifdef DSP_CAP_MULTI
2114               | DSP_CAP_MULTI
2115 #endif
2116               ;
2117             break;
2118 
2119         case SNDCTL_DSP_GETODELAY: {
2120             int l;
2121 
2122             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETODELAY\n");
2123 
2124             pa_threaded_mainloop_lock(i->mainloop);
2125 
2126             *(int*) argp = 0;
2127 
2128             for (;;) {
2129                 pa_usec_t usec;
2130 
2131                 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop);
2132 
2133                 if (pa_stream_get_latency(i->play_stream, &usec, NULL) >= 0) {
2134                     *(int*) argp = pa_usec_to_bytes(usec, &i->sample_spec);
2135                     break;
2136                 }
2137 
2138                 if (pa_context_errno(i->context) != PA_ERR_NODATA) {
2139                     debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context)));
2140                     break;
2141                 }
2142 
2143                 pa_threaded_mainloop_wait(i->mainloop);
2144             }
2145 
2146         exit_loop:
2147 
2148 #ifdef SIOCINQ
2149             if (ioctl(i->thread_fd, SIOCINQ, &l) < 0)
2150                 debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2151             else
2152                 *(int*) argp += l;
2153 #else
2154 # warning "Your platform does not support SIOCINQ, something might not work as intended."
2155 #endif
2156 
2157             pa_threaded_mainloop_unlock(i->mainloop);
2158 
2159             debug(DEBUG_LEVEL_NORMAL, __FILE__": ODELAY: %i\n", *(int*) argp);
2160 
2161             break;
2162         }
2163 
2164         case SNDCTL_DSP_RESET: {
2165             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_RESET\n");
2166 
2167             pa_threaded_mainloop_lock(i->mainloop);
2168 
2169             free_streams(i);
2170             dsp_flush_socket(i);
2171 
2172             i->optr_n_blocks = 0;
2173 
2174             pa_threaded_mainloop_unlock(i->mainloop);
2175             break;
2176         }
2177 
2178         case SNDCTL_DSP_GETFMTS: {
2179             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETFMTS\n");
2180 
2181             *(int*) argp = AFMT_MU_LAW|AFMT_A_LAW|AFMT_U8|AFMT_S16_LE|AFMT_S16_BE;
2182             break;
2183         }
2184 
2185         case SNDCTL_DSP_POST:
2186             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_POST\n");
2187 
2188             if (dsp_trigger(i) < 0)
2189                 *_errno = EIO;
2190             break;
2191 
2192         case SNDCTL_DSP_GETTRIGGER:
2193             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETTRIGGER\n");
2194 
2195             *(int*) argp = 0;
2196             if (!i->play_precork)
2197                 *(int*) argp |= PCM_ENABLE_OUTPUT;
2198             if (!i->rec_precork)
2199                 *(int*) argp |= PCM_ENABLE_INPUT;
2200 
2201             break;
2202 
2203         case SNDCTL_DSP_SETTRIGGER:
2204             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp);
2205 
2206             if (!i->io_event) {
2207                 *_errno = EIO;
2208                 break;
2209             }
2210 
2211             i->play_precork = !((*(int*) argp) & PCM_ENABLE_OUTPUT);
2212 
2213             if (i->play_stream) {
2214                 if (dsp_cork(i, i->play_stream, !((*(int*) argp) & PCM_ENABLE_OUTPUT)) < 0)
2215                     *_errno = EIO;
2216                 if (dsp_trigger(i) < 0)
2217                     *_errno = EIO;
2218             }
2219 
2220             i->rec_precork = !((*(int*) argp) & PCM_ENABLE_INPUT);
2221 
2222             if (i->rec_stream) {
2223                 if (dsp_cork(i, i->rec_stream, !((*(int*) argp) & PCM_ENABLE_INPUT)) < 0)
2224                     *_errno = EIO;
2225             }
2226 
2227             break;
2228 
2229         case SNDCTL_DSP_SYNC:
2230             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SYNC\n");
2231 
2232             if (dsp_drain(i) < 0)
2233                 *_errno = EIO;
2234 
2235             break;
2236 
2237         case SNDCTL_DSP_GETOSPACE:
2238         case SNDCTL_DSP_GETISPACE: {
2239             audio_buf_info *bi = (audio_buf_info*) argp;
2240             int l = 0;
2241             size_t k = 0;
2242 
2243             if (request == SNDCTL_DSP_GETOSPACE)
2244                 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOSPACE\n");
2245             else
2246                 debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETISPACE\n");
2247 
2248             pa_threaded_mainloop_lock(i->mainloop);
2249 
2250             fix_metrics(i);
2251 
2252             if (request == SNDCTL_DSP_GETOSPACE) {
2253                 if (i->play_stream) {
2254                     if ((k = pa_stream_writable_size(i->play_stream)) == (size_t) -1)
2255                         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
2256                 } else
2257                     k = i->fragment_size * i->n_fragments;
2258 
2259 #ifdef SIOCINQ
2260                 if (ioctl(i->thread_fd, SIOCINQ, &l) < 0) {
2261                     debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2262                     l = 0;
2263                 }
2264 #else
2265 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2266 #endif
2267 
2268                 bi->bytes = k > (size_t) l ? k - l : 0;
2269             } else {
2270                 if (i->rec_stream) {
2271                     if ((k = pa_stream_readable_size(i->rec_stream)) == (size_t) -1)
2272                         debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i->context)));
2273                 } else
2274                     k = 0;
2275 
2276 #ifdef SIOCINQ
2277                 if (ioctl(i->app_fd, SIOCINQ, &l) < 0) {
2278                     debug(DEBUG_LEVEL_NORMAL, __FILE__": SIOCINQ failed: %s\n", strerror(errno));
2279                     l = 0;
2280                 }
2281 #else
2282 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2283 #endif
2284                 bi->bytes = k + l;
2285             }
2286 
2287             bi->fragsize = i->fragment_size;
2288             bi->fragstotal = i->n_fragments;
2289             bi->fragments = bi->bytes / bi->fragsize;
2290 
2291             pa_threaded_mainloop_unlock(i->mainloop);
2292 
2293             debug(DEBUG_LEVEL_NORMAL, __FILE__": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi->fragsize, bi->fragstotal, bi->bytes, bi->fragments);
2294 
2295             break;
2296         }
2297 
2298 #ifdef HAVE_DECL_SOUND_PCM_READ_RATE
2299         case SOUND_PCM_READ_RATE:
2300             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_RATE\n");
2301 
2302             pa_threaded_mainloop_lock(i->mainloop);
2303             *(int*) argp = i->sample_spec.rate;
2304             pa_threaded_mainloop_unlock(i->mainloop);
2305             break;
2306 #endif
2307 
2308 #ifdef HAVE_DECL_SOUND_PCM_READ_CHANNELS
2309         case SOUND_PCM_READ_CHANNELS:
2310             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_CHANNELS\n");
2311 
2312             pa_threaded_mainloop_lock(i->mainloop);
2313             *(int*) argp = i->sample_spec.channels;
2314             pa_threaded_mainloop_unlock(i->mainloop);
2315             break;
2316 #endif
2317 
2318 #ifdef HAVE_DECL_SOUND_PCM_READ_BITS
2319         case SOUND_PCM_READ_BITS:
2320             debug(DEBUG_LEVEL_NORMAL, __FILE__": SOUND_PCM_READ_BITS\n");
2321 
2322             pa_threaded_mainloop_lock(i->mainloop);
2323             *(int*) argp = pa_sample_size(&i->sample_spec)*8;
2324             pa_threaded_mainloop_unlock(i->mainloop);
2325             break;
2326 #endif
2327 
2328         case SNDCTL_DSP_GETOPTR: {
2329             count_info *info;
2330 
2331             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_GETOPTR\n");
2332 
2333             info = (count_info*) argp;
2334             memset(info, 0, sizeof(*info));
2335 
2336             pa_threaded_mainloop_lock(i->mainloop);
2337 
2338             for (;;) {
2339                 pa_usec_t usec;
2340 
2341                 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, exit_loop2);
2342 
2343                 if (pa_stream_get_time(i->play_stream, &usec) >= 0) {
2344                     size_t k = pa_usec_to_bytes(usec, &i->sample_spec);
2345                     int m;
2346 
2347                     info->bytes = (int) k;
2348                     m = k / i->fragment_size;
2349                     info->blocks = m - i->optr_n_blocks;
2350                     i->optr_n_blocks = m;
2351 
2352                     break;
2353                 }
2354 
2355                 if (pa_context_errno(i->context) != PA_ERR_NODATA) {
2356                     debug(DEBUG_LEVEL_NORMAL, __FILE__": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i->context)));
2357                     break;
2358                 }
2359 
2360                 pa_threaded_mainloop_wait(i->mainloop);
2361             }
2362 
2363         exit_loop2:
2364 
2365             pa_threaded_mainloop_unlock(i->mainloop);
2366 
2367             debug(DEBUG_LEVEL_NORMAL, __FILE__": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info->bytes, info->blocks, info->ptr);
2368 
2369             break;
2370         }
2371 
2372         case SNDCTL_DSP_GETIPTR:
2373             debug(DEBUG_LEVEL_NORMAL, __FILE__": invalid ioctl SNDCTL_DSP_GETIPTR\n");
2374             goto inval;
2375 
2376         case SNDCTL_DSP_SETDUPLEX:
2377             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n");
2378             /* this is a no-op */
2379             break;
2380 
2381         default:
2382             /* Mixer ioctls are valid on /dev/dsp as well */
2383             return mixer_ioctl(i, request, argp, _errno);
2384 
2385 inval:
2386             *_errno = EINVAL;
2387             goto fail;
2388     }
2389 
2390     ret = 0;
2391 
2392 fail:
2393 
2394     return ret;
2395 }
2396 
2397 #ifndef __GLIBC__
ioctl(int fd,int request,...)2398 int ioctl(int fd, int request, ...) {
2399 #else
2400 int ioctl(int fd, unsigned long request, ...) {
2401 #endif
2402     fd_info *i;
2403     va_list args;
2404     void *argp;
2405     int r, _errno = 0;
2406 
2407     debug(DEBUG_LEVEL_VERBOSE, __FILE__": ioctl()\n");
2408 
2409     va_start(args, request);
2410     argp = va_arg(args, void *);
2411     va_end(args);
2412 
2413     if (!function_enter()) {
2414         LOAD_IOCTL_FUNC();
2415         return _ioctl(fd, request, argp);
2416     }
2417 
2418     if (!(i = fd_info_find(fd))) {
2419         function_exit();
2420         LOAD_IOCTL_FUNC();
2421         return _ioctl(fd, request, argp);
2422     }
2423 
2424     if (i->type == FD_INFO_MIXER)
2425         r = mixer_ioctl(i, request, argp, &_errno);
2426     else
2427         r = dsp_ioctl(i, request, argp, &_errno);
2428 
2429     fd_info_unref(i);
2430 
2431     if (_errno)
2432         errno = _errno;
2433 
2434     function_exit();
2435 
2436     return r;
2437 }
2438 
2439 int close(int fd) {
2440     fd_info *i;
2441 
2442     debug(DEBUG_LEVEL_VERBOSE, __FILE__": close()\n");
2443 
2444     if (!function_enter()) {
2445         LOAD_CLOSE_FUNC();
2446         return _close(fd);
2447     }
2448 
2449     if (!(i = fd_info_find(fd))) {
2450         function_exit();
2451         LOAD_CLOSE_FUNC();
2452         return _close(fd);
2453     }
2454 
2455     fd_info_remove_from_list(i);
2456     fd_info_unref(i);
2457 
2458     function_exit();
2459 
2460     return 0;
2461 }
2462 
2463 int access(const char *pathname, int mode) {
2464 
2465     debug(DEBUG_LEVEL_VERBOSE, __FILE__": access(%s)\n", pathname?pathname:"NULL");
2466 
2467     if (!pathname ||
2468         !is_audio_device_node(pathname)) {
2469         LOAD_ACCESS_FUNC();
2470         return _access(pathname, mode);
2471     }
2472 
2473     if (mode & X_OK) {
2474         debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = EACCESS\n", pathname, mode);
2475         errno = EACCES;
2476         return -1;
2477     }
2478 
2479     debug(DEBUG_LEVEL_NORMAL, __FILE__": access(%s, %x) = OK\n", pathname, mode);
2480 
2481     return 0;
2482 }
2483 
2484 int stat(const char *pathname, struct stat *buf) {
2485 #ifdef HAVE_OPEN64
2486     struct stat64 parent;
2487 #else
2488     struct stat parent;
2489 #endif
2490     int ret;
2491 
2492     if (!pathname ||
2493         !buf ||
2494         !is_audio_device_node(pathname)) {
2495         debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat(%s)\n", pathname?pathname:"NULL");
2496         LOAD_STAT_FUNC();
2497         return _stat(pathname, buf);
2498     }
2499 
2500     debug(DEBUG_LEVEL_NORMAL, __FILE__": stat(%s)\n", pathname);
2501 
2502 #ifdef _STAT_VER
2503 #ifdef HAVE_OPEN64
2504     ret = __xstat64(_STAT_VER, "/dev", &parent);
2505 #else
2506     ret = __xstat(_STAT_VER, "/dev", &parent);
2507 #endif
2508 #else
2509 #ifdef HAVE_OPEN64
2510     ret = stat64("/dev", &parent);
2511 #else
2512     ret = stat("/dev", &parent);
2513 #endif
2514 #endif
2515 
2516     if (ret) {
2517         debug(DEBUG_LEVEL_NORMAL, __FILE__": unable to stat \"/dev\"\n");
2518         return -1;
2519     }
2520 
2521     buf->st_dev = parent.st_dev;
2522     buf->st_ino = 0xDEADBEEF;   /* FIXME: Can we do this in a safe way? */
2523     buf->st_mode = S_IFCHR | S_IRUSR | S_IWUSR;
2524     buf->st_nlink = 1;
2525     buf->st_uid = getuid();
2526     buf->st_gid = getgid();
2527     buf->st_rdev = 0x0E03;      /* FIXME: Linux specific */
2528     buf->st_size = 0;
2529     buf->st_atime = 1181557705;
2530     buf->st_mtime = 1181557705;
2531     buf->st_ctime = 1181557705;
2532     buf->st_blksize = 1;
2533     buf->st_blocks = 0;
2534 
2535     return 0;
2536 }
2537 #ifdef HAVE_OPEN64
2538 #undef stat64
2539 #ifdef __GLIBC__
2540 int stat64(const char *pathname, struct stat64 *buf) {
2541 #else
2542 int stat64(const char *pathname, struct stat *buf) {
2543 #endif
2544     struct stat oldbuf;
2545     int ret;
2546 
2547     debug(DEBUG_LEVEL_VERBOSE, __FILE__": stat64(%s)\n", pathname?pathname:"NULL");
2548 
2549     if (!pathname ||
2550         !buf ||
2551         !is_audio_device_node(pathname)) {
2552         LOAD_STAT64_FUNC();
2553         return _stat64(pathname, buf);
2554     }
2555 
2556     ret = stat(pathname, &oldbuf);
2557     if (ret)
2558         return ret;
2559 
2560     buf->st_dev = oldbuf.st_dev;
2561     buf->st_ino = oldbuf.st_ino;
2562     buf->st_mode = oldbuf.st_mode;
2563     buf->st_nlink = oldbuf.st_nlink;
2564     buf->st_uid = oldbuf.st_uid;
2565     buf->st_gid = oldbuf.st_gid;
2566     buf->st_rdev = oldbuf.st_rdev;
2567     buf->st_size = oldbuf.st_size;
2568     buf->st_atime = oldbuf.st_atime;
2569     buf->st_mtime = oldbuf.st_mtime;
2570     buf->st_ctime = oldbuf.st_ctime;
2571     buf->st_blksize = oldbuf.st_blksize;
2572     buf->st_blocks = oldbuf.st_blocks;
2573 
2574     return 0;
2575 }
2576 #undef open64
2577 int open64(const char *filename, int flags, ...) {
2578     va_list args;
2579     mode_t mode = 0;
2580 
2581     debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename?filename:"NULL");
2582 
2583     if (flags & O_CREAT) {
2584         va_start(args, flags);
2585         if (sizeof(mode_t) < sizeof(int))
2586             mode = va_arg(args, int);
2587         else
2588             mode = va_arg(args, mode_t);
2589         va_end(args);
2590     }
2591 
2592     if (!filename ||
2593         !is_audio_device_node(filename)) {
2594         LOAD_OPEN64_FUNC();
2595         return _open64(filename, flags, mode);
2596     }
2597 
2598     return real_open(filename, flags, mode);
2599 }
2600 
2601 int __open64_2(const char *filename, int flags) {
2602     debug(DEBUG_LEVEL_VERBOSE, __FILE__": __open64_2(%s)\n", filename?filename:"NULL");
2603 
2604     if ((flags & O_CREAT) ||
2605         !filename ||
2606         !is_audio_device_node(filename)) {
2607         LOAD___OPEN64_2_FUNC();
2608         return ___open64_2(filename, flags);
2609     }
2610 
2611     return real_open(filename, flags, 0);
2612 }
2613 
2614 #endif
2615 
2616 #ifdef _STAT_VER
2617 
2618 int __xstat(int ver, const char *pathname, struct stat *buf) {
2619     debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat(%s)\n", pathname?pathname:"NULL");
2620 
2621     if (!pathname ||
2622         !buf ||
2623         !is_audio_device_node(pathname)) {
2624         LOAD_XSTAT_FUNC();
2625         return ___xstat(ver, pathname, buf);
2626     }
2627 
2628     if (ver != _STAT_VER) {
2629         errno = EINVAL;
2630         return -1;
2631     }
2632 
2633     return stat(pathname, buf);
2634 }
2635 
2636 #ifdef HAVE_OPEN64
2637 
2638 int __xstat64(int ver, const char *pathname, struct stat64 *buf) {
2639     debug(DEBUG_LEVEL_VERBOSE, __FILE__": __xstat64(%s)\n", pathname?pathname:"NULL");
2640 
2641     if (!pathname ||
2642         !buf ||
2643         !is_audio_device_node(pathname)) {
2644         LOAD_XSTAT64_FUNC();
2645         return ___xstat64(ver, pathname, buf);
2646     }
2647 
2648     if (ver != _STAT_VER) {
2649         errno = EINVAL;
2650         return -1;
2651     }
2652 
2653     return stat64(pathname, buf);
2654 }
2655 
2656 #endif
2657 
2658 #endif
2659 
2660 FILE* fopen(const char *filename, const char *mode) {
2661     FILE *f = NULL;
2662     int fd;
2663     mode_t m;
2664 
2665     debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen(%s)\n", filename?filename:"NULL");
2666 
2667     if (!filename ||
2668         !mode ||
2669         !is_audio_device_node(filename)) {
2670         LOAD_FOPEN_FUNC();
2671         return _fopen(filename, mode);
2672     }
2673 
2674     switch (mode[0]) {
2675     case 'r':
2676         m = O_RDONLY;
2677         break;
2678     case 'w':
2679     case 'a':
2680         m = O_WRONLY;
2681         break;
2682     default:
2683         errno = EINVAL;
2684         return NULL;
2685     }
2686 
2687     if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+'))
2688         m = O_RDWR;
2689 
2690     if ((fd = real_open(filename, m, 0)) < 0)
2691         return NULL;
2692 
2693     if (!(f = fdopen(fd, mode))) {
2694         close(fd);
2695         return NULL;
2696     }
2697 
2698     return f;
2699 }
2700 
2701 #ifdef HAVE_OPEN64
2702 #undef fopen64
2703 FILE *fopen64(const char *__restrict filename, const char *__restrict mode) {
2704 
2705     debug(DEBUG_LEVEL_VERBOSE, __FILE__": fopen64(%s)\n", filename?filename:"NULL");
2706 
2707     if (!filename ||
2708         !mode ||
2709         !is_audio_device_node(filename)) {
2710         LOAD_FOPEN64_FUNC();
2711         return _fopen64(filename, mode);
2712     }
2713 
2714     return fopen(filename, mode);
2715 }
2716 
2717 #endif
2718 
2719 int fclose(FILE *f) {
2720     fd_info *i;
2721 
2722     debug(DEBUG_LEVEL_VERBOSE, __FILE__": fclose()\n");
2723 
2724     if (!function_enter()) {
2725         LOAD_FCLOSE_FUNC();
2726         return _fclose(f);
2727     }
2728 
2729     if (!(i = fd_info_find(fileno(f)))) {
2730         function_exit();
2731         LOAD_FCLOSE_FUNC();
2732         return _fclose(f);
2733     }
2734 
2735     fd_info_remove_from_list(i);
2736 
2737     /* Dirty trick to avoid that the fd is not freed twice, once by us
2738      * and once by the real fclose() */
2739     i->app_fd = -1;
2740 
2741     fd_info_unref(i);
2742 
2743     function_exit();
2744 
2745     LOAD_FCLOSE_FUNC();
2746     return _fclose(f);
2747 }
2748