4 This file is part of PulseAudio.
6 Copyright 2006 Lennart Poettering
7 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #ifdef _FILE_OFFSET_BITS
30 #undef _FILE_OFFSET_BITS
33 #ifndef _LARGEFILE64_SOURCE
34 #define _LARGEFILE64_SOURCE 1
37 #include <sys/soundcard.h>
38 #include <sys/ioctl.h>
41 #include <sys/socket.h>
52 #include <linux/sockios.h>
55 #include <pulse/pulseaudio.h>
56 #include <pulsecore/llist.h>
57 #include <pulsecore/gccmacro.h>
59 /* On some systems SIOCINQ isn't defined, but FIONREAD is just an alias */
60 #if !defined(SIOCINQ) && defined(FIONREAD)
61 # define SIOCINQ FIONREAD
64 /* make sure gcc doesn't redefine open and friends as macros */
73 typedef struct fd_info fd_info
;
76 pthread_mutex_t mutex
;
81 int app_fd
, thread_fd
;
83 pa_sample_spec sample_spec
;
87 pa_threaded_mainloop
*mainloop
;
89 pa_stream
*play_stream
;
90 pa_stream
*rec_stream
;
94 pa_io_event
*io_event
;
95 pa_io_event_flags_t io_flags
;
100 int operation_success
;
102 pa_cvolume sink_volume
, source_volume
;
103 uint32_t sink_index
, source_index
;
104 int volume_modify_count
;
108 PA_LLIST_FIELDS(fd_info
);
111 static int dsp_drain(fd_info
*i
);
112 static void fd_info_remove_from_list(fd_info
*i
);
114 static pthread_mutex_t fd_infos_mutex
= PTHREAD_MUTEX_INITIALIZER
;
115 static pthread_mutex_t func_mutex
= PTHREAD_MUTEX_INITIALIZER
;
117 static PA_LLIST_HEAD(fd_info
, fd_infos
) = NULL
;
119 static int (*_ioctl
)(int, int, void*) = NULL
;
120 static int (*_close
)(int) = NULL
;
121 static int (*_open
)(const char *, int, mode_t
) = NULL
;
122 static FILE* (*_fopen
)(const char *path
, const char *mode
) = NULL
;
123 static int (*_stat
)(const char *, struct stat
*) = NULL
;
125 static int (*___xstat
)(int, const char *, struct stat
*) = NULL
;
128 static int (*_open64
)(const char *, int, mode_t
) = NULL
;
129 static FILE* (*_fopen64
)(const char *path
, const char *mode
) = NULL
;
130 static int (*_stat64
)(const char *, struct stat64
*) = NULL
;
132 static int (*___xstat64
)(int, const char *, struct stat64
*) = NULL
;
135 static int (*_fclose
)(FILE *f
) = NULL
;
136 static int (*_access
)(const char *, int) = NULL
;
138 /* dlsym() violates ISO C, so confide the breakage into this function to
140 typedef void (*fnptr
)(void);
141 static inline fnptr
dlsym_fn(void *handle
, const char *symbol
) {
142 return (fnptr
) (long) dlsym(handle
, symbol
);
145 #define LOAD_IOCTL_FUNC() \
147 pthread_mutex_lock(&func_mutex); \
149 _ioctl = (int (*)(int, int, void*)) dlsym_fn(RTLD_NEXT, "ioctl"); \
150 pthread_mutex_unlock(&func_mutex); \
153 #define LOAD_OPEN_FUNC() \
155 pthread_mutex_lock(&func_mutex); \
157 _open = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open"); \
158 pthread_mutex_unlock(&func_mutex); \
161 #define LOAD_OPEN64_FUNC() \
163 pthread_mutex_lock(&func_mutex); \
165 _open64 = (int (*)(const char *, int, mode_t)) dlsym_fn(RTLD_NEXT, "open64"); \
166 pthread_mutex_unlock(&func_mutex); \
169 #define LOAD_CLOSE_FUNC() \
171 pthread_mutex_lock(&func_mutex); \
173 _close = (int (*)(int)) dlsym_fn(RTLD_NEXT, "close"); \
174 pthread_mutex_unlock(&func_mutex); \
177 #define LOAD_ACCESS_FUNC() \
179 pthread_mutex_lock(&func_mutex); \
181 _access = (int (*)(const char*, int)) dlsym_fn(RTLD_NEXT, "access"); \
182 pthread_mutex_unlock(&func_mutex); \
185 #define LOAD_STAT_FUNC() \
187 pthread_mutex_lock(&func_mutex); \
189 _stat = (int (*)(const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "stat"); \
190 pthread_mutex_unlock(&func_mutex); \
193 #define LOAD_STAT64_FUNC() \
195 pthread_mutex_lock(&func_mutex); \
197 _stat64 = (int (*)(const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "stat64"); \
198 pthread_mutex_unlock(&func_mutex); \
201 #define LOAD_XSTAT_FUNC() \
203 pthread_mutex_lock(&func_mutex); \
205 ___xstat = (int (*)(int, const char *, struct stat *)) dlsym_fn(RTLD_NEXT, "__xstat"); \
206 pthread_mutex_unlock(&func_mutex); \
209 #define LOAD_XSTAT64_FUNC() \
211 pthread_mutex_lock(&func_mutex); \
213 ___xstat64 = (int (*)(int, const char *, struct stat64 *)) dlsym_fn(RTLD_NEXT, "__xstat64"); \
214 pthread_mutex_unlock(&func_mutex); \
217 #define LOAD_FOPEN_FUNC() \
219 pthread_mutex_lock(&func_mutex); \
221 _fopen = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen"); \
222 pthread_mutex_unlock(&func_mutex); \
225 #define LOAD_FOPEN64_FUNC() \
227 pthread_mutex_lock(&func_mutex); \
229 _fopen64 = (FILE* (*)(const char *, const char*)) dlsym_fn(RTLD_NEXT, "fopen64"); \
230 pthread_mutex_unlock(&func_mutex); \
233 #define LOAD_FCLOSE_FUNC() \
235 pthread_mutex_lock(&func_mutex); \
237 _fclose = (int (*)(FILE *)) dlsym_fn(RTLD_NEXT, "fclose"); \
238 pthread_mutex_unlock(&func_mutex); \
241 #define CONTEXT_CHECK_DEAD_GOTO(i, label) do { \
242 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY) { \
243 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
248 #define PLAYBACK_STREAM_CHECK_DEAD_GOTO(i, label) do { \
249 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
250 !(i)->play_stream || pa_stream_get_state((i)->play_stream) != PA_STREAM_READY) { \
251 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
256 #define RECORD_STREAM_CHECK_DEAD_GOTO(i, label) do { \
257 if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
258 !(i)->rec_stream || pa_stream_get_state((i)->rec_stream) != PA_STREAM_READY) { \
259 debug(DEBUG_LEVEL_NORMAL, __FILE__": Not connected: %s\n", (i)->context ? pa_strerror(pa_context_errno((i)->context)) : "NULL"); \
264 static void debug(int level
, const char *format
, ...) PA_GCC_PRINTF_ATTR(2,3);
266 #define DEBUG_LEVEL_ALWAYS 0
267 #define DEBUG_LEVEL_NORMAL 1
268 #define DEBUG_LEVEL_VERBOSE 2
270 static void debug(int level
, const char *format
, ...) {
272 const char *dlevel_s
;
275 dlevel_s
= getenv("PADSP_DEBUG");
279 dlevel
= atoi(dlevel_s
);
284 va_start(ap
, format
);
285 vfprintf(stderr
, format
, ap
);
289 static int padsp_disabled(void) {
291 static int sym_resolved
= 0;
293 /* If the current process has a symbol __padsp_disabled__ we use
294 * it to detect whether we should enable our stuff or not. A
295 * program needs to be compiled with -rdynamic for this to work!
296 * The symbol must be an int containing a three bit bitmask: bit 1
297 * -> disable /dev/dsp emulation, bit 2 -> disable /dev/sndstat
298 * emulation, bit 3 -> disable /dev/mixer emulation. Hence a value
299 * of 7 disables padsp entirely. */
301 pthread_mutex_lock(&func_mutex
);
303 sym
= (int*) dlsym(RTLD_DEFAULT
, "__padsp_disabled__");
307 pthread_mutex_unlock(&func_mutex
);
315 static int dsp_cloak_enable(void) {
316 if (padsp_disabled() & 1)
319 if (getenv("PADSP_NO_DSP"))
325 static int sndstat_cloak_enable(void) {
326 if (padsp_disabled() & 2)
329 if (getenv("PADSP_NO_SNDSTAT"))
335 static int mixer_cloak_enable(void) {
336 if (padsp_disabled() & 4)
339 if (getenv("PADSP_NO_MIXER"))
344 static pthread_key_t recursion_key
;
346 static void recursion_key_alloc(void) {
347 pthread_key_create(&recursion_key
, NULL
);
350 static int function_enter(void) {
351 /* Avoid recursive calls */
352 static pthread_once_t recursion_key_once
= PTHREAD_ONCE_INIT
;
353 pthread_once(&recursion_key_once
, recursion_key_alloc
);
355 if (pthread_getspecific(recursion_key
))
358 pthread_setspecific(recursion_key
, (void*) 1);
362 static void function_exit(void) {
363 pthread_setspecific(recursion_key
, NULL
);
366 static void fd_info_free(fd_info
*i
) {
369 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": freeing fd info (fd=%i)\n", i
->app_fd
);
374 pa_threaded_mainloop_stop(i
->mainloop
);
376 if (i
->play_stream
) {
377 pa_stream_disconnect(i
->play_stream
);
378 pa_stream_unref(i
->play_stream
);
382 pa_stream_disconnect(i
->rec_stream
);
383 pa_stream_unref(i
->rec_stream
);
387 pa_context_disconnect(i
->context
);
388 pa_context_unref(i
->context
);
392 pa_threaded_mainloop_free(i
->mainloop
);
394 if (i
->app_fd
>= 0) {
399 if (i
->thread_fd
>= 0) {
401 _close(i
->thread_fd
);
406 pthread_mutex_destroy(&i
->mutex
);
410 static fd_info
*fd_info_ref(fd_info
*i
) {
413 pthread_mutex_lock(&i
->mutex
);
417 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ref++, now %i\n", i
->ref
);
418 pthread_mutex_unlock(&i
->mutex
);
423 static void fd_info_unref(fd_info
*i
) {
425 pthread_mutex_lock(&i
->mutex
);
428 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ref--, now %i\n", i
->ref
);
429 pthread_mutex_unlock(&i
->mutex
);
435 static void context_state_cb(pa_context
*c
, void *userdata
) {
436 fd_info
*i
= userdata
;
439 switch (pa_context_get_state(c
)) {
440 case PA_CONTEXT_READY
:
441 case PA_CONTEXT_TERMINATED
:
442 case PA_CONTEXT_FAILED
:
443 pa_threaded_mainloop_signal(i
->mainloop
, 0);
446 case PA_CONTEXT_UNCONNECTED
:
447 case PA_CONTEXT_CONNECTING
:
448 case PA_CONTEXT_AUTHORIZING
:
449 case PA_CONTEXT_SETTING_NAME
:
454 static void reset_params(fd_info
*i
) {
457 i
->sample_spec
.format
= PA_SAMPLE_U8
;
458 i
->sample_spec
.channels
= 1;
459 i
->sample_spec
.rate
= 8000;
460 i
->fragment_size
= 0;
464 static const char *client_name(char *buf
, size_t n
) {
468 if ((e
= getenv("PADSP_CLIENT_NAME")))
471 if (pa_get_binary_name(p
, sizeof(p
)))
472 snprintf(buf
, n
, "OSS Emulation[%s]", p
);
474 snprintf(buf
, n
, "OSS");
479 static const char *stream_name(void) {
482 if ((e
= getenv("PADSP_STREAM_NAME")))
485 return "Audio Stream";
488 static void atfork_prepare(void) {
491 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_prepare() enter\n");
495 pthread_mutex_lock(&fd_infos_mutex
);
497 for (i
= fd_infos
; i
; i
= i
->next
) {
498 pthread_mutex_lock(&i
->mutex
);
499 pa_threaded_mainloop_lock(i
->mainloop
);
502 pthread_mutex_lock(&func_mutex
);
505 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_prepare() exit\n");
508 static void atfork_parent(void) {
511 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_parent() enter\n");
513 pthread_mutex_unlock(&func_mutex
);
515 for (i
= fd_infos
; i
; i
= i
->next
) {
516 pa_threaded_mainloop_unlock(i
->mainloop
);
517 pthread_mutex_unlock(&i
->mutex
);
520 pthread_mutex_unlock(&fd_infos_mutex
);
524 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_parent() exit\n");
527 static void atfork_child(void) {
530 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_child() enter\n");
532 /* We do only the bare minimum to get all fds closed */
533 pthread_mutex_init(&func_mutex
, NULL
);
534 pthread_mutex_init(&fd_infos_mutex
, NULL
);
536 for (i
= fd_infos
; i
; i
= i
->next
) {
537 pthread_mutex_init(&i
->mutex
, NULL
);
540 pa_context_disconnect(i
->context
);
541 pa_context_unref(i
->context
);
545 if (i
->play_stream
) {
546 pa_stream_unref(i
->play_stream
);
547 i
->play_stream
= NULL
;
551 pa_stream_unref(i
->rec_stream
);
552 i
->rec_stream
= NULL
;
555 if (i
->app_fd
>= 0) {
560 if (i
->thread_fd
>= 0) {
570 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": atfork_child() exit\n");
573 static void install_atfork(void) {
574 pthread_atfork(atfork_prepare
, atfork_parent
, atfork_child
);
577 static void stream_success_cb(pa_stream
*s
, int success
, void *userdata
) {
578 fd_info
*i
= userdata
;
583 i
->operation_success
= success
;
584 pa_threaded_mainloop_signal(i
->mainloop
, 0);
587 static void context_success_cb(pa_context
*c
, int success
, void *userdata
) {
588 fd_info
*i
= userdata
;
593 i
->operation_success
= success
;
594 pa_threaded_mainloop_signal(i
->mainloop
, 0);
597 static fd_info
* fd_info_new(fd_info_type_t type
, int *_errno
) {
599 int sfds
[2] = { -1, -1 };
601 static pthread_once_t install_atfork_once
= PTHREAD_ONCE_INIT
;
603 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fd_info_new()\n");
605 signal(SIGPIPE
, SIG_IGN
); /* Yes, ugly as hell */
607 pthread_once(&install_atfork_once
, install_atfork
);
609 if (!(i
= malloc(sizeof(fd_info
)))) {
614 i
->app_fd
= i
->thread_fd
= -1;
619 i
->play_stream
= NULL
;
620 i
->rec_stream
= NULL
;
625 pthread_mutex_init(&i
->mutex
, NULL
);
630 pa_cvolume_reset(&i
->sink_volume
, 2);
631 pa_cvolume_reset(&i
->source_volume
, 2);
632 i
->volume_modify_count
= 0;
633 i
->sink_index
= (uint32_t) -1;
634 i
->source_index
= (uint32_t) -1;
635 i
->optr_n_blocks
= 0;
636 PA_LLIST_INIT(fd_info
, i
);
640 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, sfds
) < 0) {
642 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": socket() failed: %s\n", strerror(errno
));
647 i
->thread_fd
= sfds
[1];
649 if (!(i
->mainloop
= pa_threaded_mainloop_new())) {
651 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_threaded_mainloop_new() failed\n");
655 if (!(i
->context
= pa_context_new(pa_threaded_mainloop_get_api(i
->mainloop
), client_name(name
, sizeof(name
))))) {
657 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_new() failed\n");
661 pa_context_set_state_callback(i
->context
, context_state_cb
, i
);
663 if (pa_context_connect(i
->context
, NULL
, 0, NULL
) < 0) {
664 *_errno
= ECONNREFUSED
;
665 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
669 pa_threaded_mainloop_lock(i
->mainloop
);
671 if (pa_threaded_mainloop_start(i
->mainloop
) < 0) {
673 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_threaded_mainloop_start() failed\n");
674 goto unlock_and_fail
;
677 /* Wait until the context is ready */
678 pa_threaded_mainloop_wait(i
->mainloop
);
680 if (pa_context_get_state(i
->context
) != PA_CONTEXT_READY
) {
681 *_errno
= ECONNREFUSED
;
682 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
683 goto unlock_and_fail
;
686 pa_threaded_mainloop_unlock(i
->mainloop
);
691 pa_threaded_mainloop_unlock(i
->mainloop
);
701 static void fd_info_add_to_list(fd_info
*i
) {
704 pthread_mutex_lock(&fd_infos_mutex
);
705 PA_LLIST_PREPEND(fd_info
, fd_infos
, i
);
706 pthread_mutex_unlock(&fd_infos_mutex
);
711 static void fd_info_remove_from_list(fd_info
*i
) {
714 pthread_mutex_lock(&fd_infos_mutex
);
715 PA_LLIST_REMOVE(fd_info
, fd_infos
, i
);
716 pthread_mutex_unlock(&fd_infos_mutex
);
721 static fd_info
* fd_info_find(int fd
) {
724 pthread_mutex_lock(&fd_infos_mutex
);
726 for (i
= fd_infos
; i
; i
= i
->next
)
727 if (i
->app_fd
== fd
&& !i
->unusable
) {
732 pthread_mutex_unlock(&fd_infos_mutex
);
737 static void fix_metrics(fd_info
*i
) {
739 char t
[PA_SAMPLE_SPEC_SNPRINT_MAX
];
741 fs
= pa_frame_size(&i
->sample_spec
);
743 /* Don't fix things more than necessary */
744 if ((i
->fragment_size
% fs
) == 0 &&
745 i
->n_fragments
>= 2 &&
746 i
->fragment_size
> 0)
749 i
->fragment_size
= (i
->fragment_size
/fs
)*fs
;
751 /* Number of fragments set? */
752 if (i
->n_fragments
< 2) {
753 if (i
->fragment_size
> 0) {
754 i
->n_fragments
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->fragment_size
;
755 if (i
->n_fragments
< 2)
761 /* Fragment size set? */
762 if (i
->fragment_size
<= 0) {
763 i
->fragment_size
= pa_bytes_per_second(&i
->sample_spec
) / 2 / i
->n_fragments
;
764 if (i
->fragment_size
< 1024)
765 i
->fragment_size
= 1024;
768 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": sample spec: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
769 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fixated metrics to %i fragments, %li bytes each.\n", i
->n_fragments
, (long)i
->fragment_size
);
772 static void stream_request_cb(pa_stream
*s
, size_t length
, void *userdata
) {
773 fd_info
*i
= userdata
;
777 pa_mainloop_api
*api
;
780 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
782 if (s
== i
->play_stream
) {
783 n
= pa_stream_writable_size(i
->play_stream
);
784 if (n
== (size_t)-1) {
785 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n",
786 pa_strerror(pa_context_errno(i
->context
)));
789 if (n
>= i
->fragment_size
)
790 i
->io_flags
|= PA_IO_EVENT_INPUT
;
792 i
->io_flags
&= ~PA_IO_EVENT_INPUT
;
795 if (s
== i
->rec_stream
) {
796 n
= pa_stream_readable_size(i
->rec_stream
);
797 if (n
== (size_t)-1) {
798 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n",
799 pa_strerror(pa_context_errno(i
->context
)));
802 if (n
>= i
->fragment_size
)
803 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
805 i
->io_flags
&= ~PA_IO_EVENT_OUTPUT
;
808 api
->io_enable(i
->io_event
, i
->io_flags
);
812 static void stream_latency_update_cb(pa_stream
*s
, void *userdata
) {
813 fd_info
*i
= userdata
;
816 pa_threaded_mainloop_signal(i
->mainloop
, 0);
819 static void fd_info_shutdown(fd_info
*i
) {
823 pa_mainloop_api
*api
;
824 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
825 api
->io_free(i
->io_event
);
830 if (i
->thread_fd
>= 0) {
836 static int fd_info_copy_data(fd_info
*i
, int force
) {
839 if (!i
->play_stream
&& !i
->rec_stream
)
842 if ((i
->play_stream
) && (pa_stream_get_state(i
->play_stream
) == PA_STREAM_READY
)) {
843 n
= pa_stream_writable_size(i
->play_stream
);
845 if (n
== (size_t)-1) {
846 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n",
847 pa_strerror(pa_context_errno(i
->context
)));
851 while (n
>= i
->fragment_size
|| force
) {
855 if (!(i
->buf
= malloc(i
->fragment_size
))) {
856 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": malloc() failed.\n");
861 if ((r
= read(i
->thread_fd
, i
->buf
, i
->fragment_size
)) <= 0) {
866 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": read(): %s\n", r
== 0 ? "EOF" : strerror(errno
));
870 if (pa_stream_write(i
->play_stream
, i
->buf
, r
, free
, 0, PA_SEEK_RELATIVE
) < 0) {
871 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_write(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
877 assert(n
>= (size_t) r
);
881 if (n
>= i
->fragment_size
)
882 i
->io_flags
|= PA_IO_EVENT_INPUT
;
884 i
->io_flags
&= ~PA_IO_EVENT_INPUT
;
887 if ((i
->rec_stream
) && (pa_stream_get_state(i
->rec_stream
) == PA_STREAM_READY
)) {
888 n
= pa_stream_readable_size(i
->rec_stream
);
890 if (n
== (size_t)-1) {
891 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n",
892 pa_strerror(pa_context_errno(i
->context
)));
896 while (n
>= i
->fragment_size
|| force
) {
902 if (pa_stream_peek(i
->rec_stream
, &data
, &len
) < 0) {
903 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_peek(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
910 buf
= (const char*)data
+ i
->rec_offset
;
912 if ((r
= write(i
->thread_fd
, buf
, len
- i
->rec_offset
)) <= 0) {
917 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": write(): %s\n", strerror(errno
));
921 assert((size_t)r
<= len
- i
->rec_offset
);
924 if (i
->rec_offset
== len
) {
925 if (pa_stream_drop(i
->rec_stream
) < 0) {
926 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drop(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
932 assert(n
>= (size_t) r
);
936 if (n
>= i
->fragment_size
)
937 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
939 i
->io_flags
&= ~PA_IO_EVENT_OUTPUT
;
943 pa_mainloop_api
*api
;
945 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
946 api
->io_enable(i
->io_event
, i
->io_flags
);
952 static void stream_state_cb(pa_stream
*s
, void * userdata
) {
953 fd_info
*i
= userdata
;
956 switch (pa_stream_get_state(s
)) {
958 case PA_STREAM_READY
:
959 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": stream established.\n");
962 case PA_STREAM_FAILED
:
963 if (s
== i
->play_stream
) {
964 debug(DEBUG_LEVEL_NORMAL
,
965 __FILE__
": pa_stream_connect_playback() failed: %s\n",
966 pa_strerror(pa_context_errno(i
->context
)));
967 pa_stream_unref(i
->play_stream
);
968 i
->play_stream
= NULL
;
969 } else if (s
== i
->rec_stream
) {
970 debug(DEBUG_LEVEL_NORMAL
,
971 __FILE__
": pa_stream_connect_record() failed: %s\n",
972 pa_strerror(pa_context_errno(i
->context
)));
973 pa_stream_unref(i
->rec_stream
);
974 i
->rec_stream
= NULL
;
979 case PA_STREAM_TERMINATED
:
980 case PA_STREAM_UNCONNECTED
:
981 case PA_STREAM_CREATING
:
986 static int create_playback_stream(fd_info
*i
) {
994 if (!(i
->play_stream
= pa_stream_new(i
->context
, stream_name(), &i
->sample_spec
, NULL
))) {
995 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
999 pa_stream_set_state_callback(i
->play_stream
, stream_state_cb
, i
);
1000 pa_stream_set_write_callback(i
->play_stream
, stream_request_cb
, i
);
1001 pa_stream_set_latency_update_callback(i
->play_stream
, stream_latency_update_cb
, i
);
1003 memset(&attr
, 0, sizeof(attr
));
1004 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
1005 attr
.tlength
= i
->fragment_size
* i
->n_fragments
;
1006 attr
.prebuf
= i
->fragment_size
;
1007 attr
.minreq
= i
->fragment_size
;
1009 flags
= PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
;
1010 if (i
->play_precork
) {
1011 flags
|= PA_STREAM_START_CORKED
;
1012 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": creating stream corked\n");
1014 if (pa_stream_connect_playback(i
->play_stream
, NULL
, &attr
, flags
, NULL
, NULL
) < 0) {
1015 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1019 n
= i
->fragment_size
;
1020 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
1021 n
= i
->fragment_size
;
1022 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
1030 static int create_record_stream(fd_info
*i
) {
1031 pa_buffer_attr attr
;
1038 if (!(i
->rec_stream
= pa_stream_new(i
->context
, stream_name(), &i
->sample_spec
, NULL
))) {
1039 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1043 pa_stream_set_state_callback(i
->rec_stream
, stream_state_cb
, i
);
1044 pa_stream_set_read_callback(i
->rec_stream
, stream_request_cb
, i
);
1045 pa_stream_set_latency_update_callback(i
->rec_stream
, stream_latency_update_cb
, i
);
1047 memset(&attr
, 0, sizeof(attr
));
1048 attr
.maxlength
= i
->fragment_size
* (i
->n_fragments
+1);
1049 attr
.fragsize
= i
->fragment_size
;
1051 flags
= PA_STREAM_INTERPOLATE_TIMING
|PA_STREAM_AUTO_TIMING_UPDATE
;
1052 if (i
->rec_precork
) {
1053 flags
|= PA_STREAM_START_CORKED
;
1054 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": creating stream corked\n");
1056 if (pa_stream_connect_record(i
->rec_stream
, NULL
, &attr
, flags
) < 0) {
1057 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_connect_record() failed: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1061 n
= i
->fragment_size
;
1062 setsockopt(i
->app_fd
, SOL_SOCKET
, SO_RCVBUF
, &n
, sizeof(n
));
1063 n
= i
->fragment_size
;
1064 setsockopt(i
->thread_fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
));
1072 static void free_streams(fd_info
*i
) {
1075 if (i
->play_stream
) {
1076 pa_stream_disconnect(i
->play_stream
);
1077 pa_stream_unref(i
->play_stream
);
1078 i
->play_stream
= NULL
;
1079 i
->io_flags
|= PA_IO_EVENT_INPUT
;
1082 if (i
->rec_stream
) {
1083 pa_stream_disconnect(i
->rec_stream
);
1084 pa_stream_unref(i
->rec_stream
);
1085 i
->rec_stream
= NULL
;
1086 i
->io_flags
|= PA_IO_EVENT_OUTPUT
;
1090 pa_mainloop_api
*api
;
1092 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
1093 api
->io_enable(i
->io_event
, i
->io_flags
);
1097 static void io_event_cb(pa_mainloop_api
*api
, pa_io_event
*e
, int fd
, pa_io_event_flags_t flags
, void *userdata
) {
1098 fd_info
*i
= userdata
;
1100 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1102 if (flags
& PA_IO_EVENT_INPUT
) {
1104 if (!i
->play_stream
) {
1105 if (create_playback_stream(i
) < 0)
1108 if (fd_info_copy_data(i
, 0) < 0)
1112 } else if (flags
& PA_IO_EVENT_OUTPUT
) {
1114 if (!i
->rec_stream
) {
1115 if (create_record_stream(i
) < 0)
1118 if (fd_info_copy_data(i
, 0) < 0)
1122 } else if (flags
& (PA_IO_EVENT_HANGUP
|PA_IO_EVENT_ERROR
))
1128 /* We can't do anything better than removing the event source */
1129 fd_info_shutdown(i
);
1132 static int dsp_open(int flags
, int *_errno
) {
1134 pa_mainloop_api
*api
;
1138 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open()\n");
1140 if (!(i
= fd_info_new(FD_INFO_STREAM
, _errno
)))
1143 if ((flags
& O_NONBLOCK
) == O_NONBLOCK
) {
1144 if ((f
= fcntl(i
->app_fd
, F_GETFL
)) >= 0)
1145 fcntl(i
->app_fd
, F_SETFL
, f
|O_NONBLOCK
);
1147 if ((f
= fcntl(i
->thread_fd
, F_GETFL
)) >= 0)
1148 fcntl(i
->thread_fd
, F_SETFL
, f
|O_NONBLOCK
);
1150 fcntl(i
->app_fd
, F_SETFD
, FD_CLOEXEC
);
1151 fcntl(i
->thread_fd
, F_SETFD
, FD_CLOEXEC
);
1153 pa_threaded_mainloop_lock(i
->mainloop
);
1154 api
= pa_threaded_mainloop_get_api(i
->mainloop
);
1156 switch (flags
& O_ACCMODE
) {
1158 i
->io_flags
= PA_IO_EVENT_OUTPUT
;
1159 shutdown(i
->thread_fd
, SHUT_RD
);
1160 shutdown(i
->app_fd
, SHUT_WR
);
1163 i
->io_flags
= PA_IO_EVENT_INPUT
;
1164 shutdown(i
->thread_fd
, SHUT_WR
);
1165 shutdown(i
->app_fd
, SHUT_RD
);
1168 i
->io_flags
= PA_IO_EVENT_INPUT
| PA_IO_EVENT_OUTPUT
;
1174 if (!(i
->io_event
= api
->io_new(api
, i
->thread_fd
, i
->io_flags
, io_event_cb
, i
)))
1177 pa_threaded_mainloop_unlock(i
->mainloop
);
1179 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open() succeeded, fd=%i\n", i
->app_fd
);
1181 fd_info_add_to_list(i
);
1188 pa_threaded_mainloop_unlock(i
->mainloop
);
1195 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": dsp_open() failed\n");
1200 static void sink_info_cb(pa_context
*context
, const pa_sink_info
*si
, int eol
, void *userdata
) {
1201 fd_info
*i
= userdata
;
1203 if (!si
&& eol
< 0) {
1204 i
->operation_success
= 0;
1205 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1212 if (!pa_cvolume_equal(&i
->sink_volume
, &si
->volume
))
1213 i
->volume_modify_count
++;
1215 i
->sink_volume
= si
->volume
;
1216 i
->sink_index
= si
->index
;
1218 i
->operation_success
= 1;
1219 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1222 static void source_info_cb(pa_context
*context
, const pa_source_info
*si
, int eol
, void *userdata
) {
1223 fd_info
*i
= userdata
;
1225 if (!si
&& eol
< 0) {
1226 i
->operation_success
= 0;
1227 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1234 if (!pa_cvolume_equal(&i
->source_volume
, &si
->volume
))
1235 i
->volume_modify_count
++;
1237 i
->source_volume
= si
->volume
;
1238 i
->source_index
= si
->index
;
1240 i
->operation_success
= 1;
1241 pa_threaded_mainloop_signal(i
->mainloop
, 0);
1244 static void subscribe_cb(pa_context
*context
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1245 fd_info
*i
= userdata
;
1246 pa_operation
*o
= NULL
;
1248 if (i
->sink_index
!= idx
)
1251 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
1254 if (!(o
= pa_context_get_sink_info_by_index(i
->context
, i
->sink_index
, sink_info_cb
, i
))) {
1255 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1259 pa_operation_unref(o
);
1262 static int mixer_open(int flags
, int *_errno
) {
1264 pa_operation
*o
= NULL
;
1267 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open()\n");
1269 if (!(i
= fd_info_new(FD_INFO_MIXER
, _errno
)))
1272 pa_threaded_mainloop_lock(i
->mainloop
);
1274 pa_context_set_subscribe_callback(i
->context
, subscribe_cb
, i
);
1276 if (!(o
= pa_context_subscribe(i
->context
, PA_SUBSCRIPTION_MASK_SINK
| PA_SUBSCRIPTION_MASK_SOURCE
, context_success_cb
, i
))) {
1277 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i
->context
)));
1282 i
->operation_success
= 0;
1283 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1284 pa_threaded_mainloop_wait(i
->mainloop
);
1285 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1288 pa_operation_unref(o
);
1291 if (!i
->operation_success
) {
1292 debug(DEBUG_LEVEL_NORMAL
, __FILE__
":Failed to subscribe to events: %s", pa_strerror(pa_context_errno(i
->context
)));
1299 if (!(o
= pa_context_get_sink_info_by_name(i
->context
, NULL
, sink_info_cb
, i
))) {
1300 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1305 i
->operation_success
= 0;
1306 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1307 pa_threaded_mainloop_wait(i
->mainloop
);
1308 CONTEXT_CHECK_DEAD_GOTO(i
, fail
);
1311 pa_operation_unref(o
);
1314 if (!i
->operation_success
) {
1315 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get sink info: %s", pa_strerror(pa_context_errno(i
->context
)));
1320 /* Get source info */
1322 if (!(o
= pa_context_get_source_info_by_name(i
->context
, NULL
, source_info_cb
, i
))) {
1323 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get source info: %s", pa_strerror(pa_context_errno(i
->context
)));
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
);
1334 pa_operation_unref(o
);
1337 if (!i
->operation_success
) {
1338 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to get source info: %s", pa_strerror(pa_context_errno(i
->context
)));
1343 pa_threaded_mainloop_unlock(i
->mainloop
);
1345 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open() succeeded, fd=%i\n", i
->app_fd
);
1347 fd_info_add_to_list(i
);
1355 pa_operation_unref(o
);
1357 pa_threaded_mainloop_unlock(i
->mainloop
);
1364 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mixer_open() failed\n");
1369 static int sndstat_open(int flags
, int *_errno
) {
1370 static const char sndstat
[] =
1371 "Sound Driver:3.8.1a-980706 (PulseAudio Virtual OSS)\n"
1373 "Config options: 0\n"
1375 "Installed drivers:\n"
1376 "Type 255: PulseAudio Virtual OSS\n"
1379 "PulseAudio Virtual OSS\n"
1382 "0: PulseAudio Virtual OSS\n"
1384 "Synth devices: NOT ENABLED IN CONFIG\n"
1391 "0: PulseAudio Virtual OSS\n";
1393 char fn
[] = "/tmp/padsp-sndstat-XXXXXX";
1398 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": sndstat_open()\n");
1400 if (flags
!= O_RDONLY
1402 && flags
!= (O_RDONLY
|O_LARGEFILE
)
1406 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": bad access!\n");
1417 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": mkstemp() failed: %s\n", strerror(errno
));
1423 if (write(fd
, sndstat
, sizeof(sndstat
) -1) != sizeof(sndstat
)-1) {
1425 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": write() failed: %s\n", strerror(errno
));
1429 if (lseek(fd
, SEEK_SET
, 0) < 0) {
1431 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": lseek() failed: %s\n", strerror(errno
));
1443 static int real_open(const char *filename
, int flags
, mode_t mode
) {
1446 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": open(%s)\n", filename
);
1448 if (!function_enter()) {
1450 return _open(filename
, flags
, mode
);
1453 if (dsp_cloak_enable() && (strcmp(filename
, "/dev/dsp") == 0 || strcmp(filename
, "/dev/adsp") == 0))
1454 r
= dsp_open(flags
, &_errno
);
1455 else if (mixer_cloak_enable() && strcmp(filename
, "/dev/mixer") == 0)
1456 r
= mixer_open(flags
, &_errno
);
1457 else if (sndstat_cloak_enable() && strcmp(filename
, "/dev/sndstat") == 0)
1458 r
= sndstat_open(flags
, &_errno
);
1462 return _open(filename
, flags
, mode
);
1473 int open(const char *filename
, int flags
, ...) {
1477 if (flags
& O_CREAT
) {
1478 va_start(args
, flags
);
1479 if (sizeof(mode_t
) < sizeof(int))
1480 mode
= va_arg(args
, int);
1482 mode
= va_arg(args
, mode_t
);
1486 return real_open(filename
, flags
, mode
);
1489 static int mixer_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
1493 case SOUND_MIXER_READ_DEVMASK
:
1494 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_DEVMASK\n");
1496 *(int*) argp
= SOUND_MASK_PCM
| SOUND_MASK_IGAIN
;
1499 case SOUND_MIXER_READ_RECMASK
:
1500 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_RECMASK\n");
1502 *(int*) argp
= SOUND_MASK_IGAIN
;
1505 case SOUND_MIXER_READ_STEREODEVS
:
1506 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_STEREODEVS\n");
1508 pa_threaded_mainloop_lock(i
->mainloop
);
1510 if (i
->sink_volume
.channels
> 1)
1511 *(int*) argp
|= SOUND_MASK_PCM
;
1512 if (i
->source_volume
.channels
> 1)
1513 *(int*) argp
|= SOUND_MASK_IGAIN
;
1514 pa_threaded_mainloop_unlock(i
->mainloop
);
1518 case SOUND_MIXER_READ_RECSRC
:
1519 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_RECSRC\n");
1521 *(int*) argp
= SOUND_MASK_IGAIN
;
1524 case SOUND_MIXER_WRITE_RECSRC
:
1525 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_RECSRC\n");
1528 case SOUND_MIXER_READ_CAPS
:
1529 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_CAPS\n");
1534 case SOUND_MIXER_READ_PCM
:
1535 case SOUND_MIXER_READ_IGAIN
: {
1538 if (request
== SOUND_MIXER_READ_PCM
)
1539 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_PCM\n");
1541 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_READ_IGAIN\n");
1543 pa_threaded_mainloop_lock(i
->mainloop
);
1545 if (request
== SOUND_MIXER_READ_PCM
)
1546 v
= &i
->sink_volume
;
1548 v
= &i
->source_volume
;
1551 ((v
->values
[0]*100/PA_VOLUME_NORM
)) |
1552 ((v
->values
[v
->channels
> 1 ? 1 : 0]*100/PA_VOLUME_NORM
) << 8);
1554 pa_threaded_mainloop_unlock(i
->mainloop
);
1559 case SOUND_MIXER_WRITE_PCM
:
1560 case SOUND_MIXER_WRITE_IGAIN
: {
1563 if (request
== SOUND_MIXER_WRITE_PCM
)
1564 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_PCM\n");
1566 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_WRITE_IGAIN\n");
1568 pa_threaded_mainloop_lock(i
->mainloop
);
1570 if (request
== SOUND_MIXER_WRITE_PCM
) {
1572 pv
= &i
->sink_volume
;
1574 v
= i
->source_volume
;
1575 pv
= &i
->source_volume
;
1578 pv
->values
[0] = ((*(int*) argp
& 0xFF)*PA_VOLUME_NORM
)/100;
1579 pv
->values
[1] = ((*(int*) argp
>> 8)*PA_VOLUME_NORM
)/100;
1581 if (!pa_cvolume_equal(pv
, &v
)) {
1584 if (request
== SOUND_MIXER_WRITE_PCM
)
1585 o
= pa_context_set_sink_volume_by_index(i
->context
, i
->sink_index
, pv
, context_success_cb
, i
);
1587 o
= pa_context_set_source_volume_by_index(i
->context
, i
->source_index
, pv
, context_success_cb
, i
);
1590 debug(DEBUG_LEVEL_NORMAL
, __FILE__
":Failed set volume: %s", pa_strerror(pa_context_errno(i
->context
)));
1593 i
->operation_success
= 0;
1594 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1595 CONTEXT_CHECK_DEAD_GOTO(i
, exit_loop
);
1597 pa_threaded_mainloop_wait(i
->mainloop
);
1601 if (!i
->operation_success
)
1602 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Failed to set volume: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1604 pa_operation_unref(o
);
1607 /* We don't wait for completion here */
1608 i
->volume_modify_count
++;
1611 pa_threaded_mainloop_unlock(i
->mainloop
);
1616 case SOUND_MIXER_INFO
: {
1617 mixer_info
*mi
= argp
;
1619 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_MIXER_INFO\n");
1621 memset(mi
, 0, sizeof(mixer_info
));
1622 strncpy(mi
->id
, "PULSEAUDIO", sizeof(mi
->id
));
1623 strncpy(mi
->name
, "PulseAudio Virtual OSS", sizeof(mi
->name
));
1624 pa_threaded_mainloop_lock(i
->mainloop
);
1625 mi
->modify_counter
= i
->volume_modify_count
;
1626 pa_threaded_mainloop_unlock(i
->mainloop
);
1631 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": unknown ioctl 0x%08lx\n", request
);
1644 static int map_format(int *fmt
, pa_sample_spec
*ss
) {
1648 ss
->format
= PA_SAMPLE_ULAW
;
1652 ss
->format
= PA_SAMPLE_ALAW
;
1659 ss
->format
= PA_SAMPLE_U8
;
1666 ss
->format
= PA_SAMPLE_S16BE
;
1673 ss
->format
= PA_SAMPLE_S16LE
;
1677 ss
->format
= PA_SAMPLE_S16NE
;
1685 static int map_format_back(pa_sample_format_t format
) {
1687 case PA_SAMPLE_S16LE
: return AFMT_S16_LE
;
1688 case PA_SAMPLE_S16BE
: return AFMT_S16_BE
;
1689 case PA_SAMPLE_ULAW
: return AFMT_MU_LAW
;
1690 case PA_SAMPLE_ALAW
: return AFMT_A_LAW
;
1691 case PA_SAMPLE_U8
: return AFMT_U8
;
1697 static int dsp_flush_fd(int fd
) {
1701 if (ioctl(fd
, SIOCINQ
, &l
) < 0) {
1702 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ: %s\n", strerror(errno
));
1710 k
= (size_t) l
> sizeof(buf
) ? sizeof(buf
) : (size_t) l
;
1711 if (read(fd
, buf
, k
) < 0)
1712 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": read(): %s\n", strerror(errno
));
1718 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1723 static int dsp_flush_socket(fd_info
*i
) {
1726 if ((i
->thread_fd
< 0) && (i
->app_fd
< 0))
1729 if (i
->thread_fd
>= 0)
1730 res
= dsp_flush_fd(i
->thread_fd
);
1736 res
= dsp_flush_fd(i
->app_fd
);
1744 static int dsp_empty_socket(fd_info
*i
) {
1748 /* Empty the socket */
1752 if (i
->thread_fd
< 0)
1755 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
1756 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ: %s\n", strerror(errno
));
1765 pa_threaded_mainloop_wait(i
->mainloop
);
1770 # warning "Your platform does not support SIOCINQ, something might not work as intended."
1775 static int dsp_drain(fd_info
*i
) {
1776 pa_operation
*o
= NULL
;
1782 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Draining.\n");
1784 pa_threaded_mainloop_lock(i
->mainloop
);
1786 if (dsp_empty_socket(i
) < 0)
1789 if (!i
->play_stream
)
1792 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Really draining.\n");
1794 if (!(o
= pa_stream_drain(i
->play_stream
, stream_success_cb
, i
))) {
1795 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drain(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1799 i
->operation_success
= 0;
1800 while (pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1801 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1803 pa_threaded_mainloop_wait(i
->mainloop
);
1806 if (!i
->operation_success
) {
1807 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_drain() 2: %s\n", pa_strerror(pa_context_errno(i
->context
)));
1816 pa_operation_unref(o
);
1818 pa_threaded_mainloop_unlock(i
->mainloop
);
1823 static int dsp_trigger(fd_info
*i
) {
1824 pa_operation
*o
= NULL
;
1827 if (!i
->play_stream
)
1830 pa_threaded_mainloop_lock(i
->mainloop
);
1832 if (dsp_empty_socket(i
) < 0)
1835 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": Triggering.\n");
1837 if (!(o
= pa_stream_trigger(i
->play_stream
, stream_success_cb
, i
))) {
1838 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1842 i
->operation_success
= 0;
1843 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1844 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1846 pa_threaded_mainloop_wait(i
->mainloop
);
1849 if (!i
->operation_success
) {
1850 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_trigger(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1859 pa_operation_unref(o
);
1861 pa_threaded_mainloop_unlock(i
->mainloop
);
1866 static int dsp_cork(fd_info
*i
, pa_stream
*s
, int b
) {
1867 pa_operation
*o
= NULL
;
1870 pa_threaded_mainloop_lock(i
->mainloop
);
1872 if (!(o
= pa_stream_cork(s
, b
, stream_success_cb
, i
))) {
1873 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1877 i
->operation_success
= 0;
1878 while (!pa_operation_get_state(o
) != PA_OPERATION_DONE
) {
1879 if (s
== i
->play_stream
)
1880 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1881 else if (s
== i
->rec_stream
)
1882 RECORD_STREAM_CHECK_DEAD_GOTO(i
, fail
);
1884 pa_threaded_mainloop_wait(i
->mainloop
);
1887 if (!i
->operation_success
) {
1888 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_cork(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
1897 pa_operation_unref(o
);
1899 pa_threaded_mainloop_unlock(i
->mainloop
);
1904 static int dsp_ioctl(fd_info
*i
, unsigned long request
, void*argp
, int *_errno
) {
1907 if (i
->thread_fd
== -1) {
1909 * We've encountered some fatal error and are just waiting
1912 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": got ioctl 0x%08lx in fatal error state\n", request
);
1918 case SNDCTL_DSP_SETFMT
: {
1919 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETFMT: %i\n", *(int*) argp
);
1921 pa_threaded_mainloop_lock(i
->mainloop
);
1923 if (*(int*) argp
== AFMT_QUERY
)
1924 *(int*) argp
= map_format_back(i
->sample_spec
.format
);
1926 map_format((int*) argp
, &i
->sample_spec
);
1930 pa_threaded_mainloop_unlock(i
->mainloop
);
1934 case SNDCTL_DSP_SPEED
: {
1939 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SPEED: %i\n", *(int*) argp
);
1941 pa_threaded_mainloop_lock(i
->mainloop
);
1943 ss
= i
->sample_spec
;
1944 ss
.rate
= *(int*) argp
;
1946 if ((valid
= pa_sample_spec_valid(&ss
))) {
1947 i
->sample_spec
= ss
;
1951 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": ss: %s\n", pa_sample_spec_snprint(t
, sizeof(t
), &i
->sample_spec
));
1953 pa_threaded_mainloop_unlock(i
->mainloop
);
1963 case SNDCTL_DSP_STEREO
:
1964 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_STEREO: %i\n", *(int*) argp
);
1966 pa_threaded_mainloop_lock(i
->mainloop
);
1968 i
->sample_spec
.channels
= *(int*) argp
? 2 : 1;
1971 pa_threaded_mainloop_unlock(i
->mainloop
);
1974 case SNDCTL_DSP_CHANNELS
: {
1978 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_CHANNELS: %i\n", *(int*) argp
);
1980 pa_threaded_mainloop_lock(i
->mainloop
);
1982 ss
= i
->sample_spec
;
1983 ss
.channels
= *(int*) argp
;
1985 if ((valid
= pa_sample_spec_valid(&ss
))) {
1986 i
->sample_spec
= ss
;
1990 pa_threaded_mainloop_unlock(i
->mainloop
);
2000 case SNDCTL_DSP_GETBLKSIZE
:
2001 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETBLKSIZE\n");
2003 pa_threaded_mainloop_lock(i
->mainloop
);
2006 *(int*) argp
= i
->fragment_size
;
2008 pa_threaded_mainloop_unlock(i
->mainloop
);
2012 case SNDCTL_DSP_SETFRAGMENT
:
2013 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETFRAGMENT: 0x%08x\n", *(int*) argp
);
2015 pa_threaded_mainloop_lock(i
->mainloop
);
2017 i
->fragment_size
= 1 << ((*(int*) argp
) & 31);
2018 i
->n_fragments
= (*(int*) argp
) >> 16;
2020 /* 0x7FFF means that we can set whatever we like */
2021 if (i
->n_fragments
== 0x7FFF)
2022 i
->n_fragments
= 12;
2026 pa_threaded_mainloop_unlock(i
->mainloop
);
2030 case SNDCTL_DSP_GETCAPS
:
2031 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_CAPS\n");
2033 *(int*) argp
= DSP_CAP_DUPLEX
| DSP_CAP_TRIGGER
2034 #ifdef DSP_CAP_MULTI
2040 case SNDCTL_DSP_GETODELAY
: {
2043 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETODELAY\n");
2045 pa_threaded_mainloop_lock(i
->mainloop
);
2052 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, exit_loop
);
2054 if (pa_stream_get_latency(i
->play_stream
, &usec
, NULL
) >= 0) {
2055 *(int*) argp
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
2059 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
2060 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2064 pa_threaded_mainloop_wait(i
->mainloop
);
2070 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0)
2071 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2075 # warning "Your platform does not support SIOCINQ, something might not work as intended."
2078 pa_threaded_mainloop_unlock(i
->mainloop
);
2080 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": ODELAY: %i\n", *(int*) argp
);
2085 case SNDCTL_DSP_RESET
: {
2086 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_RESET\n");
2088 pa_threaded_mainloop_lock(i
->mainloop
);
2091 dsp_flush_socket(i
);
2093 i
->optr_n_blocks
= 0;
2095 pa_threaded_mainloop_unlock(i
->mainloop
);
2099 case SNDCTL_DSP_GETFMTS
: {
2100 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETFMTS\n");
2102 *(int*) argp
= AFMT_MU_LAW
|AFMT_A_LAW
|AFMT_U8
|AFMT_S16_LE
|AFMT_S16_BE
;
2106 case SNDCTL_DSP_POST
:
2107 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_POST\n");
2109 if (dsp_trigger(i
) < 0)
2113 case SNDCTL_DSP_GETTRIGGER
:
2114 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETTRIGGER\n");
2117 if (!i
->play_precork
)
2118 *(int*) argp
|= PCM_ENABLE_OUTPUT
;
2119 if (!i
->rec_precork
)
2120 *(int*) argp
|= PCM_ENABLE_INPUT
;
2124 case SNDCTL_DSP_SETTRIGGER
:
2125 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETTRIGGER: 0x%08x\n", *(int*) argp
);
2132 i
->play_precork
= !((*(int*) argp
) & PCM_ENABLE_OUTPUT
);
2134 if (i
->play_stream
) {
2135 if (dsp_cork(i
, i
->play_stream
, !((*(int*) argp
) & PCM_ENABLE_OUTPUT
)) < 0)
2137 if (dsp_trigger(i
) < 0)
2141 i
->rec_precork
= !((*(int*) argp
) & PCM_ENABLE_INPUT
);
2143 if (i
->rec_stream
) {
2144 if (dsp_cork(i
, i
->rec_stream
, !((*(int*) argp
) & PCM_ENABLE_INPUT
)) < 0)
2150 case SNDCTL_DSP_SYNC
:
2151 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SYNC\n");
2153 if (dsp_drain(i
) < 0)
2158 case SNDCTL_DSP_GETOSPACE
:
2159 case SNDCTL_DSP_GETISPACE
: {
2160 audio_buf_info
*bi
= (audio_buf_info
*) argp
;
2164 if (request
== SNDCTL_DSP_GETOSPACE
)
2165 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETOSPACE\n");
2167 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETISPACE\n");
2169 pa_threaded_mainloop_lock(i
->mainloop
);
2173 if (request
== SNDCTL_DSP_GETOSPACE
) {
2174 if (i
->play_stream
) {
2175 if ((k
= pa_stream_writable_size(i
->play_stream
)) == (size_t) -1)
2176 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_writable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2178 k
= i
->fragment_size
* i
->n_fragments
;
2181 if (ioctl(i
->thread_fd
, SIOCINQ
, &l
) < 0) {
2182 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2186 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2189 bi
->bytes
= k
> (size_t) l
? k
- l
: 0;
2191 if (i
->rec_stream
) {
2192 if ((k
= pa_stream_readable_size(i
->rec_stream
)) == (size_t) -1)
2193 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_readable_size(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2198 if (ioctl(i
->app_fd
, SIOCINQ
, &l
) < 0) {
2199 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SIOCINQ failed: %s\n", strerror(errno
));
2203 # warning "Your platform does not dsp_flush_fd, something might not work as intended."
2208 bi
->fragsize
= i
->fragment_size
;
2209 bi
->fragstotal
= i
->n_fragments
;
2210 bi
->fragments
= bi
->bytes
/ bi
->fragsize
;
2212 pa_threaded_mainloop_unlock(i
->mainloop
);
2214 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": fragsize=%i, fragstotal=%i, bytes=%i, fragments=%i\n", bi
->fragsize
, bi
->fragstotal
, bi
->bytes
, bi
->fragments
);
2219 case SOUND_PCM_READ_RATE
:
2220 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_RATE\n");
2222 pa_threaded_mainloop_lock(i
->mainloop
);
2223 *(int*) argp
= i
->sample_spec
.rate
;
2224 pa_threaded_mainloop_unlock(i
->mainloop
);
2227 case SOUND_PCM_READ_CHANNELS
:
2228 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_CHANNELS\n");
2230 pa_threaded_mainloop_lock(i
->mainloop
);
2231 *(int*) argp
= i
->sample_spec
.channels
;
2232 pa_threaded_mainloop_unlock(i
->mainloop
);
2235 case SOUND_PCM_READ_BITS
:
2236 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SOUND_PCM_READ_BITS\n");
2238 pa_threaded_mainloop_lock(i
->mainloop
);
2239 *(int*) argp
= pa_sample_size(&i
->sample_spec
)*8;
2240 pa_threaded_mainloop_unlock(i
->mainloop
);
2243 case SNDCTL_DSP_GETOPTR
: {
2246 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_GETOPTR\n");
2248 info
= (count_info
*) argp
;
2249 memset(info
, 0, sizeof(*info
));
2251 pa_threaded_mainloop_lock(i
->mainloop
);
2256 PLAYBACK_STREAM_CHECK_DEAD_GOTO(i
, exit_loop
);
2258 if (pa_stream_get_time(i
->play_stream
, &usec
) >= 0) {
2259 size_t k
= pa_usec_to_bytes(usec
, &i
->sample_spec
);
2262 info
->bytes
= (int) k
;
2263 m
= k
/ i
->fragment_size
;
2264 info
->blocks
= m
- i
->optr_n_blocks
;
2265 i
->optr_n_blocks
= m
;
2270 if (pa_context_errno(i
->context
) != PA_ERR_NODATA
) {
2271 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": pa_stream_get_latency(): %s\n", pa_strerror(pa_context_errno(i
->context
)));
2275 pa_threaded_mainloop_wait(i
->mainloop
);
2278 pa_threaded_mainloop_unlock(i
->mainloop
);
2280 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": GETOPTR bytes=%i, blocks=%i, ptr=%i\n", info
->bytes
, info
->blocks
, info
->ptr
);
2285 case SNDCTL_DSP_GETIPTR
:
2286 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": invalid ioctl SNDCTL_DSP_GETIPTR\n");
2289 case SNDCTL_DSP_SETDUPLEX
:
2290 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": SNDCTL_DSP_SETDUPLEX\n");
2291 /* this is a no-op */
2295 /* Mixer ioctls are valid on /dev/dsp aswell */
2296 return mixer_ioctl(i
, request
, argp
, _errno
);
2310 int ioctl(int fd
, unsigned long request
, ...) {
2316 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": ioctl()\n");
2318 va_start(args
, request
);
2319 argp
= va_arg(args
, void *);
2322 if (!function_enter()) {
2324 return _ioctl(fd
, request
, argp
);
2327 if (!(i
= fd_info_find(fd
))) {
2330 return _ioctl(fd
, request
, argp
);
2333 if (i
->type
== FD_INFO_MIXER
)
2334 r
= mixer_ioctl(i
, request
, argp
, &_errno
);
2336 r
= dsp_ioctl(i
, request
, argp
, &_errno
);
2351 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": close()\n");
2353 if (!function_enter()) {
2358 if (!(i
= fd_info_find(fd
))) {
2364 fd_info_remove_from_list(i
);
2372 int access(const char *pathname
, int mode
) {
2375 /* Firefox needs this. See #27 */
2380 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": access(%s)\n", pathname
);
2382 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2383 strcmp(pathname
, "/dev/adsp") != 0 &&
2384 strcmp(pathname
, "/dev/sndstat") != 0 &&
2385 strcmp(pathname
, "/dev/mixer") != 0) {
2387 return _access(pathname
, mode
);
2390 if (mode
& (W_OK
| X_OK
)) {
2391 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": access(%s, %x) = EACCESS\n", pathname
, mode
);
2396 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": access(%s, %x) = OK\n", pathname
, mode
);
2401 int stat(const char *pathname
, struct stat
*buf
) {
2403 struct stat64 parent
;
2409 if (!pathname
|| !buf
) {
2414 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2415 strcmp(pathname
, "/dev/adsp") != 0 &&
2416 strcmp(pathname
, "/dev/sndstat") != 0 &&
2417 strcmp(pathname
, "/dev/mixer") != 0) {
2418 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": stat(%s)\n", pathname
);
2420 return _stat(pathname
, buf
);
2423 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": stat(%s)\n", pathname
);
2427 ret
= __xstat64(_STAT_VER
, "/dev", &parent
);
2429 ret
= __xstat(_STAT_VER
, "/dev", &parent
);
2433 ret
= stat64("/dev", &parent
);
2435 ret
= stat("/dev", &parent
);
2440 debug(DEBUG_LEVEL_NORMAL
, __FILE__
": unable to stat \"/dev\"\n");
2444 buf
->st_dev
= parent
.st_dev
;
2445 buf
->st_ino
= 0xDEADBEEF; /* FIXME: Can we do this in a safe way? */
2446 buf
->st_mode
= S_IFCHR
| S_IRUSR
| S_IWUSR
;
2448 buf
->st_uid
= getuid();
2449 buf
->st_gid
= getgid();
2450 buf
->st_rdev
= 0x0E03; /* FIXME: Linux specific */
2452 buf
->st_atime
= 1181557705;
2453 buf
->st_mtime
= 1181557705;
2454 buf
->st_ctime
= 1181557705;
2455 buf
->st_blksize
= 1;
2463 int stat64(const char *pathname
, struct stat64
*buf
) {
2467 if (!pathname
|| !buf
) {
2472 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": stat64(%s)\n", pathname
);
2474 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2475 strcmp(pathname
, "/dev/adsp") != 0 &&
2476 strcmp(pathname
, "/dev/sndstat") != 0 &&
2477 strcmp(pathname
, "/dev/mixer") != 0) {
2479 return _stat64(pathname
, buf
);
2482 ret
= stat(pathname
, &oldbuf
);
2486 buf
->st_dev
= oldbuf
.st_dev
;
2487 buf
->st_ino
= oldbuf
.st_ino
;
2488 buf
->st_mode
= oldbuf
.st_mode
;
2489 buf
->st_nlink
= oldbuf
.st_nlink
;
2490 buf
->st_uid
= oldbuf
.st_uid
;
2491 buf
->st_gid
= oldbuf
.st_gid
;
2492 buf
->st_rdev
= oldbuf
.st_rdev
;
2493 buf
->st_size
= oldbuf
.st_size
;
2494 buf
->st_atime
= oldbuf
.st_atime
;
2495 buf
->st_mtime
= oldbuf
.st_mtime
;
2496 buf
->st_ctime
= oldbuf
.st_ctime
;
2497 buf
->st_blksize
= oldbuf
.st_blksize
;
2498 buf
->st_blocks
= oldbuf
.st_blocks
;
2503 int open64(const char *filename
, int flags
, ...) {
2507 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": open64(%s)\n", filename
);
2509 if (flags
& O_CREAT
) {
2510 va_start(args
, flags
);
2511 if (sizeof(mode_t
) < sizeof(int))
2512 mode
= va_arg(args
, int);
2514 mode
= va_arg(args
, mode_t
);
2518 if (strcmp(filename
, "/dev/dsp") != 0 &&
2519 strcmp(filename
, "/dev/adsp") != 0 &&
2520 strcmp(filename
, "/dev/sndstat") != 0 &&
2521 strcmp(filename
, "/dev/mixer") != 0) {
2523 return _open64(filename
, flags
, mode
);
2526 return real_open(filename
, flags
, mode
);
2533 int __xstat(int ver
, const char *pathname
, struct stat
*buf
) {
2534 if (!pathname
|| !buf
) {
2539 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": __xstat(%s)\n", pathname
);
2541 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2542 strcmp(pathname
, "/dev/adsp") != 0 &&
2543 strcmp(pathname
, "/dev/sndstat") != 0 &&
2544 strcmp(pathname
, "/dev/mixer") != 0) {
2546 return ___xstat(ver
, pathname
, buf
);
2549 if (ver
!= _STAT_VER
) {
2554 return stat(pathname
, buf
);
2559 int __xstat64(int ver
, const char *pathname
, struct stat64
*buf
) {
2560 if (!pathname
|| !buf
) {
2565 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": __xstat64(%s)\n", pathname
);
2567 if (strcmp(pathname
, "/dev/dsp") != 0 &&
2568 strcmp(pathname
, "/dev/adsp") != 0 &&
2569 strcmp(pathname
, "/dev/sndstat") != 0 &&
2570 strcmp(pathname
, "/dev/mixer") != 0) {
2571 LOAD_XSTAT64_FUNC();
2572 return ___xstat64(ver
, pathname
, buf
);
2575 if (ver
!= _STAT_VER
) {
2580 return stat64(pathname
, buf
);
2587 FILE* fopen(const char *filename
, const char *mode
) {
2592 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fopen(%s)\n", filename
);
2594 if (strcmp(filename
, "/dev/dsp") != 0 &&
2595 strcmp(filename
, "/dev/adsp") != 0 &&
2596 strcmp(filename
, "/dev/sndstat") != 0 &&
2597 strcmp(filename
, "/dev/mixer") != 0) {
2599 return _fopen(filename
, mode
);
2615 if ((((mode
[1] == 'b') || (mode
[1] == 't')) && (mode
[2] == '+')) || (mode
[1] == '+'))
2618 if ((fd
= real_open(filename
, m
, 0)) < 0)
2621 if (!(f
= fdopen(fd
, mode
))) {
2631 FILE *fopen64(const char *filename
, const char *mode
) {
2633 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fopen64(%s)\n", filename
);
2635 if (strcmp(filename
, "/dev/dsp") != 0 &&
2636 strcmp(filename
, "/dev/adsp") != 0 &&
2637 strcmp(filename
, "/dev/sndstat") != 0 &&
2638 strcmp(filename
, "/dev/mixer") != 0) {
2639 LOAD_FOPEN64_FUNC();
2640 return _fopen64(filename
, mode
);
2643 return fopen(filename
, mode
);
2648 int fclose(FILE *f
) {
2651 debug(DEBUG_LEVEL_VERBOSE
, __FILE__
": fclose()\n");
2653 if (!function_enter()) {
2658 if (!(i
= fd_info_find(fileno(f
)))) {
2664 fd_info_remove_from_list(i
);
2666 /* Dirty trick to avoid that the fd is not freed twice, once by us
2667 * and once by the real fclose() */