xref: /third_party/pulseaudio/src/utils/padsp.c (revision 53a5a1b3)
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
66typedef enum {
67    FD_INFO_MIXER,
68    FD_INFO_STREAM,
69} fd_info_type_t;
70
71typedef struct fd_info fd_info;
72
73struct 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
110static int dsp_drain(fd_info *i);
111static void fd_info_remove_from_list(fd_info *i);
112
113static pthread_mutex_t fd_infos_mutex = PTHREAD_MUTEX_INITIALIZER;
114static pthread_mutex_t func_mutex = PTHREAD_MUTEX_INITIALIZER;
115
116static PA_LLIST_HEAD(fd_info, fd_infos) = NULL;
117
118static int (*_ioctl)(int, int, void*) = NULL;
119static int (*_close)(int) = NULL;
120static int (*_open)(const char *, int, mode_t) = NULL;
121static int (*___open_2)(const char *, int) = NULL;
122static FILE* (*_fopen)(const char *path, const char *mode) = NULL;
123static int (*_stat)(const char *, struct stat *) = NULL;
124#ifdef _STAT_VER
125static int (*___xstat)(int, const char *, struct stat *) = NULL;
126#endif
127#ifdef HAVE_OPEN64
128static int (*_open64)(const char *, int, mode_t) = NULL;
129static int (*___open64_2)(const char *, int) = NULL;
130static FILE* (*_fopen64)(const char *path, const char *mode) = NULL;
131static int (*_stat64)(const char *, struct stat64 *) = NULL;
132#ifdef _STAT_VER
133static int (*___xstat64)(int, const char *, struct stat64 *) = NULL;
134#endif
135#endif
136static int (*_fclose)(FILE *f) = NULL;
137static int (*_access)(const char *, int) = NULL;
138
139/* dlsym() violates ISO C, so confide the breakage into this function to
140 * avoid warnings. */
141typedef void (*fnptr)(void);
142static inline fnptr dlsym_fn(void *handle, const char *symbol) {
143    return (fnptr) (long) dlsym(handle, symbol);
144}
145
146#define LOAD_IOCTL_FUNC() \
147do { \
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() \
155do { \
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() \
163do { \
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() \
171do { \
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() \
179do { \
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() \
187do { \
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() \
195do { \
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() \
203do { \
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() \
211do { \
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() \
219do { \
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() \
227do { \
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() \
235do { \
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() \
243do { \
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() \
251do { \
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 { \
259if (!(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 { \
266if (!(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 { \
274if (!(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
281static 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
287static 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
306static 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
331static 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
341static 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
351static 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}
360static pthread_key_t recursion_key;
361
362static void recursion_key_alloc(void) {
363    pthread_key_create(&recursion_key, NULL);
364}
365
366static 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
378static void function_exit(void) {
379    pthread_setspecific(recursion_key, NULL);
380}
381
382static 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
426static 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
439static 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
451static 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
470static 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
480static 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
496static 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
505static 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
524static 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
543static 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
591static void install_atfork(void) {
592    pthread_atfork(atfork_prepare, atfork_parent, atfork_child);
593}
594
595static 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
605static 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
615static 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
708unlock_and_fail:
709
710    pa_threaded_mainloop_unlock(i->mainloop);
711
712fail:
713
714    if (i)
715        fd_info_unref(i);
716
717    return NULL;
718}
719
720static 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
730static 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
740static 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
756static 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
791static 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
831static 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
838static 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
855static 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
995static 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
1029static 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
1069fail:
1070    return -1;
1071}
1072
1073static 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
1111fail:
1112    return -1;
1113}
1114
1115static 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
1140static 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
1170fail:
1171    /* We can't do anything better than removing the event source */
1172    fd_info_shutdown(i);
1173}
1174
1175static 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
1233fail:
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
1246static 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
1268static 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
1290static 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
1308static 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
1399fail:
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
1415static 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
1487fail:
1488    pa_xfree(fn);
1489    if (fd >= 0)
1490        close(fd);
1491    return -1;
1492}
1493
1494static 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
1524int 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
1540static 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
1549int __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
1561static 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
1711fail:
1712
1713    return ret;
1714}
1715
1716static 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
1757static 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
1769static 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
1802static 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
1823static 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
1854static 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
1892fail:
1893
1894    if (o)
1895        pa_operation_unref(o);
1896
1897    pa_threaded_mainloop_unlock(i->mainloop);
1898
1899    return r;
1900}
1901
1902static 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
1935fail:
1936
1937    if (o)
1938        pa_operation_unref(o);
1939
1940    pa_threaded_mainloop_unlock(i->mainloop);
1941
1942    return r;
1943}
1944
1945static 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
1973fail:
1974
1975    if (o)
1976        pa_operation_unref(o);
1977
1978    pa_threaded_mainloop_unlock(i->mainloop);
1979
1980    return r;
1981}
1982
1983static 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
2385inval:
2386            *_errno = EINVAL;
2387            goto fail;
2388    }
2389
2390    ret = 0;
2391
2392fail:
2393
2394    return ret;
2395}
2396
2397#if !defined(__GLIBC__) && !defined(__FreeBSD__)
2398int ioctl(int fd, int request, ...) {
2399#else
2400int 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
2439int 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
2463int 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
2484int 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__
2540int stat64(const char *pathname, struct stat64 *buf) {
2541#else
2542int 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
2577int 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
2601int __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
2618int __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
2638int __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
2660FILE* 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
2703FILE *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
2719int 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